Set up the main views for the window, as well as the redraw policy
Whenever we change views, we need to call the redraw function. That function will handle dropping the old view and populating the new one.
This commit is contained in:
parent
c4befcc6de
commit
baf652173c
|
@ -976,6 +976,7 @@ checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
|
||||||
name = "fitnesstrax"
|
name = "fitnesstrax"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"emseries",
|
||||||
"ft-core",
|
"ft-core",
|
||||||
"gio",
|
"gio",
|
||||||
"glib",
|
"glib",
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] }
|
adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] }
|
||||||
|
emseries = { path = "../../emseries" }
|
||||||
ft-core = { path = "../core" }
|
ft-core = { path = "../core" }
|
||||||
gio = { version = "0.18" }
|
gio = { version = "0.18" }
|
||||||
glib = { version = "0.18" }
|
glib = { version = "0.18" }
|
||||||
|
|
|
@ -1,16 +1,171 @@
|
||||||
|
use adw::prelude::*;
|
||||||
|
use emseries::Series;
|
||||||
|
use ft_core::TraxRecord;
|
||||||
use gio::resources_lookup_data;
|
use gio::resources_lookup_data;
|
||||||
use gtk::{prelude::*, STYLE_PROVIDER_PRIORITY_USER};
|
use glib::Object;
|
||||||
use std::env;
|
use gtk::{prelude::*, subclass::prelude::*, STYLE_PROVIDER_PRIORITY_USER};
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
env,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
const APP_ID_DEV: &str = "com.luminescent-dreams.fitnesstrax.dev";
|
const APP_ID_DEV: &str = "com.luminescent-dreams.fitnesstrax.dev";
|
||||||
const APP_ID_PROD: &str = "com.luminescent-dreams.fitnesstrax";
|
const APP_ID_PROD: &str = "com.luminescent-dreams.fitnesstrax";
|
||||||
|
|
||||||
const RESOURCE_BASE_PATH: &str = "/com/luminescent-dreams/fitnesstrax/";
|
const RESOURCE_BASE_PATH: &str = "/com/luminescent-dreams/fitnesstrax/";
|
||||||
|
|
||||||
struct AppState {}
|
/// The real, headless application. This is where all of the logic will reside.
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct App {
|
||||||
|
database: Arc<RwLock<Option<Series<TraxRecord>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
database: Arc::new(RwLock::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UnconfiguredViewPrivate {}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for UnconfiguredViewPrivate {
|
||||||
|
const NAME: &'static str = "UnconfiguredView";
|
||||||
|
type Type = UnconfiguredView;
|
||||||
|
type ParentType = gtk::Box;
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for UnconfiguredViewPrivate {}
|
||||||
|
impl WidgetImpl for UnconfiguredViewPrivate {}
|
||||||
|
impl BoxImpl for UnconfiguredViewPrivate {}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct UnconfiguredView(ObjectSubclass<UnconfiguredViewPrivate>) @extends gtk::Box, gtk::Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnconfiguredView {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let s: Self = Object::builder().build();
|
||||||
|
|
||||||
|
let label = gtk::Label::builder()
|
||||||
|
.label("Database is not configured.")
|
||||||
|
.build();
|
||||||
|
s.append(&label);
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HistoricalViewPrivate {}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for HistoricalViewPrivate {
|
||||||
|
const NAME: &'static str = "HistoricalView";
|
||||||
|
type Type = HistoricalView;
|
||||||
|
type ParentType = gtk::Box;
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for HistoricalViewPrivate {}
|
||||||
|
impl WidgetImpl for HistoricalViewPrivate {}
|
||||||
|
impl BoxImpl for HistoricalViewPrivate {}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct HistoricalView(ObjectSubclass<HistoricalViewPrivate>) @extends gtk::Box, gtk::Widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HistoricalView {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let s: Self = Object::builder().build();
|
||||||
|
|
||||||
|
let label = gtk::Label::builder()
|
||||||
|
.label("Database has been configured and now it is time to show data")
|
||||||
|
.build();
|
||||||
|
s.append(&label);
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// These are the possible states of the main application view.
|
||||||
|
enum MainView {
|
||||||
|
/// The application is not configured yet. This is a basic background widget to take up the
|
||||||
|
/// space when there is no data to be shown.
|
||||||
|
Unconfigured(UnconfiguredView),
|
||||||
|
|
||||||
|
/// The Historical view shows a history of records and whatnot.
|
||||||
|
Historical(HistoricalView),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The application window, or the main window, is the main user interface for the app. Almost
|
||||||
|
/// everything occurs here.
|
||||||
struct AppWindow {
|
struct AppWindow {
|
||||||
|
app: App,
|
||||||
window: adw::ApplicationWindow,
|
window: adw::ApplicationWindow,
|
||||||
|
current_view: RefCell<MainView>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppWindow {
|
||||||
|
/// Construct a new App Window.
|
||||||
|
///
|
||||||
|
/// adw_app is an Adwaita application. Application windows need to have access to this, but
|
||||||
|
/// otherwise we don't use this.
|
||||||
|
///
|
||||||
|
/// app is a core [App] object which encapsulates all of the basic logic.
|
||||||
|
fn new(adw_app: &adw::Application, app: App) -> AppWindow {
|
||||||
|
let window = adw::ApplicationWindow::builder()
|
||||||
|
.application(adw_app)
|
||||||
|
.width_request(800)
|
||||||
|
.height_request(600)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let current_view = if app.database.read().unwrap().is_none() {
|
||||||
|
MainView::Unconfigured(UnconfiguredView::new())
|
||||||
|
} else {
|
||||||
|
MainView::Historical(HistoricalView::new())
|
||||||
|
};
|
||||||
|
|
||||||
|
let stylesheet = String::from_utf8(
|
||||||
|
resources_lookup_data(
|
||||||
|
&format!("{}style.css", RESOURCE_BASE_PATH),
|
||||||
|
gio::ResourceLookupFlags::NONE,
|
||||||
|
)
|
||||||
|
.expect("stylesheet must be available in the resources")
|
||||||
|
.to_vec(),
|
||||||
|
)
|
||||||
|
.expect("to parse stylesheet");
|
||||||
|
|
||||||
|
let provider = gtk::CssProvider::new();
|
||||||
|
provider.load_from_data(&stylesheet);
|
||||||
|
|
||||||
|
let context = window.style_context();
|
||||||
|
context.add_provider(&provider, STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
|
||||||
|
window.present();
|
||||||
|
|
||||||
|
let s = Self {
|
||||||
|
app,
|
||||||
|
window,
|
||||||
|
current_view: RefCell::new(current_view),
|
||||||
|
};
|
||||||
|
s.redraw();
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn redraw(&self) {
|
||||||
|
match *self.current_view.borrow() {
|
||||||
|
MainView::Unconfigured(ref view) => self.window.set_content(Some(view)),
|
||||||
|
MainView::Historical(ref view) => self.window.set_content(Some(view)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -31,10 +186,7 @@ fn main() {
|
||||||
|
|
||||||
println!("database path: {}", settings.string("series-path"));
|
println!("database path: {}", settings.string("series-path"));
|
||||||
|
|
||||||
let app = adw::Application::builder()
|
let app = App::new();
|
||||||
.application_id(app_id)
|
|
||||||
.resource_base_path(RESOURCE_BASE_PATH)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
@ -43,32 +195,15 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let app = adw::Application::builder()
|
let adw_app = adw::Application::builder()
|
||||||
.application_id(app_id)
|
.application_id(app_id)
|
||||||
.resource_base_path(RESOURCE_BASE_PATH)
|
.resource_base_path(RESOURCE_BASE_PATH)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
app.connect_activate(move |app| {
|
adw_app.connect_activate(move |adw_app| {
|
||||||
let stylesheet = String::from_utf8(
|
AppWindow::new(adw_app, app.clone());
|
||||||
resources_lookup_data(
|
|
||||||
&format!("{}style.css", RESOURCE_BASE_PATH),
|
|
||||||
gio::ResourceLookupFlags::NONE,
|
|
||||||
)
|
|
||||||
.expect("stylesheet must be available in the resources")
|
|
||||||
.to_vec(),
|
|
||||||
)
|
|
||||||
.expect("to parse stylesheet");
|
|
||||||
|
|
||||||
let provider = gtk::CssProvider::new();
|
|
||||||
provider.load_from_data(&stylesheet);
|
|
||||||
|
|
||||||
let window = adw::ApplicationWindow::new(app);
|
|
||||||
let context = window.style_context();
|
|
||||||
context.add_provider(&provider, STYLE_PROVIDER_PRIORITY_USER);
|
|
||||||
|
|
||||||
window.present();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
ApplicationExtManual::run_with_args(&app, &args);
|
ApplicationExtManual::run_with_args(&adw_app, &args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,4 @@ use emseries::DateTimeTz;
|
||||||
|
|
||||||
mod legacy;
|
mod legacy;
|
||||||
mod types;
|
mod types;
|
||||||
|
pub use types::TraxRecord;
|
||||||
|
|
Loading…
Reference in New Issue