refactor: introduce thread local THEME variable and distinguish between custom and system theme settings
This commit is contained in:
parent
40efcbbe31
commit
6c57e04e36
8 changed files with 80 additions and 36 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
/// Copyright 2022 System76 <info@system76.com>
|
/// Copyright 2022 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
cosmic_config::config_subscription,
|
cosmic_theme::{
|
||||||
|
palette::{rgb::Rgb, Srgba},
|
||||||
|
ThemeBuilder,
|
||||||
|
},
|
||||||
font::load_fonts,
|
font::load_fonts,
|
||||||
iced::{self, Application, Command, Length, Subscription},
|
iced::{self, Application, Command, Length, Subscription},
|
||||||
iced::{
|
iced::{
|
||||||
|
|
@ -10,7 +13,7 @@ use cosmic::{
|
||||||
window::{self, close, drag, minimize, toggle_maximize},
|
window::{self, close, drag, minimize, toggle_maximize},
|
||||||
},
|
},
|
||||||
keyboard_nav,
|
keyboard_nav,
|
||||||
theme::{self, CosmicTheme, Theme},
|
theme::{self, Theme},
|
||||||
widget::{
|
widget::{
|
||||||
header_bar, icon, list, nav_bar, nav_bar_toggle, scrollable, segmented_button, settings,
|
header_bar, icon, list, nav_bar, nav_bar_toggle, scrollable, segmented_button, settings,
|
||||||
warning, IconSource,
|
warning, IconSource,
|
||||||
|
|
@ -18,9 +21,7 @@ use cosmic::{
|
||||||
Element, ElementExt,
|
Element, ElementExt,
|
||||||
};
|
};
|
||||||
use cosmic_time::{Instant, Timeline};
|
use cosmic_time::{Instant, Timeline};
|
||||||
use log::error;
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{
|
sync::{
|
||||||
|
|
@ -163,7 +164,6 @@ pub struct Window {
|
||||||
warning_message: String,
|
warning_message: String,
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
scale_factor_string: String,
|
scale_factor_string: String,
|
||||||
system_theme: Arc<CosmicTheme>,
|
|
||||||
timeline: Rc<RefCell<Timeline>>,
|
timeline: Rc<RefCell<Timeline>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,7 +209,6 @@ pub enum Message {
|
||||||
ToggleNavBarCondensed,
|
ToggleNavBarCondensed,
|
||||||
ToggleWarning,
|
ToggleWarning,
|
||||||
FontsLoaded,
|
FontsLoaded,
|
||||||
SystemTheme(CosmicTheme),
|
|
||||||
Tick(Instant),
|
Tick(Instant),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,17 +388,6 @@ impl Application for Window {
|
||||||
Subscription::batch(vec![
|
Subscription::batch(vec![
|
||||||
window_break.map(|_| Message::CondensedViewToggle),
|
window_break.map(|_| Message::CondensedViewToggle),
|
||||||
keyboard_nav::subscription().map(Message::KeyboardNav),
|
keyboard_nav::subscription().map(Message::KeyboardNav),
|
||||||
config_subscription::<_, CosmicTheme>(0, Cow::from("com.system76.CosmicTheme"), 1).map(
|
|
||||||
|(_, update)| match update {
|
|
||||||
Ok(t) => Message::SystemTheme(t),
|
|
||||||
Err((errors, t)) => {
|
|
||||||
for error in errors {
|
|
||||||
error!("{:?}", error);
|
|
||||||
}
|
|
||||||
Message::SystemTheme(t)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
self.timeline
|
self.timeline
|
||||||
.borrow()
|
.borrow()
|
||||||
.as_subscription()
|
.as_subscription()
|
||||||
|
|
@ -429,7 +417,18 @@ impl Application for Window {
|
||||||
demo::ThemeVariant::Dark => Theme::dark(),
|
demo::ThemeVariant::Dark => Theme::dark(),
|
||||||
demo::ThemeVariant::HighContrastDark => Theme::dark_hc(),
|
demo::ThemeVariant::HighContrastDark => Theme::dark_hc(),
|
||||||
demo::ThemeVariant::HighContrastLight => Theme::light_hc(),
|
demo::ThemeVariant::HighContrastLight => Theme::light_hc(),
|
||||||
demo::ThemeVariant::Custom => Theme::custom(self.system_theme.clone()),
|
demo::ThemeVariant::Custom => Theme::custom(Arc::new(
|
||||||
|
ThemeBuilder::light()
|
||||||
|
.bg_color(Srgba::new(1.0, 0.9, 0.9, 1.0))
|
||||||
|
.text_tint(Rgb::new(0.0, 1.0, 0.0))
|
||||||
|
.neutral_tint(Rgb::new(0.0, 0.5, 1.0))
|
||||||
|
.accent(Rgb::new(0.5, 0.1, 0.5))
|
||||||
|
.success(Rgb::new(0.0, 0.5, 0.3))
|
||||||
|
.warning(Rgb::new(0.894, 0.816, 0.039))
|
||||||
|
.destructive(Rgb::new(0.890, 0.145, 0.420))
|
||||||
|
.build(),
|
||||||
|
)),
|
||||||
|
demo::ThemeVariant::System => cosmic::theme::theme(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Some(demo::Output::ToggleWarning) => self.toggle_warning(),
|
Some(demo::Output::ToggleWarning) => self.toggle_warning(),
|
||||||
|
|
@ -460,9 +459,6 @@ impl Application for Window {
|
||||||
},
|
},
|
||||||
Message::ToggleWarning => self.toggle_warning(),
|
Message::ToggleWarning => self.toggle_warning(),
|
||||||
Message::FontsLoaded => {}
|
Message::FontsLoaded => {}
|
||||||
Message::SystemTheme(t) => {
|
|
||||||
self.system_theme = Arc::new(t);
|
|
||||||
}
|
|
||||||
Message::Tick(instant) => self.timeline.borrow_mut().now(instant),
|
Message::Tick(instant) => self.timeline.borrow_mut().now(instant),
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ pub enum ThemeVariant {
|
||||||
HighContrastDark,
|
HighContrastDark,
|
||||||
HighContrastLight,
|
HighContrastLight,
|
||||||
Custom,
|
Custom,
|
||||||
|
System,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ThemeType> for ThemeVariant {
|
impl From<&ThemeType> for ThemeVariant {
|
||||||
|
|
@ -37,6 +38,7 @@ impl From<&ThemeType> for ThemeVariant {
|
||||||
ThemeType::HighContrastDark => ThemeVariant::HighContrastDark,
|
ThemeType::HighContrastDark => ThemeVariant::HighContrastDark,
|
||||||
ThemeType::HighContrastLight => ThemeVariant::HighContrastLight,
|
ThemeType::HighContrastLight => ThemeVariant::HighContrastLight,
|
||||||
ThemeType::Custom(_) => ThemeVariant::Custom,
|
ThemeType::Custom(_) => ThemeVariant::Custom,
|
||||||
|
ThemeType::System(_) => ThemeVariant::System,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -210,8 +212,9 @@ impl State {
|
||||||
ThemeVariant::Light,
|
ThemeVariant::Light,
|
||||||
ThemeVariant::Dark,
|
ThemeVariant::Dark,
|
||||||
ThemeVariant::HighContrastLight,
|
ThemeVariant::HighContrastLight,
|
||||||
ThemeVariant::HighContrastLight,
|
ThemeVariant::HighContrastDark,
|
||||||
ThemeVariant::Custom,
|
ThemeVariant::Custom,
|
||||||
|
ThemeVariant::System,
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(
|
.fold(
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_desktop_wallpaper<'a>(&'a self, window: &'a Window) -> Element<'a, Message> {
|
fn view_desktop_wallpaper<'a>(&'a self, window: &'a Window) -> Element<'a, Message> {
|
||||||
let mut image_paths: Vec<std::path::PathBuf> = Vec::new();
|
let image_paths: Vec<std::path::PathBuf> = Vec::new();
|
||||||
/*
|
/*
|
||||||
//TODO: load image paths, do this asynchronously somehow
|
//TODO: load image paths, do this asynchronously somehow
|
||||||
if let Ok(entries) = std::fs::read_dir("/usr/share/backgrounds") {
|
if let Ok(entries) = std::fs::read_dir("/usr/share/backgrounds") {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use apply::Apply;
|
use cosmic::iced::widget::{horizontal_space, row};
|
||||||
use cosmic::iced::widget::{horizontal_space, row, scrollable};
|
|
||||||
use cosmic::iced::{Alignment, Length};
|
use cosmic::iced::{Alignment, Length};
|
||||||
use cosmic::widget::{button, segmented_button, view_switcher};
|
use cosmic::widget::{button, segmented_button, view_switcher};
|
||||||
use cosmic::{theme, Element};
|
use cosmic::{theme, Element};
|
||||||
|
|
@ -60,7 +59,7 @@ impl State {
|
||||||
self.pages.remove(id);
|
self.pages.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn view<'a>(&'a self, window: &'a super::Window) -> Element<'a, Message> {
|
pub(super) fn view<'a>(&'a self, _window: &'a super::Window) -> Element<'a, Message> {
|
||||||
let tabs = view_switcher::horizontal(&self.pages)
|
let tabs = view_switcher::horizontal(&self.pages)
|
||||||
.show_close_icon_on_hover(true)
|
.show_close_icon_on_hover(true)
|
||||||
.on_activate(Message::Activate)
|
.on_activate(Message::Activate)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ pub struct Core {
|
||||||
/// Scaling factor used by the application
|
/// Scaling factor used by the application
|
||||||
scale_factor: f32,
|
scale_factor: f32,
|
||||||
|
|
||||||
pub theme: Theme,
|
pub system_theme: Theme,
|
||||||
pub(crate) title: String,
|
pub(crate) title: String,
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ impl Default for Core {
|
||||||
toggled_condensed: true,
|
toggled_condensed: true,
|
||||||
},
|
},
|
||||||
scale_factor: 1.0,
|
scale_factor: 1.0,
|
||||||
theme: theme::theme(),
|
system_theme: theme::theme(),
|
||||||
title: String::new(),
|
title: String::new(),
|
||||||
window: Window {
|
window: Window {
|
||||||
can_fullscreen: false,
|
can_fullscreen: false,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use super::{command, Application, ApplicationExt, Core, Subscription};
|
use super::{command, Application, ApplicationExt, Core, Subscription};
|
||||||
use crate::theme::{self, Theme};
|
use crate::theme::{self, Theme, ThemeType, THEME};
|
||||||
use crate::widget::nav_bar;
|
use crate::widget::nav_bar;
|
||||||
use crate::{keyboard_nav, Element};
|
use crate::{keyboard_nav, Element};
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
|
|
@ -36,6 +36,8 @@ pub enum Message {
|
||||||
ScaleFactor(f32),
|
ScaleFactor(f32),
|
||||||
/// Requests theme changes.
|
/// Requests theme changes.
|
||||||
ThemeChange(Theme),
|
ThemeChange(Theme),
|
||||||
|
/// Notification of system theme changes.
|
||||||
|
SystemThemeChange(Theme),
|
||||||
/// Toggles visibility of the nav bar.
|
/// Toggles visibility of the nav bar.
|
||||||
ToggleNavBar,
|
ToggleNavBar,
|
||||||
/// Toggles the condensed status of the nav bar.
|
/// Toggles the condensed status of the nav bar.
|
||||||
|
|
@ -146,14 +148,14 @@ where
|
||||||
.map(Message::KeyboardNav)
|
.map(Message::KeyboardNav)
|
||||||
.map(super::Message::Cosmic),
|
.map(super::Message::Cosmic),
|
||||||
theme::subscription(0)
|
theme::subscription(0)
|
||||||
.map(Message::ThemeChange)
|
.map(Message::SystemThemeChange)
|
||||||
.map(super::Message::Cosmic),
|
.map(super::Message::Cosmic),
|
||||||
window_events.map(super::Message::Cosmic),
|
window_events.map(super::Message::Cosmic),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn theme(&self) -> Self::Theme {
|
fn theme(&self) -> Self::Theme {
|
||||||
self.app.core().theme.clone()
|
THEME.with(|t| t.borrow().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
|
|
@ -267,12 +269,32 @@ impl<T: Application> Cosmic<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::ThemeChange(theme) => {
|
Message::ThemeChange(theme) => {
|
||||||
self.app.core_mut().theme = theme;
|
// our system theme is always receiving updates so we should use it instead
|
||||||
|
let theme = if matches!(theme.theme_type, ThemeType::System(_)) {
|
||||||
|
self.app.core().system_theme.clone()
|
||||||
|
} else {
|
||||||
|
theme
|
||||||
|
};
|
||||||
|
|
||||||
|
THEME.with(move |t| {
|
||||||
|
let mut cosmic_theme = t.borrow_mut();
|
||||||
|
cosmic_theme.set_theme(theme.theme_type);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::ScaleFactor(factor) => {
|
Message::ScaleFactor(factor) => {
|
||||||
self.app.core_mut().set_scale_factor(factor);
|
self.app.core_mut().set_scale_factor(factor);
|
||||||
}
|
}
|
||||||
|
Message::SystemThemeChange(theme) => {
|
||||||
|
self.app.core_mut().system_theme = theme.clone();
|
||||||
|
THEME.with(move |t| {
|
||||||
|
let mut cosmic_theme = t.borrow_mut();
|
||||||
|
// only apply update if the theme is set to load a system theme
|
||||||
|
if matches!(cosmic_theme.theme_type, ThemeType::System(_)) {
|
||||||
|
cosmic_theme.set_theme(theme.theme_type);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iced::Command::none()
|
iced::Command::none()
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ pub mod message {
|
||||||
|
|
||||||
pub use self::core::Core;
|
pub use self::core::Core;
|
||||||
pub use self::settings::Settings;
|
pub use self::settings::Settings;
|
||||||
|
use crate::theme::THEME;
|
||||||
use crate::widget::nav_bar;
|
use crate::widget::nav_bar;
|
||||||
use crate::{Element, ElementExt};
|
use crate::{Element, ElementExt};
|
||||||
use apply::Apply;
|
use apply::Apply;
|
||||||
|
|
@ -58,7 +59,10 @@ pub fn run<App: Application>(settings: Settings, flags: App::Flags) -> iced::Res
|
||||||
core.set_scale_factor(settings.scale_factor);
|
core.set_scale_factor(settings.scale_factor);
|
||||||
core.set_window_width(settings.size.0);
|
core.set_window_width(settings.size.0);
|
||||||
core.set_window_height(settings.size.1);
|
core.set_window_height(settings.size.1);
|
||||||
core.theme = settings.theme;
|
THEME.with(move |t| {
|
||||||
|
let mut cosmic_theme = t.borrow_mut();
|
||||||
|
cosmic_theme.set_theme(settings.theme.theme_type);
|
||||||
|
});
|
||||||
|
|
||||||
let mut iced = iced::Settings::with_flags((core, flags));
|
let mut iced = iced::Settings::with_flags((core, flags));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
pub mod expander;
|
pub mod expander;
|
||||||
mod segmented_button;
|
mod segmented_button;
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
|
|
@ -64,6 +65,10 @@ lazy_static::lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub(crate) static THEME: RefCell<Theme> = RefCell::new(Theme { theme_type: ThemeType::Dark, layer: cosmic_theme::Layer::Background });
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
pub enum ThemeType {
|
pub enum ThemeType {
|
||||||
#[default]
|
#[default]
|
||||||
|
|
@ -72,6 +77,7 @@ pub enum ThemeType {
|
||||||
HighContrastDark,
|
HighContrastDark,
|
||||||
HighContrastLight,
|
HighContrastLight,
|
||||||
Custom(Arc<CosmicTheme>),
|
Custom(Arc<CosmicTheme>),
|
||||||
|
System(Arc<CosmicTheme>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
|
|
@ -88,7 +94,7 @@ impl Theme {
|
||||||
ThemeType::Light => &COSMIC_LIGHT,
|
ThemeType::Light => &COSMIC_LIGHT,
|
||||||
ThemeType::HighContrastDark => &COSMIC_HC_DARK,
|
ThemeType::HighContrastDark => &COSMIC_HC_DARK,
|
||||||
ThemeType::HighContrastLight => &COSMIC_HC_LIGHT,
|
ThemeType::HighContrastLight => &COSMIC_HC_LIGHT,
|
||||||
ThemeType::Custom(ref t) => t.as_ref(),
|
ThemeType::Custom(ref t) | ThemeType::System(ref t) => t.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,6 +138,14 @@ impl Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn system(theme: Arc<CosmicTheme>) -> Self {
|
||||||
|
Self {
|
||||||
|
theme_type: ThemeType::System(theme),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// get current container
|
/// get current container
|
||||||
/// can be used in a component that is intended to be a child of a `CosmicContainer`
|
/// can be used in a component that is intended to be a child of a `CosmicContainer`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -142,6 +156,11 @@ impl Theme {
|
||||||
cosmic_theme::Layer::Secondary => &self.cosmic().secondary,
|
cosmic_theme::Layer::Secondary => &self.cosmic().secondary,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set the theme
|
||||||
|
pub fn set_theme(&mut self, theme: ThemeType) {
|
||||||
|
self.theme_type = theme;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayeredTheme for Theme {
|
impl LayeredTheme for Theme {
|
||||||
|
|
@ -1215,7 +1234,7 @@ pub fn theme() -> Theme {
|
||||||
}
|
}
|
||||||
theme
|
theme
|
||||||
});
|
});
|
||||||
crate::theme::Theme::custom(Arc::new(t))
|
crate::theme::Theme::system(Arc::new(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
||||||
|
|
@ -1231,7 +1250,8 @@ pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
||||||
}
|
}
|
||||||
theme
|
theme
|
||||||
});
|
});
|
||||||
crate::theme::Theme::custom(Arc::new(theme))
|
|
||||||
|
crate::theme::Theme::system(Arc::new(theme))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue