vizia_core/
environment.rs1use crate::prelude::*;
3
4use unic_langid::LanguageIdentifier;
5use vizia_derive::Lens;
6use web_time::Duration;
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
10pub enum ThemeMode {
11 DarkMode,
13 #[default]
15 LightMode,
16}
17
18use crate::{context::EventContext, events::Event};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum AppTheme {
23 System,
26 BuiltIn(ThemeMode),
28 }
30
31#[derive(Lens)]
33pub struct Theme {
34 pub app_theme: AppTheme,
36 pub sys_theme: Option<ThemeMode>,
38}
39
40impl Default for Theme {
41 fn default() -> Self {
42 Self { app_theme: AppTheme::BuiltIn(ThemeMode::LightMode), sys_theme: None }
43 }
44}
45
46impl Theme {
47 pub fn get_current_theme(&self) -> ThemeMode {
49 match self.app_theme {
50 AppTheme::System => self.sys_theme.unwrap_or_default(),
51 AppTheme::BuiltIn(theme) => theme,
52 }
53 }
54}
55
56#[derive(Lens)]
58pub struct Environment {
59 pub locale: LanguageIdentifier,
61 pub theme: Theme,
63 pub(crate) caret_timer: Timer,
65}
66
67impl Environment {
68 pub(crate) fn new(cx: &mut Context) -> Self {
69 let locale = sys_locale::get_locale().and_then(|l| l.parse().ok()).unwrap_or_default();
70 let caret_timer = cx.add_timer(Duration::from_millis(530), None, |cx, action| {
71 if matches!(action, TimerAction::Tick(_)) {
72 cx.emit(TextEvent::ToggleCaret);
73 }
74 });
75 Self { locale, theme: Theme::default(), caret_timer }
76 }
77}
78
79pub enum EnvironmentEvent {
81 SetLocale(LanguageIdentifier),
83 SetThemeMode(AppTheme),
86 UseSystemLocale,
88 ToggleThemeMode,
90}
91
92impl Model for Environment {
93 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
94 event.take(|event, _| match event {
95 EnvironmentEvent::SetLocale(locale) => {
96 self.locale = locale;
97 }
98
99 EnvironmentEvent::SetThemeMode(theme) => {
100 theme.clone_into(&mut self.theme.app_theme);
101
102 cx.set_theme_mode(self.theme.get_current_theme());
103 cx.reload_styles().unwrap();
104 }
105
106 EnvironmentEvent::UseSystemLocale => {
107 self.locale =
108 sys_locale::get_locale().map(|l| l.parse().unwrap()).unwrap_or_default();
109 }
110
111 EnvironmentEvent::ToggleThemeMode => {
112 let theme_mode = match self.theme.get_current_theme() {
113 ThemeMode::DarkMode => ThemeMode::LightMode,
114 ThemeMode::LightMode => ThemeMode::DarkMode,
115 };
116
117 self.theme.app_theme = AppTheme::BuiltIn(theme_mode);
118
119 cx.set_theme_mode(theme_mode);
120 cx.reload_styles().unwrap();
121 }
122 });
123
124 event.map(|event, _| match event {
125 WindowEvent::ThemeChanged(theme) => {
126 self.theme.sys_theme = Some(*theme);
127 if self.theme.app_theme == AppTheme::System {
128 cx.set_theme_mode(*theme);
129 cx.reload_styles().unwrap();
130 }
131 }
132 _ => (),
133 })
134 }
135}