From e0eae7c13a1fa699642f1361277f2ae1fc84abdf Mon Sep 17 00:00:00 2001 From: Gabriele Musco Date: Thu, 1 May 2025 01:18:46 +0200 Subject: [PATCH] feat: theme manager --- Cargo.lock | 23 ++++++++++++++------ Cargo.toml | 1 + src/config.rs | 7 +++++++ src/ui/app.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++- src/ui/main_view.rs | 2 ++ 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 74138cb..cb2d639 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -445,6 +445,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "delicious-adwaita" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53548c789a95211e0ce6d26c213067002b9b4360f8de69046d84de78ad9da3f" +dependencies = [ + "gtk4", + "libadwaita", +] + [[package]] name = "deranged" version = "0.3.11" @@ -567,6 +577,7 @@ version = "3.1.1" dependencies = [ "anyhow", "ash", + "delicious-adwaita", "gettext-rs", "git2", "gtk4", @@ -1073,9 +1084,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9376d14d7e33486c54823a42bef296e882b9f25cb4c52b52f4d1d57bbadb5b6d" +checksum = "af1c491051f030994fd0cde6f3c44f3f5640210308cff1298c7673c47408091d" dependencies = [ "cairo-rs", "field-offset", @@ -1106,9 +1117,9 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e653b0a9001ba9be1ffddb9373bfe9a111f688222f5aeee2841481300d91b55a" +checksum = "41e03b01e54d77c310e1d98647d73f996d04b2f29b9121fe493ea525a7ec03d6" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1523,9 +1534,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libadwaita" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8611ee9fb85e7606c362b513afcaf5b59853f79e4d98caaaf581d99465014247" +checksum = "500135d29c16aabf67baafd3e7741d48e8b8978ca98bac39e589165c8dc78191" dependencies = [ "gdk4", "gio", diff --git a/Cargo.toml b/Cargo.toml index 62cf1dc..4ecd109 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,3 +44,4 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter", "json"] } tracing = "0.1.41" tracing-appender = "0.2.3" serde_yaml = "0.9.34" +delicious-adwaita = { version = "0.3.0", features = ["all_themes"] } diff --git a/src/config.rs b/src/config.rs index 18cd864..80cf0f5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,6 +45,10 @@ const fn default_win_size() -> [i32; 2] { DEFAULT_WIN_SIZE } +fn default_theme_name() -> String { + "Follow system".into() +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Config { pub selected_profile_uuid: String, @@ -54,6 +58,8 @@ pub struct Config { pub win_size: [i32; 2], #[serde(default)] pub plugins: HashMap, + #[serde(default = "default_theme_name")] + pub theme_name: String, } impl Default for Config { @@ -65,6 +71,7 @@ impl Default for Config { user_profiles: Vec::default(), win_size: DEFAULT_WIN_SIZE, plugins: HashMap::default(), + theme_name: default_theme_name(), } } } diff --git a/src/ui/app.rs b/src/ui/app.rs index c4f3b10..4cc6520 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -51,6 +51,7 @@ use crate::{ xr_devices::XRDevice, }; use adw::{prelude::*, ResponseAppearance}; +use delicious_adwaita::{theme::Theme, ThemeEngine}; use gtk::glib::{self, clone}; use notify_rust::NotificationHandle; use relm4::{ @@ -96,6 +97,8 @@ pub struct App { inhibit_fail_notif: Option, pluginstore: Option>, + + theme_engine: ThemeEngine, } #[derive(Debug)] @@ -130,6 +133,8 @@ pub enum Msg { WivrnCheckPairMode, OpenPluginStore, UpdateConfigPlugins(HashMap), + ShowThemeManager, + SaveThemeConfig, NoOp, } @@ -367,7 +372,7 @@ impl AsyncComponent for App { set_content: Some(&adw::NavigationPage::new(model.debug_view.widget(), "Debug View")), set_show_content: false, set_collapsed: !model.config.debug_view_enabled, - } + }, }, connect_close_request[sender] => move |win| { sender.input(Msg::SaveWinSize(win.width(), win.height())); @@ -391,6 +396,27 @@ impl AsyncComponent for App { ) { match message { Msg::NoOp => {} + Msg::ShowThemeManager => { + let dialog = self + .theme_engine + .theme_chooser_dialog(Theme::default_themes().as_ref()); + dialog.set_content_height(2000); + dialog.present(Some(&self.app_win)); + dialog.connect_closed(clone!( + #[strong] + sender, + move |_| { + sender.input(Msg::SaveThemeConfig); + } + )); + } + Msg::SaveThemeConfig => { + let name = self.theme_engine.current_theme_name(); + if self.config.theme_name != name { + self.config.theme_name = name; + self.config.save(); + } + } Msg::OnServiceLog(rows) => { if !rows.is_empty() { self.debug_view @@ -974,6 +1000,17 @@ impl AsyncComponent for App { } ) ); + stateless_action!( + actions, + ThemeManagerAction, + clone!( + #[strong] + sender, + move |_| { + sender.input(Msg::ShowThemeManager); + } + ) + ); // this bypasses the macro because I need the underlying gio action // to enable/disable it in update() let configure_wivrn_action = { @@ -1042,6 +1079,17 @@ impl AsyncComponent for App { .detach(), split_view: None, setcap_confirm_dialog, + theme_engine: ThemeEngine::new_with_theme(&{ + if config.theme_name == "Follow system" { + Theme::default() + } else { + Theme::default_themes() + .into_iter() + .find(|t| t.name == config.theme_name) + .unwrap_or_default() + } + }) + .unwrap(), config, profiles, xrservice_worker: None, @@ -1130,6 +1178,7 @@ new_stateless_action!(pub QuitAction, AppActionGroup, "quit"); new_stateful_action!(pub DebugViewToggleAction, AppActionGroup, "debugviewtoggle", (), bool); new_stateless_action!(pub ConfigureWivrnAction, AppActionGroup, "configurewivrn"); new_stateless_action!(pub PluginStoreAction, AppActionGroup, "store"); +new_stateless_action!(pub ThemeManagerAction, AppActionGroup, "thememanager"); new_stateless_action!(pub DebugOpenDataAction, AppActionGroup, "debugopendata"); new_stateless_action!(pub DebugOpenPrefixAction, AppActionGroup, "debugopenprefix"); diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index 09cd408..8a2c145 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -21,6 +21,7 @@ use crate::{ paths::{get_data_dir, get_home_dir}, profile::{LighthouseDriver, Profile, XRServiceType}, stateless_action, + ui::app::ThemeManagerAction, util::{ file_utils::{get_writer, mount_has_nosuid}, steamvr_utils::chaperone_info_exists, @@ -159,6 +160,7 @@ impl AsyncComponent for MainView { "Configure _WiVRn" => ConfigureWivrnAction, }, section! { + "Change _Theme" => ThemeManagerAction, "_About" => AboutAction, }, },