use crate::{
context::{Context, EmitContext},
events::{Timer, TimerAction},
model::Model,
views::TextEvent,
window::WindowEvent,
};
use unic_langid::LanguageIdentifier;
use vizia_derive::Lens;
use web_time::Duration;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ThemeMode {
DarkMode,
#[default]
LightMode,
}
use crate::{context::EventContext, events::Event};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AppTheme {
System,
BuiltIn(ThemeMode),
}
#[derive(Lens)]
pub struct Theme {
pub app_theme: AppTheme,
pub sys_theme: Option<ThemeMode>,
}
impl Default for Theme {
fn default() -> Self {
Self { app_theme: AppTheme::BuiltIn(ThemeMode::LightMode), sys_theme: None }
}
}
impl Theme {
pub fn get_current_theme(&self) -> ThemeMode {
match self.app_theme {
AppTheme::System => self.sys_theme.unwrap_or_default(),
AppTheme::BuiltIn(theme) => theme,
}
}
}
#[derive(Lens)]
pub struct Environment {
pub locale: LanguageIdentifier,
pub theme: Theme,
pub(crate) caret_timer: Timer,
}
impl Environment {
pub fn new(cx: &mut Context) -> Self {
let locale = sys_locale::get_locale().and_then(|l| l.parse().ok()).unwrap_or_default();
let caret_timer = cx.add_timer(Duration::from_millis(530), None, |cx, action| {
if matches!(action, TimerAction::Tick(_)) {
cx.emit(TextEvent::ToggleCaret);
}
});
Self { locale, theme: Theme::default(), caret_timer }
}
}
pub enum EnvironmentEvent {
SetLocale(LanguageIdentifier),
SetThemeMode(AppTheme),
UseSystemLocale,
ToggleThemeMode,
}
impl Model for Environment {
fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
event.take(|event, _| match event {
EnvironmentEvent::SetLocale(locale) => {
self.locale = locale;
}
EnvironmentEvent::SetThemeMode(theme) => {
theme.clone_into(&mut self.theme.app_theme);
cx.set_theme_mode(self.theme.get_current_theme());
cx.reload_styles().unwrap();
}
EnvironmentEvent::UseSystemLocale => {
self.locale =
sys_locale::get_locale().map(|l| l.parse().unwrap()).unwrap_or_default();
}
EnvironmentEvent::ToggleThemeMode => {
let theme_mode = match self.theme.get_current_theme() {
ThemeMode::DarkMode => ThemeMode::LightMode,
ThemeMode::LightMode => ThemeMode::DarkMode,
};
self.theme.app_theme = AppTheme::BuiltIn(theme_mode);
cx.set_theme_mode(theme_mode);
cx.reload_styles().unwrap();
}
});
event.map(|event, _| match event {
WindowEvent::ThemeChanged(theme) => {
self.theme.sys_theme = Some(*theme);
if self.theme.app_theme == AppTheme::System {
cx.set_theme_mode(*theme);
cx.reload_styles().unwrap();
}
}
_ => (),
})
}
}