1//! A model for system specific state which can be accessed by any model or view.
2use crate::prelude::*;
34use unic_langid::LanguageIdentifier;
5use vizia_derive::Lens;
6use web_time::Duration;
78/// And enum which represents the current built-in theme mode.
9#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
10pub enum ThemeMode {
11/// The built-in vizia dark theme.
12DarkMode,
13/// The built-in vizia light theme.
14#[default]
15LightMode,
16}
1718use crate::{context::EventContext, events::Event};
1920/// Represents the theme used by the application.
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum AppTheme {
23/// System theme, if we choose this as our theme vizia
24 /// will follow system theme in supported platforms.
25System,
26/// Built-in vizia themes.
27BuiltIn(ThemeMode),
28// Custom(String),
29}
3031/// Represents the theme used by the application.
32#[derive(Lens)]
33pub struct Theme {
34/// The current application theme
35pub app_theme: AppTheme,
36/// The current system theme
37pub sys_theme: Option<ThemeMode>,
38}
3940impl Default for Theme {
41fn default() -> Self {
42Self { app_theme: AppTheme::BuiltIn(ThemeMode::LightMode), sys_theme: None }
43 }
44}
4546impl Theme {
47/// Returns the current theme of the application.
48pub fn get_current_theme(&self) -> ThemeMode {
49match self.app_theme {
50 AppTheme::System => self.sys_theme.unwrap_or_default(),
51 AppTheme::BuiltIn(theme) => theme,
52 }
53 }
54}
5556/// A model for system specific state which can be accessed by any model or view.
57#[derive(Lens)]
58pub struct Environment {
59/// The locale used for localization.
60pub locale: LanguageIdentifier,
61/// Current application and system theme.
62pub theme: Theme,
63/// The timer used to blink the caret of a textbox.
64pub(crate) caret_timer: Timer,
65}
6667impl Environment {
68pub(crate) fn new(cx: &mut Context) -> Self {
69let locale = sys_locale::get_locale().and_then(|l| l.parse().ok()).unwrap_or_default();
70let caret_timer = cx.add_timer(Duration::from_millis(530), None, |cx, action| {
71if matches!(action, TimerAction::Tick(_)) {
72 cx.emit(TextEvent::ToggleCaret);
73 }
74 });
75Self { locale, theme: Theme::default(), caret_timer }
76 }
77}
7879/// Events for setting the state in the [Environment].
80pub enum EnvironmentEvent {
81/// Set the locale used for the whole application.
82SetLocale(LanguageIdentifier),
83/// Set the default theme mode.
84// TODO: add SetSysTheme event when the winit `set_theme` fixed.
85SetThemeMode(AppTheme),
86/// Reset the locale to use the system provided locale.
87UseSystemLocale,
88/// Alternate between dark and light theme modes.
89ToggleThemeMode,
90}
9192impl Model for Environment {
93fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
94 event.take(|event, _| match event {
95 EnvironmentEvent::SetLocale(locale) => {
96self.locale = locale;
97 }
9899 EnvironmentEvent::SetThemeMode(theme) => {
100 theme.clone_into(&mut self.theme.app_theme);
101102 cx.set_theme_mode(self.theme.get_current_theme());
103 cx.reload_styles().unwrap();
104 }
105106 EnvironmentEvent::UseSystemLocale => {
107self.locale =
108 sys_locale::get_locale().map(|l| l.parse().unwrap()).unwrap_or_default();
109 }
110111 EnvironmentEvent::ToggleThemeMode => {
112let theme_mode = match self.theme.get_current_theme() {
113 ThemeMode::DarkMode => ThemeMode::LightMode,
114 ThemeMode::LightMode => ThemeMode::DarkMode,
115 };
116117self.theme.app_theme = AppTheme::BuiltIn(theme_mode);
118119 cx.set_theme_mode(theme_mode);
120 cx.reload_styles().unwrap();
121 }
122 });
123124 event.map(|event, _| match event {
125 WindowEvent::ThemeChanged(theme) => {
126self.theme.sys_theme = Some(*theme);
127if self.theme.app_theme == AppTheme::System {
128 cx.set_theme_mode(*theme);
129 cx.reload_styles().unwrap();
130 }
131 }
132_ => (),
133 })
134 }
135}