From 50497621672a7f6b636cfe73e9015c5341b0d093 Mon Sep 17 00:00:00 2001 From: Hannes Kuchelmeister Date: Fri, 5 Aug 2022 12:47:48 +0200 Subject: [PATCH] Added internal messaging and workers to handle per toolbx settings, actual settings handling still missing --- src/main.rs | 1 + src/ui/app/messages.rs | 2 +- src/ui/app/toolbox_list.rs | 7 +- src/ui/app/update.rs | 14 ++-- .../components/toolbox_settings/components.rs | 11 +++ .../components/toolbox_settings/messages.rs | 7 +- src/ui/components/toolbox_settings/mod.rs | 2 + src/ui/components/toolbox_settings/model.rs | 14 +++- src/ui/components/toolbox_settings/update.rs | 53 +++++++++++-- src/ui/components/toolbox_settings/widgets.rs | 2 +- src/ui/components/toolbox_settings/workers.rs | 76 +++++++++++++++++++ 11 files changed, 171 insertions(+), 18 deletions(-) create mode 100644 src/ui/components/toolbox_settings/components.rs create mode 100644 src/ui/components/toolbox_settings/workers.rs diff --git a/src/main.rs b/src/main.rs index 4e0cb79..dc1b143 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use std::collections::VecDeque; +use relm4::gtk::{Application, ApplicationWindow}; use relm4::{factory::FactoryVecDeque, RelmApp}; use toolbx::ToolbxContainer; use ui::app::model::AppModel; diff --git a/src/ui/app/messages.rs b/src/ui/app/messages.rs index 6b138b4..a344449 100644 --- a/src/ui/app/messages.rs +++ b/src/ui/app/messages.rs @@ -5,7 +5,7 @@ use crate::toolbx::ToolbxContainer; use super::model::ToolbxEntry; pub enum AppMsg { - ShowToolboxSettingsRequest, + ShowToolboxSettingsRequest(DynamicIndex), ShowToolboxAppsRequest, ToolbxListUpdate(Vec), ToolbxContainerToggleStartStop(DynamicIndex), diff --git a/src/ui/app/toolbox_list.rs b/src/ui/app/toolbox_list.rs index 878356a..140a4e3 100644 --- a/src/ui/app/toolbox_list.rs +++ b/src/ui/app/toolbox_list.rs @@ -33,7 +33,8 @@ impl FactoryPrototype for ToolbxEntry { type Msg = AppMsg; fn init_view(&self, key: &DynamicIndex, sender: Sender) -> Self::Widgets { - let index = key.clone(); + let index_terminal = key.clone(); + let index_settings = key.clone(); view! { suffix_box = >k::Box{ @@ -60,7 +61,7 @@ impl FactoryPrototype for ToolbxEntry { set_tooltip_text: Some(TERMINAL_TOOLTIP), set_css_classes: &["flat"], connect_clicked(sender) => move |btn| { - send!(sender, AppMsg::OpenToolbxTerminal(index.clone())); + send!(sender, AppMsg::OpenToolbxTerminal(index_terminal.clone())); }, } }, @@ -73,7 +74,7 @@ impl FactoryPrototype for ToolbxEntry { set_tooltip_text: Some(SETTINGS_TOOLTIP), set_css_classes: &["circular"], connect_clicked(sender) => move |btn| { - send!(sender, AppMsg::ShowToolboxSettingsRequest); + send!(sender, AppMsg::ShowToolboxSettingsRequest(index_settings.clone())); }, }, } diff --git a/src/ui/app/update.rs b/src/ui/app/update.rs index 777b739..76c7bfd 100644 --- a/src/ui/app/update.rs +++ b/src/ui/app/update.rs @@ -15,11 +15,15 @@ use super::{messages::AppMsg, model::AppModel, workers::AsyncHandlerMsg}; impl AppUpdate for AppModel { fn update(&mut self, msg: AppMsg, components: &AppComponents, _sender: Sender) -> bool { match msg { - AppMsg::ShowToolboxSettingsRequest => { - components - .toolbox_settings_dialog - .send(ToolboxSettingsDialogMsg::Show) - .unwrap(); + AppMsg::ShowToolboxSettingsRequest(index) => { + if let Some(toolbx_entry) = self.toolboxes.get(index.current_index()) { + components + .toolbox_settings_dialog + .send(ToolboxSettingsDialogMsg::Show( + toolbx_entry.toolbx_container.clone(), + )) + .unwrap(); + } } AppMsg::ShowToolboxAppsRequest => { components diff --git a/src/ui/components/toolbox_settings/components.rs b/src/ui/components/toolbox_settings/components.rs new file mode 100644 index 0000000..ad8ac23 --- /dev/null +++ b/src/ui/components/toolbox_settings/components.rs @@ -0,0 +1,11 @@ +use relm4::RelmComponent; +use relm4::RelmMsgHandler; +use relm4::Sender; + +use super::model::ToolboxSettingsDialogModel; +use crate::ui::components::toolbox_settings::workers::AsyncSettingsHandler; + +#[derive(relm4::Components)] +pub struct SettingsComponents { + pub async_handler: RelmMsgHandler, +} diff --git a/src/ui/components/toolbox_settings/messages.rs b/src/ui/components/toolbox_settings/messages.rs index c3555f9..a530798 100644 --- a/src/ui/components/toolbox_settings/messages.rs +++ b/src/ui/components/toolbox_settings/messages.rs @@ -1,4 +1,9 @@ +use crate::toolbx::ToolbxContainer; + +use super::model::ToolboxPreferences; + pub enum ToolboxSettingsDialogMsg { - Show, + Show(ToolbxContainer), + ReplyToolbxSettings(ToolboxPreferences), Close, } diff --git a/src/ui/components/toolbox_settings/mod.rs b/src/ui/components/toolbox_settings/mod.rs index a48f622..79c7f13 100644 --- a/src/ui/components/toolbox_settings/mod.rs +++ b/src/ui/components/toolbox_settings/mod.rs @@ -1,4 +1,6 @@ +pub mod components; pub mod messages; pub mod model; pub mod update; pub mod widgets; +pub mod workers; diff --git a/src/ui/components/toolbox_settings/model.rs b/src/ui/components/toolbox_settings/model.rs index e0f07be..69fade0 100644 --- a/src/ui/components/toolbox_settings/model.rs +++ b/src/ui/components/toolbox_settings/model.rs @@ -1,13 +1,23 @@ use relm4::Model; -use super::{messages::ToolboxSettingsDialogMsg, widgets::ToolboxSettingsDialogWidgets}; +use super::{ + components::SettingsComponents, messages::ToolboxSettingsDialogMsg, + widgets::ToolboxSettingsDialogWidgets, +}; +use crate::toolbx::ToolbxContainer; pub struct ToolboxSettingsDialogModel { pub hidden: bool, + pub window_title: Option, + pub current_toolbox_container: Option, + pub current_toolbx_settings: Option, } impl Model for ToolboxSettingsDialogModel { type Msg = ToolboxSettingsDialogMsg; type Widgets = ToolboxSettingsDialogWidgets; - type Components = (); + type Components = SettingsComponents; } + +#[derive(Debug, Clone)] +pub struct ToolboxPreferences {} diff --git a/src/ui/components/toolbox_settings/update.rs b/src/ui/components/toolbox_settings/update.rs index 4ea78aa..361d2bc 100644 --- a/src/ui/components/toolbox_settings/update.rs +++ b/src/ui/components/toolbox_settings/update.rs @@ -2,23 +2,66 @@ use relm4::{ComponentUpdate, Sender}; use crate::ui::app::{messages::AppMsg, model::AppModel}; -use super::{messages::ToolboxSettingsDialogMsg, model::ToolboxSettingsDialogModel}; +use super::{ + components::SettingsComponents, messages::ToolboxSettingsDialogMsg, + model::ToolboxSettingsDialogModel, workers::AsyncSettingsHandlerMsg, +}; impl ComponentUpdate for ToolboxSettingsDialogModel { fn init_model(_parent_model: &AppModel) -> Self { - ToolboxSettingsDialogModel { hidden: true } + ToolboxSettingsDialogModel { + hidden: true, + window_title: None, + current_toolbox_container: None, + current_toolbx_settings: None, + } } fn update( &mut self, msg: ToolboxSettingsDialogMsg, - _components: &(), + components: &SettingsComponents, _sender: Sender, parent_sender: Sender, ) { match msg { - ToolboxSettingsDialogMsg::Show => self.hidden = false, - ToolboxSettingsDialogMsg::Close => self.hidden = true, + ToolboxSettingsDialogMsg::ReplyToolbxSettings(settings) => { + self.current_toolbx_settings = Some(settings); + println!("Received Toolbox Settings"); + } + ToolboxSettingsDialogMsg::Show(toolbx_container) => { + self.hidden = false; + self.window_title = Some(format!( + "Toolbx Preferences: {}", + toolbx_container.name.clone() + )); + // TODO: create settings handling for each toolbox + // probably settings for a toolbox should be stored in a HashMap and loaded based on that + components + .async_handler + .sender() + .blocking_send(AsyncSettingsHandlerMsg::RequestToolbxSettings( + toolbx_container.clone(), + )) + .expect("Receiver dropped"); + self.current_toolbox_container = Some(toolbx_container); + } + ToolboxSettingsDialogMsg::Close => { + self.current_toolbx_settings.as_ref().map(|settings| { + components + .async_handler + .sender() + .blocking_send(AsyncSettingsHandlerMsg::SaveToolboxSettings( + settings.clone(), + )) + .expect("Receiver dropped"); + }); + + self.hidden = true; + self.window_title = None; + self.current_toolbox_container = None; + self.current_toolbx_settings = None; + } } } } diff --git a/src/ui/components/toolbox_settings/widgets.rs b/src/ui/components/toolbox_settings/widgets.rs index 3ca14ce..aefd5d1 100644 --- a/src/ui/components/toolbox_settings/widgets.rs +++ b/src/ui/components/toolbox_settings/widgets.rs @@ -24,7 +24,7 @@ use super::model::ToolboxSettingsDialogModel; impl Widgets for ToolboxSettingsDialogWidgets { view! { adw::PreferencesWindow { - set_title: Some("Preferences: "), + set_title: watch!{ model.window_title.as_ref().map( |x| x.as_str() ) }, set_transient_for: parent!{Some(&parent_widgets.main_window)}, set_modal: true, set_visible: watch!(!model.hidden), diff --git a/src/ui/components/toolbox_settings/workers.rs b/src/ui/components/toolbox_settings/workers.rs new file mode 100644 index 0000000..979c65a --- /dev/null +++ b/src/ui/components/toolbox_settings/workers.rs @@ -0,0 +1,76 @@ +use std::time::Duration; + +use crate::toolbx::ToolbxContainer; + +use relm4::factory::DynamicIndex; +use relm4::{send, MessageHandler, Sender}; +use tokio::runtime::{Builder, Runtime}; +use tokio::sync::mpsc::{channel, Sender as TokioSender}; + +use crate::ui::app::{messages::AppMsg, model::AppModel}; + +use super::model::ToolboxPreferences; +use crate::ui::components::toolbox_settings::messages::ToolboxSettingsDialogMsg; +use crate::ui::components::ToolboxSettingsDialogModel; + +// Code adapted from https://relm4.org/book/stable/message_handler.html +pub struct AsyncSettingsHandler { + _rt: Runtime, + sender: TokioSender, +} + +#[derive(Debug)] +pub enum AsyncSettingsHandlerMsg { + RequestToolbxSettings(ToolbxContainer), + SaveToolboxSettings(ToolboxPreferences), +} + +impl MessageHandler for AsyncSettingsHandler { + type Msg = AsyncSettingsHandlerMsg; + type Sender = TokioSender; + + fn init( + _parent_model: &ToolboxSettingsDialogModel, + parent_sender: Sender, + ) -> Self { + let (sender, mut rx) = channel::(10); + + let rt = Builder::new_multi_thread() + .worker_threads(1) + .enable_time() + .build() + .unwrap(); + + rt.spawn(async move { + while let Some(msg) = rx.recv().await { + let parent_sender = parent_sender.clone(); + tokio::spawn(async move { + match msg { + AsyncSettingsHandlerMsg::SaveToolboxSettings(tbx_settings) => { + // TODO: actually save settings + println!("Received Toolbx Settings save request"); + } + AsyncSettingsHandlerMsg::RequestToolbxSettings(tbx) => { + println!("Received ToolbxSettings Request"); + parent_sender + .send(ToolboxSettingsDialogMsg::ReplyToolbxSettings( + ToolboxPreferences {}, + )) + .unwrap(); + } + } + }); + } + }); + + AsyncSettingsHandler { _rt: rt, sender } + } + + fn send(&self, msg: Self::Msg) { + self.sender.blocking_send(msg).unwrap(); + } + + fn sender(&self) -> Self::Sender { + self.sender.clone() + } +}