diff --git a/src/app/browser.rs b/src/app/browser.rs index 14301411..96faabb4 100644 --- a/src/app/browser.rs +++ b/src/app/browser.rs @@ -177,7 +177,7 @@ impl Browser { // Show welcome dialog on profile not selected yet (e.g. first launch) if self.profile.database.selected().is_none() { - // @TODO Welcome::new(self.profile.clone()).present(Some(self.widget.gobject())); + // @TODO Welcome::new(self.profile.clone(), self.widget.gobject().clone()).present(); } self diff --git a/src/app/browser/welcome.rs b/src/app/browser/welcome.rs index 7b26ec53..a28dba83 100644 --- a/src/app/browser/welcome.rs +++ b/src/app/browser/welcome.rs @@ -2,7 +2,7 @@ mod widget; use widget::Widget; use crate::profile::Profile; -use gtk::prelude::IsA; +use adw::ApplicationWindow; use std::rc::Rc; pub struct Welcome { @@ -14,17 +14,39 @@ impl Welcome { // Construct /// Create new `Self` for given Profile - pub fn new(profile: Rc) -> Self { - Self { - profile, - widget: Rc::new(Widget::new()), - } + pub fn new(profile: Rc, parent: ApplicationWindow) -> Self { + // Init widget + let widget = Rc::new(Widget::new(parent)); + + // Init events + widget.connect_response(|value| { + match value { + Some(id) => { + // Select profile by record ID @TODO + } + None => { + // Create new profile @TODO + } + } + }); + + // Return activated `Self` + Self { profile, widget } } // Actions /// Show dialog for parent [Window](https://docs.gtk.org/gtk4/class.Window.html) - pub fn present(&self, parent: Option<&impl IsA>) { - self.widget.present(parent); + pub fn present(&self) { + // Collect Profile list + let mut responses = Vec::new(); + for record in self.profile.database.records() { + responses.push(( + record.id.to_string(), + record.time.format_iso8601().unwrap().to_string(), + )) + } + // Show dialog + self.widget.present(responses); } } diff --git a/src/app/browser/welcome/widget.rs b/src/app/browser/welcome/widget.rs index ed371f85..572d1668 100644 --- a/src/app/browser/welcome/widget.rs +++ b/src/app/browser/welcome/widget.rs @@ -1,8 +1,9 @@ use adw::{ prelude::{AdwDialogExt, AlertDialogExt, AlertDialogExtManual}, - AlertDialog, ResponseAppearance, + AlertDialog, ApplicationWindow, ResponseAppearance, }; -use gtk::prelude::IsA; +use gtk::prelude::GtkWindowExt; +use std::cell::RefCell; const HEADING: &str = "Welcome!"; const BODY: &str = "Select profile for browser data"; @@ -11,13 +12,15 @@ const RESPONSE_CREATE: (&str, &str) = ("create", "Create new profile"); pub struct Widget { gobject: AlertDialog, + parent: ApplicationWindow, + responses: RefCell>, // wanted to cleanup previous preset by key } impl Widget { // Constructors - /// Create new `Self` - pub fn new() -> Self { + /// Create new `Self` for [Window](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.3/class.ApplicationWindow.html) + pub fn new(parent: ApplicationWindow) -> Self { // Init gobject let gobject = AlertDialog::builder() .heading(HEADING) @@ -26,28 +29,56 @@ impl Widget { .default_response(RESPONSE_CREATE.0) .build(); - // Init response variants + // Set response variants gobject.add_responses(&[RESPONSE_QUIT, RESPONSE_CREATE]); - // Decorate + // Decorate default response preset gobject.set_response_appearance(RESPONSE_CREATE.0, ResponseAppearance::Suggested); gobject.set_response_appearance(RESPONSE_QUIT.0, ResponseAppearance::Destructive); // Return new `Self` - Self { gobject } + Self { + gobject, + parent, + responses: RefCell::new(Vec::new()), + } } // Actions - /// Show dialog for parent [Window](https://docs.gtk.org/gtk4/class.Window.html) - pub fn present(&self, parent: Option<&impl IsA>) { - self.gobject.present(parent); + /// Wrapper for default [response](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/signal.AlertDialog.response.html) signal + /// * return profile ID, new record request on `None` or immediately close `self.parent` given on construction + pub fn connect_response(&self, callback: impl Fn(Option) + 'static) { + self.gobject.connect_response(None, { + let parent = self.parent.clone(); + move |_, response| match response { + id if id == RESPONSE_CREATE.0 => callback(None), + id if id == RESPONSE_QUIT.0 => parent.close(), + _ => callback(Some(response.parse::().unwrap())), + } + }); } - /* @TODO not in use - /// Get reference to GObject - /// - pub fn gobject(&self) -> &AlertDialog { - &self.gobject - } */ + /// Show dialog with new profile responses preset + pub fn present(&self, profiles: Vec<(String, String)>) { + // Borrow current index to update + let mut index = self.responses.borrow_mut(); + + // Remove previous responses from widget + for response in index.iter() { + self.gobject.remove_response(response) + } + + // Reset index + index.clear(); + + // Build new preset + for (id, label) in profiles { + self.gobject.add_response(&id, &label); + index.push(id) + } + + // Show dialog + self.gobject.present(Some(&self.parent)) + } }