mod icon; mod percent_value; mod ui; mod window; pub use icon::IconConfig; pub use percent_value::PercentValueConfig; pub use ui::UiConfig; pub use window::WindowConfig; use dirs::config_dir; use serde::Deserialize; use std::path::PathBuf; use thiserror::Error; /// Errors returned by Popcorn configuration loading. #[derive(Debug, Error)] pub enum ConfigError { #[error("I/O error: {0}")] Io(std::io::Error), #[error("TOML parse error: {0}")] Toml(toml::de::Error), } /// Complete Popcorn configuration. /// Combines window, UI, percent text, and icon styling. #[derive(Debug, Deserialize, Default)] pub struct PopcornConfig { #[serde(default)] pub window: WindowConfig, #[serde(default)] pub ui: UiConfig, #[serde(default)] pub percent_value: PercentValueConfig, #[serde(default)] pub icon: IconConfig, } impl PopcornConfig { /// Load the Popcorn configuration from: /// `~/.config/candywidgets/popcorn/config.toml` /// /// # Errors /// - `ConfigError::Io` if the file cannot be read /// - `ConfigError::Toml` if the syntax is invalid pub fn load() -> Result { let path = config_dir() .unwrap_or_else(|| PathBuf::from(".")) .join("candywidgets/popcorn/config.toml"); let text = std::fs::read_to_string(path).map_err(ConfigError::Io)?; let cfg: PopcornConfig = toml::from_str(&text).map_err(ConfigError::Toml)?; Ok(cfg) } /// Load configuration.\ /// If the file is missing or broken, fall back to built-in defaults. #[must_use] pub fn load_or_default() -> Self { Self::load().unwrap_or_default() } }