diff --git a/fitnesstrax/app/src/main.rs b/fitnesstrax/app/src/main.rs index dcb3748..8a36bf5 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::welcome_modal; const APP_ID_DEV: &str = "com.luminescent-dreams.fitnesstrax.dev"; const APP_ID_PROD: &str = "com.luminescent-dreams.fitnesstrax"; diff --git a/fitnesstrax/app/src/ui/mod.rs b/fitnesstrax/app/src/ui/mod.rs new file mode 100644 index 0000000..3a0fe05 --- /dev/null +++ b/fitnesstrax/app/src/ui/mod.rs @@ -0,0 +1,2 @@ +mod modal; +pub use modal::{welcome_modal, Modal}; diff --git a/fitnesstrax/app/src/ui/modal.rs b/fitnesstrax/app/src/ui/modal.rs new file mode 100644 index 0000000..a8ce309 --- /dev/null +++ b/fitnesstrax/app/src/ui/modal.rs @@ -0,0 +1,75 @@ +//! The Modal is a reusable component with a title, arbitrary content, and up to three action +//! buttons. It does not itself enforce being a modal, but is meant to become a child of an Overlay +//! component. +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use std::cell::RefCell; + +pub struct ModalPrivate { + title: gtk::Label, + content: RefCell, + primary_action: gtk::Button, + secondary_action: Option, + tertiary_action: Option, +} + +#[glib::object_subclass] +impl ObjectSubclass for ModalPrivate { + const NAME: &'static str = "Modal"; + type Type = Modal; + type ParentType = gtk::Box; + + fn new() -> Self { + let title = gtk::Label::builder().label("Modal").build(); + let content = gtk::Box::new(gtk::Orientation::Vertical, 0); + let actions = gtk::Box::new(gtk::Orientation::Horizontal, 0); + + Self { + title, + content: RefCell::new(content.upcast()), + primary_action: gtk::Button::new(), + secondary_action: None, + tertiary_action: None, + } + } +} + +impl ObjectImpl for ModalPrivate {} +impl WidgetImpl for ModalPrivate {} +impl BoxImpl for ModalPrivate {} + +glib::wrapper! { + pub struct Modal(ObjectSubclass) @extends gtk::Box, gtk::Widget; +} + +impl Modal { + pub fn new() -> Self { + let s: Self = Object::builder().build(); + + s.append(&s.imp().title); + s.append(&*s.imp().content.borrow()); + // s.append(&s.imp().actions); + + s + } + + pub fn set_title(&self, text: &str) { + self.imp().title.set_text(text); + } + + pub fn set_content(&self, content: gtk::Widget) { + self.remove(&*self.imp().content.borrow()); + self.insert_child_after(&content, Some(&self.imp().title)); + *self.imp().content.borrow_mut() = content; + } +} + +/// The welcome modal is the first thing the user will see when FitnessTrax starts up if the +/// database has not been configured yet. +/// +/// This is a [Modal] component with all of the welcome content. +pub fn welcome_modal() -> Modal { + let modal = Modal::new(); + modal.set_title("Welcome to FitnessTrax"); + modal +}