feat: add support for dark / light mode switching and simultaneouscustom light / dark mode themes

This commit is contained in:
Ashley Wulber 2023-10-03 13:26:35 -04:00
parent a91deacff5
commit b1b32b867c
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
9 changed files with 186 additions and 21 deletions

View file

@ -1,6 +1,9 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: MPL-2.0
use cosmic_config::CosmicConfigEntry;
use cosmic_theme::ThemeMode;
use crate::Theme;
/// Status of the nav bar and its panels.
@ -49,6 +52,9 @@ pub struct Core {
/// Last known system theme
pub(super) system_theme: Theme,
/// Theme mode
pub(super) system_theme_mode: ThemeMode,
pub(super) title: String,
pub window: Window,
@ -70,6 +76,16 @@ impl Default for Core {
scale_factor: 1.0,
title: String::new(),
system_theme: crate::theme::active(),
system_theme_mode: ThemeMode::config()
.map(|c| {
ThemeMode::get_entry(&c).unwrap_or_else(|(errors, mode)| {
for e in errors {
tracing::error!("{e}");
}
mode
})
})
.unwrap_or_default(),
window: Window {
context_title: String::new(),
header_title: String::new(),
@ -169,4 +185,15 @@ impl Core {
self.window.width = new_width;
self.is_condensed_update();
}
/// Get the current system theme
pub fn system_theme(&self) -> &Theme {
&self.system_theme
}
#[must_use]
/// Get the current system theme mode
pub fn system_theme_mode(&self) -> ThemeMode {
self.system_theme_mode
}
}

View file

@ -5,6 +5,7 @@ use super::{command, Application, ApplicationExt, Core, Subscription};
use crate::theme::{self, Theme, ThemeType, THEME};
use crate::widget::nav_bar;
use crate::{keyboard_nav, Element};
use cosmic_theme::ThemeMode;
#[cfg(feature = "wayland")]
use iced::event::wayland::{self, WindowEvent};
#[cfg(feature = "wayland")]
@ -44,6 +45,8 @@ pub enum Message {
ToggleNavBarCondensed,
/// Notification of system theme changes.
SystemThemeChange(Theme),
/// Notification of system theme mode changes.
SystemThemeModeChange(ThemeMode),
/// Updates the tracked window geometry.
WindowResize(window::Id, u32, u32),
/// Tracks updates to window state.
@ -152,9 +155,27 @@ where
keyboard_nav::subscription()
.map(Message::KeyboardNav)
.map(super::Message::Cosmic),
theme::subscription(0)
theme::subscription(0, self.app.core().system_theme_mode.is_dark)
.map(Message::SystemThemeChange)
.map(super::Message::Cosmic),
cosmic_config::config_subscription::<_, cosmic_theme::ThemeMode>(
0,
cosmic_theme::THEME_MODE_ID.into(),
cosmic_theme::ThemeMode::version(),
)
.map(|(_, u)| {
tracing::error!("{u:?}");
match u {
Ok(t) => Message::SystemThemeModeChange(t),
Err((errors, t)) => {
for e in errors {
tracing::error!("{e}");
}
Message::SystemThemeModeChange(t)
}
}
})
.map(super::Message::Cosmic),
window_events.map(super::Message::Cosmic),
])
}
@ -295,7 +316,7 @@ impl<T: Application> Cosmic<T> {
THEME.with(move |t| {
let mut cosmic_theme = t.borrow_mut();
// Anly apply update if the theme is set to load a system theme
// Only apply update if the theme is set to load a system theme
if let ThemeType::System(_) = cosmic_theme.theme_type {
cosmic_theme.set_theme(theme.theme_type);
}
@ -310,6 +331,10 @@ impl<T: Application> Cosmic<T> {
self.app.on_app_exit();
return self.close();
}
Message::SystemThemeModeChange(mode) => {
let core = self.app.core_mut();
core.system_theme_mode = mode;
}
}
iced::Command::none()

View file

@ -4,11 +4,11 @@
//! Contains the [`Theme`] type and its widget stylesheet implementations.
pub mod style;
use cosmic_theme::ThemeMode;
pub use style::*;
use cosmic_config::config_subscription;
use cosmic_config::CosmicConfigEntry;
use cosmic_theme::util::CssColor;
use cosmic_theme::Component;
use cosmic_theme::LayeredTheme;
use iced_futures::Subscription;
@ -68,10 +68,15 @@ pub fn is_high_contrast() -> bool {
}
/// Watches for changes to the system's theme preference.
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
config_subscription::<u64, crate::cosmic_theme::Theme<Srgba>>(
id,
crate::cosmic_theme::NAME.into(),
pub fn subscription(id: u64, is_dark: bool) -> Subscription<crate::theme::Theme> {
config_subscription::<_, crate::cosmic_theme::Theme<Srgba>>(
(id, is_dark),
if is_dark {
cosmic_theme::DARK_THEME_ID
} else {
cosmic_theme::LIGHT_THEME_ID
}
.into(),
crate::cosmic_theme::Theme::<Srgba>::version(),
)
.map(|(_, res)| {
@ -88,10 +93,21 @@ pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
/// Loads the preferred system theme from `cosmic-config`.
pub fn system_preference() -> Theme {
let Ok(helper) = crate::cosmic_config::Config::new(
crate::cosmic_theme::NAME,
crate::cosmic_theme::Theme::<CssColor>::version(),
) else {
let Ok(mode_config) = ThemeMode::config() else {
return Theme::dark();
};
let Ok(is_dark) = ThemeMode::is_dark(&mode_config) else {
return Theme::dark();
};
let helper = if is_dark {
crate::cosmic_theme::Theme::<Srgba>::dark_config()
} else {
crate::cosmic_theme::Theme::<Srgba>::light_config()
};
let Ok(helper) = helper else {
return Theme::dark();
};