From 104ff68bbb1add87d44756784916dfed27aad8c1 Mon Sep 17 00:00:00 2001 From: Nikita Podvirnyi Date: Wed, 1 Jan 2025 17:29:06 +0200 Subject: [PATCH] feat(ui): initial dynamic settings component writeup --- src/ui/components/dynamic_settings.rs | 176 ++++++++++++++++++++++++++ src/ui/components/mod.rs | 8 ++ 2 files changed, 184 insertions(+) create mode 100644 src/ui/components/dynamic_settings.rs diff --git a/src/ui/components/dynamic_settings.rs b/src/ui/components/dynamic_settings.rs new file mode 100644 index 0000000..02ef9ab --- /dev/null +++ b/src/ui/components/dynamic_settings.rs @@ -0,0 +1,176 @@ +use std::collections::HashMap; + +use adw::prelude::*; +use relm4::prelude::*; + +#[derive(Debug, Clone)] +pub struct DynamicSettingsComponentGroup { + pub group: adw::PreferencesGroup, + pub components: HashMap +} + +impl DynamicSettingsComponentGroup { + pub fn new( + title: Option>, + description: Option>, + components: impl Iterator + ) -> Self { + let group = adw::PreferencesGroup::new(); + let components = HashMap::from_iter(components); + + if let Some(title) = title { + group.set_title(title.as_ref()); + } + + if let Some(description) = description { + group.set_description(Some(description.as_ref())); + } + + for component in components.values() { + match component { + DynamicSettingsComponentRow::Switch(switch) => group.add(switch), + DynamicSettingsComponentRow::Text(text) => group.add(text), + DynamicSettingsComponentRow::Enum { component, .. } => group.add(component) + } + } + + Self { + group, + components + } + } +} + +#[derive(Debug, Clone)] +pub enum DynamicSettingsComponentRow { + Switch(adw::SwitchRow), + Text(adw::EntryRow), + + Enum { + component: adw::ComboRow, + values: HashMap + } +} + +impl DynamicSettingsComponentRow { + pub fn new_switch(title: impl AsRef, description: Option>, default: bool) -> Self { + let switch = adw::SwitchRow::new(); + + switch.set_title(title.as_ref()); + switch.set_active(default); + + if let Some(description) = description { + switch.set_subtitle(description.as_ref()); + } + + Self::Switch(switch) + } + + pub fn new_text(title: impl AsRef, description: Option>, default: impl AsRef) -> Self { + let text = adw::EntryRow::new(); + + text.set_title(title.as_ref()); + text.set_text(default.as_ref()); + + if let Some(description) = description { + text.set_tooltip(description.as_ref()); + } + + Self::Text(text) + } + + pub fn new_enum( + title: impl AsRef, + description: Option>, + values: impl Iterator, + default: impl AsRef + ) -> Self { + let component = adw::ComboRow::new(); + let values = HashMap::from_iter(values); + + component.set_title(title.as_ref()); + + if let Some(description) = description { + component.set_subtitle(description.as_ref()); + } + + let model = gtk::StringList::new(&[]); + let default = default.as_ref(); + + for item in values.values() { + model.append(item); + } + + component.set_model(Some(&model)); + + if let Some((k, _)) = values.keys().enumerate().find(|(_, k)| k == &default) { + component.set_selected(k as u32); + } + + Self::Enum { + component, + values + } + } +} + +#[derive(Debug, Clone)] +pub enum DynamicSettingsComponentInput { + AddGroup(DynamicSettingsComponentGroup), + Clear +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DynamicSettingsComponentOutput { + +} + +#[derive(Debug)] +pub struct DynamicSettingsComponent { + preferences_page: adw::PreferencesPage, + groups: Vec +} + +#[relm4::component(pub, async)] +impl SimpleAsyncComponent for DynamicSettingsComponent { + type Init = (); + type Input = DynamicSettingsComponentInput; + type Output = DynamicSettingsComponentOutput; + + view! { + #[root] + gtk::Box { + #[local_ref] + preferences_page -> adw::PreferencesPage, + } + } + + #[inline] + async fn init(_init: Self::Init, root: Self::Root, _sender: AsyncComponentSender) -> AsyncComponentParts { + let model = Self { + preferences_page: adw::PreferencesPage::new(), + groups: Vec::new() + }; + + let preferences_page = &model.preferences_page; + + let widgets = view_output!(); + + AsyncComponentParts { model, widgets } + } + + async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender) { + match msg { + DynamicSettingsComponentInput::AddGroup(group) => { + self.preferences_page.add(&group.group); + self.groups.push(group); + } + + DynamicSettingsComponentInput::Clear => { + for group in self.groups.drain(..) { + self.preferences_page.remove(&group.group); + } + } + } + } +} diff --git a/src/ui/components/mod.rs b/src/ui/components/mod.rs index 5764230..1236396 100644 --- a/src/ui/components/mod.rs +++ b/src/ui/components/mod.rs @@ -7,6 +7,7 @@ pub mod graph; pub mod game_store_details; pub mod hardware_requirements; +pub mod dynamic_settings; pub use lazy_picture::{ ImagePath, @@ -56,6 +57,13 @@ pub use hardware_requirements::{ HardwareRequirementsSectionMsg }; +pub use dynamic_settings::{ + DynamicSettingsComponentRow, + DynamicSettingsComponent, + DynamicSettingsComponentInput, + DynamicSettingsComponentOutput +}; + // FIXME: NOT REFACTORED pub mod downloads_row; pub mod game_library_details;