tomodoro 0.4.1

Terminal Pomodoro timer with animated backgrounds
use serde::Deserialize;

#[derive(Deserialize)]
#[serde(default)]
pub struct AppConfig {
    pub theme: usize,
    pub render_mode: String,
    pub focus_theme: Option<usize>,
    pub break_theme: Option<usize>,
    pub focus: u64,
    pub short_break: u64,
    pub long_break: u64,
    pub volume: f32,
    pub long_break_interval: u32,
    pub auto_start: bool,
    pub countdown_beeps: u64,
    pub notifications: bool,
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            theme: 0,
            render_mode: "half".into(),
            focus_theme: None,
            break_theme: None,
            focus: 25,
            short_break: 5,
            long_break: 15,
            volume: 1.0,
            long_break_interval: 4,
            auto_start: false,
            countdown_beeps: 5,
            notifications: false,
        }
    }
}

const DEFAULT_CONFIG: &str = r#"# tomodoro configuration
# All values shown are defaults. Uncomment and edit to customise.

# Starting animation theme (0–7): waves, rain, leaves, stars, fire, aurora, blossom, sunset
# theme = 0

# Per-phase themes — overrides `theme` for each phase independently
# focus_theme = 0
# break_theme = 0

# Render mode: "half", "quarter", or "braille"
# render_mode = "half"

# Default durations in minutes
# focus = 25
# short_break = 5
# long_break = 15

# Sessions before a long break
# long_break_interval = 4

# Starting volume (0.0–1.0)
# volume = 1.0

# Skip the startup screen and begin immediately
# auto_start = false

# Countdown beep seconds at end of each break
# countdown_beeps = 5

# Desktop notifications via notify-send on phase end
# notifications = false
"#;

impl AppConfig {
    pub fn load() -> Self {
        let path = config_path();
        if !path.exists() {
            if let Some(dir) = path.parent() {
                let _ = std::fs::create_dir_all(dir);
            }
            let _ = std::fs::write(&path, DEFAULT_CONFIG);
            return Self::default();
        }
        let Ok(text) = std::fs::read_to_string(&path) else { return Self::default() };
        toml::from_str(&text).unwrap_or_else(|e| {
            eprintln!("tomodoro: config parse error ({}): {}", path.display(), e);
            Self::default()
        })
    }
}

fn config_path() -> std::path::PathBuf {
    let home = std::env::var("HOME").unwrap_or_else(|_| ".".into());
    std::path::PathBuf::from(home).join(".config/tomodoro/config.toml")
}