use crate::{ cass::{Cassiopeia, TimeFile}, Address, Client, Io, }; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; use std::{ fs::File, io::{Read, Write}, path::PathBuf, }; use xdg::BaseDirectories as BaseDirs; #[derive(Debug)] pub struct Meta { clients: BTreeMap, pub dir: BaseDirs, pub invoice_dir: PathBuf, pub template: Option, pub revisioning: bool, /// Optional current timefile path pub timefile: Option, pub project_id: Option, } /// #[derive(Debug, Serialize, Deserialize)] pub struct Config { pub revisioning: bool, pub invoice_dir: PathBuf, } impl Meta { pub fn new(dir: BaseDirs) -> Self { // Get the path to the configuration, and make sure a default // configuration is created if none exists yet. let path = dir.find_config_file("config.yml").unwrap_or_else(|| { let path = dir.place_config_file("config.yml").unwrap(); let mut cfg = File::create(path.clone()).unwrap(); let buf = "revisioning: true invoicedir: $HOME/.local/k-office/"; cfg.write_all(buf.as_bytes()).unwrap(); path }); let mut cfg = File::open(path).unwrap(); let mut buf = String::new(); cfg.read_to_string(&mut buf).unwrap(); let yml = Config::from_yaml(buf); Self { dir, clients: BTreeMap::new(), invoice_dir: yml.invoice_dir, template: None, revisioning: yml.revisioning, timefile: None, project_id: None, } } pub fn load_timefile(&mut self, path: &str) { let timefile = Cassiopeia::load(path) .expect("Timefile not found") .timefile(); self.timefile = Some(timefile); } pub fn client_mut(&mut self, name: &str) -> Option<&mut Client> { self.clients.get_mut(name) } pub fn new_client(&mut self, name: &str, address: Address) { self.clients.insert( name.to_string(), Client { name: name.to_string(), address, last_project: None, }, ); } } /// Initialise a k-office application state pub fn initialise() -> Meta { let dir = BaseDirs::with_prefix("k-koffice").unwrap(); dir.create_config_directory("") .expect("Couldn't create config directory"); Meta::new(dir) }