mod default;
use std::default::Default;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::opts::Opts;
use default::DEFAULT_CONFIG_SETTINGS;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(transparent)]
pub struct PluginSettings(pub toml::value::Table);
impl Default for PluginSettings {
fn default() -> Self {
let mut google_cal: toml::value::Table = toml::map::Map::new();
let google_cal_accounts: Vec<String> = vec![];
let google_cal_accounts_val = toml::Value::try_from(google_cal_accounts)
.expect(
"Could not decode google_cal_accounts as toml Value, even though we should be able to."
);
google_cal.insert(String::from("accounts"), google_cal_accounts_val);
let x11_window_title_checker: toml::value::Table =
toml::map::Map::new();
let mut plugin_settings_table: toml::value::Table =
toml::map::Map::new();
plugin_settings_table.insert(
String::from("google_calendar"),
toml::Value::Table(google_cal),
);
plugin_settings_table.insert(
String::from("x11_window_title_checker"),
toml::Value::Table(x11_window_title_checker),
);
Self(plugin_settings_table)
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Settings {
#[serde(default = "default_break_duration_seconds")]
pub break_duration_seconds: u32,
#[serde(default = "default_seconds_between_breaks")]
pub seconds_between_breaks: u32,
#[serde(default = "default_clicks_to_end_break_early")]
pub clicks_to_end_break_early: u32,
#[serde(default = "default_idle_detection_seconds")]
pub idle_detection_seconds: u32,
#[serde(rename = "plugin")]
pub all_plugin_settings: PluginSettings,
}
const fn default_break_duration_seconds() -> u32 {
60 * 10
}
const fn default_seconds_between_breaks() -> u32 {
60 * 50
}
const fn default_clicks_to_end_break_early() -> u32 {
400
}
const fn default_idle_detection_seconds() -> u32 {
480
}
impl Default for Settings {
fn default() -> Self {
Self {
break_duration_seconds: default_break_duration_seconds(),
seconds_between_breaks: default_seconds_between_breaks(),
clicks_to_end_break_early: default_clicks_to_end_break_early(),
all_plugin_settings: PluginSettings::default(),
idle_detection_seconds: default_idle_detection_seconds(),
}
}
}
#[derive(Clone, Debug)]
pub struct Config {
pub file_path: PathBuf,
pub cache_dir: PathBuf,
pub settings: Settings,
}
impl Config {
pub fn load(opts: Opts) -> Result<Self, ()> {
let config_file_name = "config.toml";
let config_file_path = match opts.conf_dir {
Some(conf_dir) => {
std::fs::create_dir_all(&conf_dir).map_err(|_io_err| ())?;
conf_dir.join(config_file_name)
}
None => {
let xdg_base_dir =
xdg::BaseDirectories::with_prefix("break-time")
.map_err(|_xdg_base_dir_err| ())?;
xdg_base_dir
.place_config_file(config_file_name)
.map_err(|_io_err| ())?
}
};
let cache_dir = match opts.cache_dir {
Some(cache_dir) => cache_dir,
None => {
let xdg_base_dir =
xdg::BaseDirectories::with_prefix("break-time")
.map_err(|_xdg_base_dir_err| ())?;
xdg_base_dir.get_cache_home()
}
};
std::fs::create_dir_all(&cache_dir).map_err(|_io_err| ())?;
let res_config_file = std::fs::read_to_string(&config_file_path);
let settings = match res_config_file {
Err(_) => {
let write_res =
std::fs::write(&config_file_path, DEFAULT_CONFIG_SETTINGS);
match write_res {
Ok(()) => (),
Err(err) =>
panic!(
"Couldn't write a new config file at {:?} because of the following error: {}",
config_file_path,
err
),
}
Settings::default()
}
Ok(config_file) => {
let res_settings = toml::from_str(&config_file);
match res_settings {
Err(err) => {
panic!(
"Can't parse config file at {:?} because of the following error: {}",
config_file_path,
err
)
}
Ok(settings) => settings,
}
}
};
let config = Self {
file_path: config_file_path,
cache_dir,
settings,
};
Ok(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_settings_constant_is_same_as_default_impl() {
let settings_from_default_instance: Settings = Default::default();
let settings_from_default_const: Settings =
toml::from_str(DEFAULT_CONFIG_SETTINGS).unwrap();
assert_eq!(settings_from_default_instance, settings_from_default_const);
}
}