diff options
-rw-r--r-- | src/utils.rs | 123 |
1 files changed, 90 insertions, 33 deletions
diff --git a/src/utils.rs b/src/utils.rs index b45bbf3..c579241 100644 --- a/src/utils.rs +++ b/src/utils.rs | |||
@@ -1,62 +1,119 @@ | |||
1 | use cursive::theme::{BaseColor, Color}; | 1 | use cursive::theme::{BaseColor, Color}; |
2 | use directories::ProjectDirs; | 2 | use directories::ProjectDirs; |
3 | use serde::Deserialize; | 3 | use serde::{Deserialize, Serialize}; |
4 | |||
4 | use std; | 5 | use std; |
5 | use std::fs; | 6 | use std::default::Default; |
6 | use std::fs::File; | 7 | use std::fs::{self, File, OpenOptions}; |
7 | use std::io::Read; | 8 | use std::io::{Read, Write}; |
8 | use std::path::PathBuf; | 9 | use std::path::PathBuf; |
9 | 10 | ||
10 | #[derive(Deserialize)] | 11 | pub const VIEW_WIDTH: usize = 25; |
11 | #[serde(default = "default_config")] | 12 | pub const VIEW_HEIGHT: usize = 8; |
12 | pub struct AppConfig { | 13 | pub const GRID_WIDTH: usize = 3; |
14 | |||
15 | #[derive(Serialize, Deserialize)] | ||
16 | pub struct Characters { | ||
17 | #[serde(default = "base_char")] | ||
13 | pub true_chr: char, | 18 | pub true_chr: char, |
19 | #[serde(default = "base_char")] | ||
14 | pub false_chr: char, | 20 | pub false_chr: char, |
21 | #[serde(default = "base_char")] | ||
15 | pub future_chr: char, | 22 | pub future_chr: char, |
23 | } | ||
16 | 24 | ||
17 | // view dimensions | 25 | fn base_char() -> char { |
18 | pub view_width: usize, | 26 | '·' |
19 | pub view_height: usize, | 27 | } |
20 | 28 | ||
21 | // app dimensions | 29 | impl Default for Characters { |
22 | pub grid_width: usize, | 30 | fn default() -> Self { |
31 | Characters { | ||
32 | true_chr: '·', | ||
33 | false_chr: '·', | ||
34 | future_chr: '·', | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | #[derive(Serialize, Deserialize)] | ||
40 | pub struct Colors { | ||
41 | #[serde(default = "cyan")] | ||
42 | pub reached: String, | ||
43 | #[serde(default = "magenta")] | ||
44 | pub todo: String, | ||
45 | #[serde(default = "light_black")] | ||
46 | pub inactive: String, | ||
47 | } | ||
48 | |||
49 | fn cyan() -> String { | ||
50 | "cyan".into() | ||
51 | } | ||
52 | fn magenta() -> String { | ||
53 | "magenta".into() | ||
54 | } | ||
55 | fn light_black() -> String { | ||
56 | "light_black".into() | ||
57 | } | ||
58 | |||
59 | impl Default for Colors { | ||
60 | fn default() -> Self { | ||
61 | Colors { | ||
62 | reached: cyan(), | ||
63 | todo: magenta(), | ||
64 | inactive: light_black(), | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | #[derive(Serialize, Deserialize)] | ||
70 | pub struct AppConfig { | ||
71 | #[serde(default)] | ||
72 | pub look: Characters, | ||
73 | |||
74 | #[serde(default)] | ||
75 | pub colors: Colors, | ||
76 | } | ||
77 | |||
78 | impl Default for AppConfig { | ||
79 | fn default() -> Self { | ||
80 | AppConfig { | ||
81 | look: Default::default(), | ||
82 | colors: Default::default(), | ||
83 | } | ||
84 | } | ||
23 | } | 85 | } |
24 | 86 | ||
25 | impl AppConfig { | 87 | impl AppConfig { |
26 | // TODO: implement string parsing from config.json | 88 | // TODO: implement string parsing from config.json |
27 | pub fn reached_color(&self) -> Color { | 89 | pub fn reached_color(&self) -> Color { |
28 | return Color::Dark(BaseColor::Cyan); | 90 | return Color::parse(&self.colors.reached).unwrap_or(Color::Dark(BaseColor::Cyan)); |
29 | } | 91 | } |
30 | pub fn todo_color(&self) -> Color { | 92 | pub fn todo_color(&self) -> Color { |
31 | return Color::Dark(BaseColor::Magenta); | 93 | return Color::parse(&self.colors.todo).unwrap_or(Color::Dark(BaseColor::Magenta)); |
32 | } | 94 | } |
33 | pub fn future_color(&self) -> Color { | 95 | pub fn inactive_color(&self) -> Color { |
34 | return Color::Dark(BaseColor::Magenta); | 96 | return Color::parse(&self.colors.inactive).unwrap_or(Color::Light(BaseColor::Black)); |
35 | } | 97 | } |
36 | } | 98 | } |
37 | 99 | ||
38 | pub fn load_configuration_file() -> AppConfig { | 100 | pub fn load_configuration_file() -> AppConfig { |
39 | let config_f = config_file(); | 101 | let cf = config_file(); |
40 | if let Ok(ref mut f) = File::open(config_f) { | 102 | if let Ok(ref mut f) = File::open(&cf) { |
41 | let mut j = String::new(); | 103 | let mut j = String::new(); |
42 | f.read_to_string(&mut j); | 104 | f.read_to_string(&mut j); |
43 | return serde_json::from_str(&j).unwrap(); | 105 | return toml::from_str(&j).unwrap(); |
44 | } else { | 106 | } else { |
45 | return default_config(); | 107 | if let Ok(dc) = toml::to_string(&AppConfig::default()) { |
108 | match OpenOptions::new().create(true).write(true).open(&cf) { | ||
109 | Ok(ref mut file) => file.write(dc.as_bytes()).unwrap(), | ||
110 | Err(_) => 0, | ||
111 | }; | ||
112 | } | ||
113 | return Default::default(); | ||
46 | } | 114 | } |
47 | } | 115 | } |
48 | 116 | ||
49 | pub fn default_config() -> AppConfig { | ||
50 | return AppConfig { | ||
51 | true_chr: '·', | ||
52 | false_chr: '·', | ||
53 | future_chr: '·', | ||
54 | view_width: 25, | ||
55 | view_height: 8, | ||
56 | grid_width: 3, | ||
57 | }; | ||
58 | } | ||
59 | |||
60 | fn project_dirs() -> ProjectDirs { | 117 | fn project_dirs() -> ProjectDirs { |
61 | ProjectDirs::from("rs", "nerdypepper", "dijo") | 118 | ProjectDirs::from("rs", "nerdypepper", "dijo") |
62 | .unwrap_or_else(|| panic!("Invalid home directory!")) | 119 | .unwrap_or_else(|| panic!("Invalid home directory!")) |
@@ -64,9 +121,9 @@ fn project_dirs() -> ProjectDirs { | |||
64 | 121 | ||
65 | pub fn config_file() -> PathBuf { | 122 | pub fn config_file() -> PathBuf { |
66 | let proj_dirs = project_dirs(); | 123 | let proj_dirs = project_dirs(); |
67 | let mut data_file = PathBuf::from(proj_dirs.data_dir()); | 124 | let mut data_file = PathBuf::from(proj_dirs.config_dir()); |
68 | fs::create_dir_all(&data_file); | 125 | fs::create_dir_all(&data_file); |
69 | data_file.push("config.json"); | 126 | data_file.push("config.toml"); |
70 | return data_file; | 127 | return data_file; |
71 | } | 128 | } |
72 | 129 | ||