diff --git a/Cargo.lock b/Cargo.lock index 8675925..34202fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2281,6 +2281,7 @@ version = "0.1.0" dependencies = [ "semver", "serde", + "serde_json", "thiserror 2.0.18", "toml 1.1.2+spec-1.1.0", "url", diff --git a/crates/ely_domain/Cargo.toml b/crates/ely_domain/Cargo.toml index c63251f..e4230c0 100644 --- a/crates/ely_domain/Cargo.toml +++ b/crates/ely_domain/Cargo.toml @@ -13,5 +13,8 @@ toml.workspace = true url.workspace = true uuid.workspace = true +[dev-dependencies] +serde_json.workspace = true + [lints] workspace = true diff --git a/crates/ely_domain/src/appearance.rs b/crates/ely_domain/src/appearance.rs new file mode 100644 index 0000000..341805a --- /dev/null +++ b/crates/ely_domain/src/appearance.rs @@ -0,0 +1,105 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum WallpaperTheme { + #[default] + Dawn, + Violet, + Mint, + Slate, +} + +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum ThemeMode { + #[default] + System, + Light, + Dark, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] +pub struct AppearanceSettings { + wallpaper: WallpaperTheme, + theme_mode: ThemeMode, + reduce_motion: bool, +} + +impl Default for AppearanceSettings { + fn default() -> Self { + Self { + wallpaper: WallpaperTheme::default(), + theme_mode: ThemeMode::default(), + reduce_motion: false, + } + } +} + +impl AppearanceSettings { + pub fn wallpaper(&self) -> WallpaperTheme { + self.wallpaper + } + + pub fn theme_mode(&self) -> ThemeMode { + self.theme_mode + } + + pub fn reduce_motion(&self) -> bool { + self.reduce_motion + } + + pub fn set_wallpaper(&mut self, wallpaper: WallpaperTheme) { + self.wallpaper = wallpaper; + } + + pub fn set_theme_mode(&mut self, theme_mode: ThemeMode) { + self.theme_mode = theme_mode; + } + + pub fn set_reduce_motion(&mut self, reduce_motion: bool) { + self.reduce_motion = reduce_motion; + } +} + +#[cfg(test)] +mod tests { + use super::{AppearanceSettings, ThemeMode, WallpaperTheme}; + + #[test] + fn default_settings_use_dawn_and_system_mode() { + let settings = AppearanceSettings::default(); + assert_eq!(settings.wallpaper(), WallpaperTheme::Dawn); + assert_eq!(settings.theme_mode(), ThemeMode::System); + assert!(!settings.reduce_motion()); + } + + #[test] + fn setters_update_each_field_independently() { + let mut settings = AppearanceSettings::default(); + + settings.set_wallpaper(WallpaperTheme::Violet); + settings.set_theme_mode(ThemeMode::Dark); + settings.set_reduce_motion(true); + + assert_eq!(settings.wallpaper(), WallpaperTheme::Violet); + assert_eq!(settings.theme_mode(), ThemeMode::Dark); + assert!(settings.reduce_motion()); + } + + #[test] + fn json_round_trip_preserves_kebab_case_variants() { + let settings = AppearanceSettings { + wallpaper: WallpaperTheme::Mint, + theme_mode: ThemeMode::Light, + reduce_motion: true, + }; + + let json = serde_json::to_string(&settings).unwrap(); + assert!(json.contains("\"wallpaper\":\"mint\"")); + assert!(json.contains("\"theme_mode\":\"light\"")); + + let restored: AppearanceSettings = serde_json::from_str(&json).unwrap(); + assert_eq!(restored, settings); + } +} diff --git a/crates/ely_domain/src/lib.rs b/crates/ely_domain/src/lib.rs index 85cf812..9c9c2fd 100644 --- a/crates/ely_domain/src/lib.rs +++ b/crates/ely_domain/src/lib.rs @@ -1,3 +1,4 @@ +mod appearance; mod archive; mod bookmark; mod command; @@ -23,6 +24,7 @@ mod tab_group; mod update; mod url_text; +pub use appearance::{AppearanceSettings, ThemeMode, WallpaperTheme}; pub use archive::{ArchiveSource, ArchivedTab}; pub use bookmark::BookmarkEntry; pub use command::{CommandIntent, CommandScope};