From 38db3d6780b25de87802490f44ccade3c7c578a7 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 18 Dec 2023 21:14:08 -0500 Subject: [PATCH] Elaborate upon and format the welcome dialog --- fitnesstrax/app/Cargo.toml | 2 +- fitnesstrax/app/src/main.rs | 34 +++++++------ fitnesstrax/app/src/ui/mod.rs | 91 +++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 fitnesstrax/app/src/ui/mod.rs diff --git a/fitnesstrax/app/Cargo.toml b/fitnesstrax/app/Cargo.toml index 470ecea..66f08ef 100644 --- a/fitnesstrax/app/Cargo.toml +++ b/fitnesstrax/app/Cargo.toml @@ -11,7 +11,7 @@ emseries = { path = "../../emseries" } ft-core = { path = "../core" } gio = { version = "0.18" } glib = { version = "0.18" } -gtk = { version = "0.7", package = "gtk4", features = [ "v4_8" ] } +gtk = { version = "0.7", package = "gtk4", features = [ "v4_10" ] } tokio = { version = "1.34", features = [ "full" ] } [build-dependencies] diff --git a/fitnesstrax/app/src/main.rs b/fitnesstrax/app/src/main.rs index e337a81..c67024e 100644 --- a/fitnesstrax/app/src/main.rs +++ b/fitnesstrax/app/src/main.rs @@ -13,6 +13,9 @@ General Public License for more details. You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see . */ + +mod ui; + use adw::prelude::*; use emseries::Series; use ft_core::TraxRecord; @@ -24,6 +27,7 @@ use std::{ env, sync::{Arc, RwLock}, }; +use ui::FileChooserRow; const APP_ID_DEV: &str = "com.luminescent-dreams.fitnesstrax.dev"; const APP_ID_PROD: &str = "com.luminescent-dreams.fitnesstrax"; @@ -71,32 +75,32 @@ impl WelcomeView { pub fn new() -> Self { let s: Self = Object::builder().build(); s.set_orientation(gtk::Orientation::Vertical); + s.set_css_classes(&["modal"]); // Replace this with the welcome screen that we set up in the fitnesstrax/unconfigured-page // branch. - let label = gtk::Label::builder() + let title = gtk::Label::builder() .label("Welcome to FitnessTrax") + .css_classes(["modal-title"]) + .build(); + s.append(&title); + + let content = gtk::Box::builder() + .css_classes(["model-content"]) + .orientation(gtk::Orientation::Vertical) + .vexpand(true) .build(); - s.append(&label); - - s.append(>k::Label::new(Some("Welcome to FitnessTrax. The application has not yet been configured, so I will walk you through that. Let's start out by selecting your database."))); + content.append(>k::Label::new(Some("Welcome to FitnessTrax. The application has not yet been configured, so I will walk you through that. Let's start out by selecting your database."))); // The database selection row should be a box that shows a default database path, along with a // button that triggers a file chooser dialog. Once the dialog returns, the box should be // updated to reflect the chosen path. - let db_row = gtk::Box::builder() - .orientation(gtk::Orientation::Horizontal) - .build(); - db_row.append( - >k::Label::builder() - .label("No Path Selected") - .hexpand(true) - .build(), - ); - db_row.append(>k::Button::builder().label("Select Database").build()); + let db_row = FileChooserRow::new(); - s.append(&db_row); + content.append(&db_row); + + s.append(&content); s.append(>k::Button::builder().label("Save Settings").build()); s diff --git a/fitnesstrax/app/src/ui/mod.rs b/fitnesstrax/app/src/ui/mod.rs new file mode 100644 index 0000000..662d1e1 --- /dev/null +++ b/fitnesstrax/app/src/ui/mod.rs @@ -0,0 +1,91 @@ +/* +Copyright 2023, Savanni D'Gerinel + +This file is part of FitnessTrax. + +FitnessTrax is free software: you can redistribute it and/or modify it under the terms of the GNU +General Public License as published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +FitnessTrax is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see . +*/ + +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use std::{cell::RefCell, path::PathBuf}; + +pub struct FileChooserRowPrivate { + path: RefCell>, + label: gtk::Label, +} + +#[glib::object_subclass] +impl ObjectSubclass for FileChooserRowPrivate { + const NAME: &'static str = "FileChooser"; + type Type = FileChooserRow; + type ParentType = gtk::Box; + + fn new() -> Self { + Self { + path: RefCell::new(None), + label: gtk::Label::builder().hexpand(true).build(), + } + } +} + +impl ObjectImpl for FileChooserRowPrivate {} +impl WidgetImpl for FileChooserRowPrivate {} +impl BoxImpl for FileChooserRowPrivate {} + +glib::wrapper! { + pub struct FileChooserRow(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; +} + +impl FileChooserRow { + pub fn new() -> Self { + let s: Self = Object::builder().build(); + + s.set_orientation(gtk::Orientation::Horizontal); + + // The database selection row should be a box that shows a default database path, along with a + // button that triggers a file chooser dialog. Once the dialog returns, the box should be + // updated to reflect the chosen path. + s.imp().label.set_text("No database selected"); + + let db_file_chooser_button = gtk::Button::builder().label("Select Database").build(); + db_file_chooser_button.connect_clicked({ + let s = s.clone(); + move |_| { + let no_window: Option<>k::Window> = None; + let not_cancellable: Option<&gio::Cancellable> = None; + let s = s.clone(); + gtk::FileDialog::builder().build().open( + no_window, + not_cancellable, + move |file_id| match file_id { + Ok(file_id) => match file_id.path() { + Some(path) => { + s.imp().label.set_text(path.to_str().unwrap()); + *s.imp().path.borrow_mut() = Some(path); + } + None => { + *s.imp().path.borrow_mut() = None; + s.imp().label.set_text("No database selected"); + } + }, + Err(err) => println!("file opening failed: {}", err), + }, + ); + } + }); + + s.append(&s.imp().label); + s.append(&db_file_chooser_button); + + s + } +}