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:
Savanni D'Gerinel 2023-12-18 18:30:41 -05:00
parent c4befcc6de
commit baf652173c
4 changed files with 166 additions and 28 deletions

1
Cargo.lock generated
View File

@ -976,6 +976,7 @@ checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
name = "fitnesstrax"
version = "0.1.0"
dependencies = [
"emseries",
"ft-core",
"gio",
"glib",

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] }
emseries = { path = "../../emseries" }
ft-core = { path = "../core" }
gio = { version = "0.18" }
glib = { version = "0.18" }

View File

@ -1,16 +1,171 @@
use adw::prelude::*;
use emseries::Series;
use ft_core::TraxRecord;
use gio::resources_lookup_data;
use gtk::{prelude::*, STYLE_PROVIDER_PRIORITY_USER};
use std::env;
use glib::Object;
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_PROD: &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 {
app: App,
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() {
@ -31,10 +186,7 @@ fn main() {
println!("database path: {}", settings.string("series-path"));
let app = adw::Application::builder()
.application_id(app_id)
.resource_base_path(RESOURCE_BASE_PATH)
.build();
let app = App::new();
/*
let runtime = tokio::runtime::Builder::new_multi_thread()
@ -43,32 +195,15 @@ fn main() {
.unwrap();
*/
let app = adw::Application::builder()
let adw_app = adw::Application::builder()
.application_id(app_id)
.resource_base_path(RESOURCE_BASE_PATH)
.build();
app.connect_activate(move |app| {
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 window = adw::ApplicationWindow::new(app);
let context = window.style_context();
context.add_provider(&provider, STYLE_PROVIDER_PRIORITY_USER);
window.present();
adw_app.connect_activate(move |adw_app| {
AppWindow::new(adw_app, app.clone());
});
let args: Vec<String> = env::args().collect();
ApplicationExtManual::run_with_args(&app, &args);
ApplicationExtManual::run_with_args(&adw_app, &args);
}

View File

@ -4,3 +4,4 @@ use emseries::DateTimeTz;
mod legacy;
mod types;
pub use types::TraxRecord;