use std::{fmt::Display, path::PathBuf}; use anyhow::Result; use log::{debug, error, trace}; use serde::{Deserialize, Serialize}; use tauri::api::path::config_dir; #[derive(Debug, Clone, Default, Deserialize, Serialize)] pub struct Config { #[serde(default)] pub background_color: BGColor, #[serde(default = "default_interval")] pub blink_interval: u64, #[serde(default = "default_sens")] pub mic_sens: f32, } #[inline(always)] fn default_interval() -> u64 { 1500 } #[inline(always)] fn default_sens() -> f32 { 1.0 } #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum BGColor { Transparent, Green, Blue, Pink, Custom(String), } impl Default for BGColor { fn default() -> Self { Self::Transparent } } impl Display for BGColor { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Custom(c) => { write!(f, "{}", c) } _ => { write!(f, "{}", self.to_string().to_lowercase()) } } } } #[inline] pub fn get_config_dir() -> Option { Some(config_dir()?.join("cathode")) } pub fn load_config() -> Config { if let Some(path) = get_config_dir() { use std::fs; if !path.exists() { if let Err(e) = fs::create_dir_all(&path) { debug!("{:?}", e); error!("Failed to create config directory"); error!("{}", e); } else { debug!("Created config dir at {}", path.display()) } Config::default() } else { let raw = fs::read_to_string(path.join("config.toml")).unwrap_or_else(|f| { error!("Failed to load config file: {}", f); String::new() }); trace!("Using config: {}", raw); match toml::from_str::(&raw) { Ok(c) => { trace!("parsed config: {:#?}", c); c } Err(e) => { error!("Unable to parse config file: {}", e); Config::default() } } } } else { debug!("Using default config"); Config::default() } } pub fn save_config(config: &Config) -> Result<()> { let raw = toml::to_string_pretty(config)?; if let Some(dir) = get_config_dir() { use std::fs; debug!("Writing config"); trace!("Config: {}", raw); let path = dir.join("config.toml"); fs::write(&path, raw)?; } Ok(()) }