diff --git a/lact-gui/i18n/en/lact_gui.ftl b/lact-gui/i18n/en/lact_gui.ftl index 57458c8c..78c58a57 100644 --- a/lact-gui/i18n/en/lact_gui.ftl +++ b/lact-gui/i18n/en/lact_gui.ftl @@ -295,6 +295,11 @@ ui = UI daemon = Daemon about = About +color-scheme = Color Scheme +color-scheme-auto = System +color-scheme-light = Light +color-scheme-dark = Dark + # Crash page crash-page-title = Application Crashed exit = Exit diff --git a/lact-gui/i18n/it/lact_gui.ftl b/lact-gui/i18n/it/lact_gui.ftl index 8521d430..c16ce51c 100644 --- a/lact-gui/i18n/it/lact_gui.ftl +++ b/lact-gui/i18n/it/lact_gui.ftl @@ -267,3 +267,7 @@ version-mismatch-description = Se hai aggiornato LACT, รจ necessario riavviare il servizio con: close = Chiudi menu = Menu +color-scheme = Schema di Colori +color-scheme-auto = Sistema +color-scheme-light = Chiaro +color-scheme-dark = Scuro diff --git a/lact-gui/src/app.rs b/lact-gui/src/app.rs index 8c74244d..8937f76a 100644 --- a/lact-gui/src/app.rs +++ b/lact-gui/src/app.rs @@ -365,6 +365,7 @@ impl AsyncComponent for AppModel { if let Err(err) = styles::apply_theme(CONFIG.read().theme) { error!("could not apply theme: {err:#}"); } + CONFIG.read().color_scheme.apply(); let (daemon_client, conn_err) = match args.tcp_address { Some(remote_addr) => { diff --git a/lact-gui/src/app/preferences_dialog.rs b/lact-gui/src/app/preferences_dialog.rs index fff2302e..2012e077 100644 --- a/lact-gui/src/app/preferences_dialog.rs +++ b/lact-gui/src/app/preferences_dialog.rs @@ -3,7 +3,10 @@ use crate::{ app::{ APP_BROKER, msg::AppMsg, - utils::styles::{self, AppTheme}, + utils::{ + color_scheme::AppColorScheme, + styles::{self, AppTheme}, + }, }, config::{MAX_STATS_POLL_INTERVAL_MS, MIN_STATS_POLL_INTERVAL_MS}, }; @@ -27,6 +30,7 @@ pub struct PreferencesDialog { pub enum PreferencesDialogMsg { Show, ThemeSelected(AppTheme), + ColorSchemeSelected(AppColorScheme), } #[relm4::component(pub)] @@ -90,6 +94,52 @@ impl relm4::Component for PreferencesDialog { }, }, + adw::ActionRow { + set_title: &fl!(I18N, "color-scheme"), + + add_suffix = >k::Box { + set_orientation: gtk::Orientation::Horizontal, + add_css_class: "linked", + set_valign: gtk::Align::Center, + + #[name = "color_scheme_auto_btn"] + gtk::ToggleButton { + set_label: &fl!(I18N, "color-scheme-auto"), + #[watch] + set_active: CONFIG.read().color_scheme == AppColorScheme::Auto, + connect_toggled[sender] => move |btn| { + if btn.is_active() { + sender.input(PreferencesDialogMsg::ColorSchemeSelected(AppColorScheme::Auto)); + } + }, + }, + + gtk::ToggleButton { + set_label: &fl!(I18N, "color-scheme-light"), + set_group: Some(&color_scheme_auto_btn), + #[watch] + set_active: CONFIG.read().color_scheme == AppColorScheme::Light, + connect_toggled[sender] => move |btn| { + if btn.is_active() { + sender.input(PreferencesDialogMsg::ColorSchemeSelected(AppColorScheme::Light)); + } + }, + }, + + gtk::ToggleButton { + set_label: &fl!(I18N, "color-scheme-dark"), + set_group: Some(&color_scheme_auto_btn), + #[watch] + set_active: CONFIG.read().color_scheme == AppColorScheme::Dark, + connect_toggled[sender] => move |btn| { + if btn.is_active() { + sender.input(PreferencesDialogMsg::ColorSchemeSelected(AppColorScheme::Dark)); + } + }, + }, + }, + }, + adw::ActionRow { set_title: &fl!(I18N, "stats-update-interval"), @@ -174,6 +224,14 @@ impl relm4::Component for PreferencesDialog { config.theme = theme; }); } + PreferencesDialogMsg::ColorSchemeSelected(scheme) => { + scheme.apply(); + CONFIG.write().edit(|config| { + config.color_scheme = scheme; + }); + + styles::apply_theme(CONFIG.read().theme).expect("Could not apply theme"); + } } self.update_view(widgets, sender); } diff --git a/lact-gui/src/app/utils/color_scheme.rs b/lact-gui/src/app/utils/color_scheme.rs new file mode 100644 index 00000000..73bf4def --- /dev/null +++ b/lact-gui/src/app/utils/color_scheme.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum AppColorScheme { + #[default] + Auto, + Light, + Dark, +} + +impl From for adw::ColorScheme { + fn from(value: AppColorScheme) -> Self { + match value { + AppColorScheme::Auto => adw::ColorScheme::Default, + AppColorScheme::Light => adw::ColorScheme::ForceLight, + AppColorScheme::Dark => adw::ColorScheme::ForceDark, + } + } +} + +impl AppColorScheme { + pub fn apply(&self) { + adw::StyleManager::default().set_color_scheme((*self).into()); + } +} diff --git a/lact-gui/src/app/utils/mod.rs b/lact-gui/src/app/utils/mod.rs index eafa1f12..b034a488 100644 --- a/lact-gui/src/app/utils/mod.rs +++ b/lact-gui/src/app/utils/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod color_scheme; pub(crate) mod ext; pub(crate) mod formatting; pub(crate) mod styles; diff --git a/lact-gui/src/app/utils/styles.rs b/lact-gui/src/app/utils/styles.rs index eae328f8..458f5585 100644 --- a/lact-gui/src/app/utils/styles.rs +++ b/lact-gui/src/app/utils/styles.rs @@ -5,6 +5,8 @@ use gtk::{ use serde::{Deserialize, Serialize}; use std::cell::RefCell; +use crate::{CONFIG, app::utils::color_scheme::AppColorScheme}; + pub const COMBINED_CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/combined.css")); macro_rules! include_theme_str { @@ -72,9 +74,13 @@ pub fn apply_theme(theme: AppTheme) -> anyhow::Result<()> { fn breeze_css() -> &'static str { let settings = gio::Settings::new("org.gnome.desktop.interface"); - match settings.string("color-scheme").as_str() { - "prefer-dark" => BREEZE_DARK_CSS, - "prefer-light" => BREEZE_LIGHT_CSS, + let system_colors = settings.string("color-scheme"); + + let app_colors = CONFIG.read().color_scheme; + + match (app_colors, system_colors.as_str()) { + (AppColorScheme::Dark, _) | (AppColorScheme::Auto, "prefer-dark") => BREEZE_DARK_CSS, + (AppColorScheme::Light, _) | (AppColorScheme::Auto, "prefer-light") => BREEZE_LIGHT_CSS, _ => BREEZE_LIGHT_CSS, } } diff --git a/lact-gui/src/config.rs b/lact-gui/src/config.rs index 103f2a22..0d5a5f28 100644 --- a/lact-gui/src/config.rs +++ b/lact-gui/src/config.rs @@ -1,4 +1,7 @@ -use crate::app::{graphs_window::stat::StatType, utils::styles::AppTheme}; +use crate::app::{ + graphs_window::stat::StatType, + utils::{color_scheme::AppColorScheme, styles::AppTheme}, +}; use serde::{Deserialize, Deserializer, Serialize}; use serde_with::skip_serializing_none; use std::{collections::HashMap, env, fs, path::PathBuf}; @@ -24,6 +27,8 @@ pub struct UiConfig { pub gpus: HashMap, #[serde(default)] pub theme: AppTheme, + #[serde(default)] + pub color_scheme: AppColorScheme, pub window_size: Option, } @@ -37,6 +42,7 @@ impl Default for UiConfig { stats_poll_interval_ms: default_stats_poll_interval(), gpus: HashMap::new(), theme: AppTheme::Automatic, + color_scheme: AppColorScheme::default(), window_size: None, } }