aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs75
1 files changed, 63 insertions, 12 deletions
diff --git a/src/app.rs b/src/app.rs
index 57c489f..276b7ff 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -7,7 +7,7 @@ use cursive::event::{Event, EventResult, Key};
7use cursive::view::View; 7use cursive::view::View;
8use cursive::{Printer, Vec2}; 8use cursive::{Printer, Vec2};
9 9
10use chrono::NaiveDate; 10use chrono::{Local, NaiveDate};
11 11
12use crate::habit::{Bit, Count, Habit, HabitWrapper}; 12use crate::habit::{Bit, Count, Habit, HabitWrapper};
13use crate::Command; 13use crate::Command;
@@ -28,6 +28,8 @@ impl std::default::Default for ViewMode {
28 } 28 }
29} 29}
30 30
31struct StatusLine(String, String);
32
31#[derive(Serialize, Deserialize)] 33#[derive(Serialize, Deserialize)]
32pub struct App { 34pub struct App {
33 habits: Vec<Box<dyn HabitWrapper>>, 35 habits: Vec<Box<dyn HabitWrapper>>,
@@ -37,6 +39,9 @@ pub struct App {
37 39
38 #[serde(skip)] 40 #[serde(skip)]
39 view_mode: ViewMode, 41 view_mode: ViewMode,
42
43 #[serde(skip)]
44 view_month_offset: u32,
40} 45}
41 46
42impl App { 47impl App {
@@ -45,6 +50,7 @@ impl App {
45 habits: vec![], 50 habits: vec![],
46 view_mode: ViewMode::Day, 51 view_mode: ViewMode::Day,
47 focus: 0, 52 focus: 0,
53 view_month_offset: 0,
48 }; 54 };
49 } 55 }
50 56
@@ -58,6 +64,22 @@ impl App {
58 } 64 }
59 } 65 }
60 66
67 pub fn sift_backward(&mut self) {
68 self.view_month_offset += 1;
69 for v in self.habits.iter_mut() {
70 v.set_view_month_offset(self.view_month_offset);
71 }
72 }
73
74 pub fn sift_forward(&mut self) {
75 if self.view_month_offset > 0 {
76 self.view_month_offset -= 1;
77 for v in self.habits.iter_mut() {
78 v.set_view_month_offset(self.view_month_offset);
79 }
80 }
81 }
82
61 fn set_focus(&mut self, d: Absolute) { 83 fn set_focus(&mut self, d: Absolute) {
62 let grid_width = CONFIGURATION.grid_width; 84 let grid_width = CONFIGURATION.grid_width;
63 match d { 85 match d {
@@ -89,13 +111,30 @@ impl App {
89 } 111 }
90 } 112 }
91 113
92 fn status(&self) -> String { 114 fn status(&self) -> StatusLine {
93 let today = chrono::Local::now().naive_utc().date(); 115 let today = chrono::Local::now().naive_utc().date();
94 let remaining = self.habits.iter().map(|h| h.remaining(today)).sum::<u32>(); 116 let remaining = self.habits.iter().map(|h| h.remaining(today)).sum::<u32>();
95 let total = self.habits.iter().map(|h| h.total()).sum::<u32>(); 117 let total = self.habits.iter().map(|h| h.total()).sum::<u32>();
96 let completed = total - remaining; 118 let completed = total - remaining;
97 119
98 return format!("{} completed, {} remaining", completed, remaining); 120 let timestamp = if self.view_month_offset == 0 {
121 format!(
122 "{:>width$}",
123 Local::now().date().format("%d/%b/%y"),
124 width = CONFIGURATION.view_width * CONFIGURATION.grid_width
125 )
126 } else {
127 format!(
128 "{:>width$}",
129 format!("{} months ago", self.view_month_offset),
130 width = CONFIGURATION.view_width * CONFIGURATION.grid_width
131 )
132 };
133
134 StatusLine {
135 0: format!("Today: {} completed, {} remaining", completed, remaining),
136 1: timestamp,
137 }
99 } 138 }
100 139
101 fn max_size(&self) -> Vec2 { 140 fn max_size(&self) -> Vec2 {
@@ -132,12 +171,12 @@ impl App {
132 Command::Add(name, kind, goal) => { 171 Command::Add(name, kind, goal) => {
133 if kind == "count" { 172 if kind == "count" {
134 self.add_habit(Box::new(Count::new(name, goal.unwrap_or(0)))); 173 self.add_habit(Box::new(Count::new(name, goal.unwrap_or(0))));
135 eprintln!("Found COUNT!");
136 } else if kind == "bit" { 174 } else if kind == "bit" {
137 self.add_habit(Box::new(Bit::new(name))); 175 self.add_habit(Box::new(Bit::new(name)));
138 eprintln!("Found BIT!");
139 } 176 }
140 } 177 }
178 Command::MonthNext => self.sift_forward(),
179 Command::MonthPrev => self.sift_backward(),
141 _ => { 180 _ => {
142 eprintln!("UNKNOWN COMMAND!"); 181 eprintln!("UNKNOWN COMMAND!");
143 } 182 }
@@ -162,31 +201,35 @@ impl View for App {
162 offset = offset.map_y(|y| y + CONFIGURATION.view_height).map_x(|_| 0); 201 offset = offset.map_y(|y| y + CONFIGURATION.view_height).map_x(|_| 0);
163 } 202 }
164 i.draw(&printer.offset(offset).focused(self.focus == idx)); 203 i.draw(&printer.offset(offset).focused(self.focus == idx));
165 offset = offset.map_x(|x| x + CONFIGURATION.view_width); 204 offset = offset.map_x(|x| x + CONFIGURATION.view_width + 2);
166 } 205 }
167 offset = offset.map_x(|_| 0).map_y(|_| self.max_size().y - 3); 206
168 printer.print(offset, &self.status()); 207 offset = offset.map_x(|_| 0).map_y(|_| self.max_size().y - 2);
208 printer.print(offset, &self.status().1); // right
209 printer.print(offset, &self.status().0); // left
169 } 210 }
170 211
171 fn required_size(&mut self, _: Vec2) -> Vec2 { 212 fn required_size(&mut self, _: Vec2) -> Vec2 {
172 let grid_width = CONFIGURATION.grid_width; 213 let grid_width = CONFIGURATION.grid_width;
214 let view_width = CONFIGURATION.view_width;
215 let view_height = CONFIGURATION.view_height;
173 let width = { 216 let width = {
174 if self.habits.len() > 0 { 217 if self.habits.len() > 0 {
175 grid_width * CONFIGURATION.view_width 218 grid_width * view_width
176 } else { 219 } else {
177 0 220 0
178 } 221 }
179 }; 222 };
180 let height = { 223 let height = {
181 if self.habits.len() > 0 { 224 if self.habits.len() > 0 {
182 (CONFIGURATION.view_height as f64 225 (view_height as f64 * (self.habits.len() as f64 / grid_width as f64).ceil())
183 * (self.habits.len() as f64 / grid_width as f64).ceil())
184 as usize 226 as usize
227 + 2 // to acoomodate statusline and commandline
185 } else { 228 } else {
186 0 229 0
187 } 230 }
188 }; 231 };
189 Vec2::new(width, height + 2) 232 Vec2::new(width, height)
190 } 233 }
191 234
192 fn take_focus(&mut self, _: Direction) -> bool { 235 fn take_focus(&mut self, _: Direction) -> bool {
@@ -235,6 +278,14 @@ impl View for App {
235 self.save_state(); 278 self.save_state();
236 return EventResult::with_cb(|s| s.quit()); 279 return EventResult::with_cb(|s| s.quit());
237 } 280 }
281 Event::CtrlChar('f') => {
282 self.sift_forward();
283 return EventResult::Consumed(None);
284 }
285 Event::CtrlChar('b') => {
286 self.sift_backward();
287 return EventResult::Consumed(None);
288 }
238 _ => self.habits[self.focus].on_event(e), 289 _ => self.habits[self.focus].on_event(e),
239 } 290 }
240 } 291 }