Skip to main content

aaai_core/profile/
prefs.rs

1//! User preferences — persisted to `~/.aaai/prefs.yaml`.
2//!
3//! Currently stores the GUI theme selection.  Future preferences
4//! (font size, language override, etc.) can be added here without
5//! breaking the format because unknown YAML keys are ignored by serde.
6
7use serde::{Deserialize, Serialize};
8use std::path::PathBuf;
9
10/// GUI colour theme.
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Theme {
14    /// iced built-in light palette (default).
15    #[default]
16    Light,
17    /// iced built-in dark palette.
18    Dark,
19    /// System preference (not yet implemented — falls back to Light).
20    System,
21}
22
23impl std::fmt::Display for Theme {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        match self {
26            Theme::Light  => write!(f, "Light"),
27            Theme::Dark   => write!(f, "Dark"),
28            Theme::System => write!(f, "System"),
29        }
30    }
31}
32
33/// Persisted user preferences.
34#[derive(Debug, Clone, Default, Serialize, Deserialize)]
35pub struct UserPrefs {
36    /// Selected GUI theme.
37    #[serde(default)]
38    pub theme: Theme,
39}
40
41impl UserPrefs {
42    fn path() -> anyhow::Result<PathBuf> {
43        let base = dirs::home_dir()
44            .ok_or_else(|| anyhow::anyhow!("Cannot determine home directory"))?
45            .join(".aaai");
46        std::fs::create_dir_all(&base)?;
47        Ok(base.join("prefs.yaml"))
48    }
49
50    /// Load from `~/.aaai/prefs.yaml`.  Returns defaults if the file is absent.
51    pub fn load() -> Self {
52        match Self::path().and_then(|p| {
53            if !p.exists() { return Ok(Self::default()); }
54            let text = std::fs::read_to_string(&p)?;
55            serde_yaml::from_str(&text).map_err(|e| anyhow::anyhow!(e))
56        }) {
57            Ok(prefs) => prefs,
58            Err(e) => {
59                log::warn!("Could not load prefs: {e}");
60                Self::default()
61            }
62        }
63    }
64
65    /// Save to `~/.aaai/prefs.yaml`.
66    pub fn save(&self) {
67        if let Err(e) = Self::path().and_then(|p| {
68            let yaml = serde_yaml::to_string(self).map_err(|e| anyhow::anyhow!(e))?;
69            std::fs::write(&p, yaml)?;
70            Ok(())
71        }) {
72            log::warn!("Could not save prefs: {e}");
73        }
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn round_trip_yaml() {
83        let prefs = UserPrefs { theme: Theme::Dark };
84        let yaml = serde_yaml::to_string(&prefs).unwrap();
85        let restored: UserPrefs = serde_yaml::from_str(&yaml).unwrap();
86        assert_eq!(restored.theme, Theme::Dark);
87    }
88
89    #[test]
90    fn default_is_light() {
91        assert_eq!(UserPrefs::default().theme, Theme::Light);
92    }
93
94    #[test]
95    fn display_names() {
96        assert_eq!(Theme::Light.to_string(), "Light");
97        assert_eq!(Theme::Dark.to_string(), "Dark");
98    }
99}