diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/views.rs | 125 | ||||
-rw-r--r-- | src/views/habitview.rs | 137 | ||||
-rw-r--r-- | src/views/mod.rs | 4 |
3 files changed, 125 insertions, 141 deletions
diff --git a/src/views.rs b/src/views.rs new file mode 100644 index 0000000..ebb83b8 --- /dev/null +++ b/src/views.rs | |||
@@ -0,0 +1,125 @@ | |||
1 | use cursive::direction::Direction; | ||
2 | use cursive::event::{Event, EventResult, Key}; | ||
3 | use cursive::theme::Style; | ||
4 | use cursive::view::View; | ||
5 | use cursive::{Printer, Vec2}; | ||
6 | |||
7 | use chrono::prelude::*; | ||
8 | use chrono::{Local, NaiveDate}; | ||
9 | |||
10 | use crate::habit::{Bit, Count, Habit, TrackEvent}; | ||
11 | use crate::CONFIGURATION; | ||
12 | |||
13 | pub trait ShadowView { | ||
14 | fn draw(&self, printer: &Printer); | ||
15 | fn required_size(&mut self, _: Vec2) -> Vec2; | ||
16 | fn take_focus(&mut self, _: Direction) -> bool; | ||
17 | fn on_event(&mut self, e: Event) -> EventResult; | ||
18 | } | ||
19 | |||
20 | // the only way to not rewrite each View implementation for trait | ||
21 | // objects of Habit is to rewrite the View trait itself. | ||
22 | impl<T> ShadowView for T | ||
23 | where | ||
24 | T: Habit, | ||
25 | T::HabitType: std::fmt::Display, | ||
26 | { | ||
27 | fn draw(&self, printer: &Printer) { | ||
28 | let now = Local::now(); | ||
29 | let year = now.year(); | ||
30 | let month = now.month(); | ||
31 | |||
32 | let goal_reached_style = Style::from(CONFIGURATION.reached_color); | ||
33 | let todo_style = Style::from(CONFIGURATION.todo_color); | ||
34 | let future_style = Style::from(CONFIGURATION.future_color); | ||
35 | |||
36 | printer.with_style( | ||
37 | if !printer.focused { | ||
38 | future_style | ||
39 | } else { | ||
40 | goal_reached_style | ||
41 | }, | ||
42 | |p| { | ||
43 | p.print( | ||
44 | (0, 0), | ||
45 | &format!("{:width$}", self.name(), width = CONFIGURATION.view_width), | ||
46 | ) | ||
47 | }, | ||
48 | ); | ||
49 | |||
50 | for i in 1..=31 { | ||
51 | let day = NaiveDate::from_ymd_opt(year, month, i); | ||
52 | let day_style; | ||
53 | |||
54 | if let Some(d) = day { | ||
55 | if self.reached_goal(d) { | ||
56 | day_style = goal_reached_style; | ||
57 | } else { | ||
58 | day_style = todo_style; | ||
59 | } | ||
60 | let coords: Vec2 = ((i % 7) * 3, i / 7 + 2).into(); | ||
61 | if let Some(c) = self.get_by_date(d) { | ||
62 | printer.with_style(day_style, |p| { | ||
63 | p.print(coords, &format!("{:^3}", c)); | ||
64 | }); | ||
65 | } else { | ||
66 | printer.with_style(future_style, |p| { | ||
67 | p.print(coords, &format!("{:^3}", CONFIGURATION.future_chr)); | ||
68 | }); | ||
69 | } | ||
70 | //printer.with_style(day_style, |p| { | ||
71 | // p.print(coords, &format!("{:^3}", c)); | ||
72 | // } else { | ||
73 | // p.print(coords, &format!("{:^3}", CONFIGURATION.future_chr)); | ||
74 | // } | ||
75 | //}); | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | fn required_size(&mut self, _: Vec2) -> Vec2 { | ||
80 | (25, 6).into() | ||
81 | } | ||
82 | |||
83 | fn take_focus(&mut self, _: Direction) -> bool { | ||
84 | true | ||
85 | } | ||
86 | |||
87 | fn on_event(&mut self, e: Event) -> EventResult { | ||
88 | let now = Local::now().naive_utc().date(); | ||
89 | match e { | ||
90 | Event::Key(Key::Enter) | Event::Char('n') => { | ||
91 | self.modify(now, TrackEvent::Increment); | ||
92 | return EventResult::Consumed(None); | ||
93 | } | ||
94 | Event::Key(Key::Backspace) | Event::Char('p') => { | ||
95 | self.modify(now, TrackEvent::Decrement); | ||
96 | return EventResult::Consumed(None); | ||
97 | } | ||
98 | _ => return EventResult::Ignored, | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | macro_rules! auto_view_impl { | ||
104 | ($struct_name:ident) => { | ||
105 | impl View for $struct_name { | ||
106 | fn draw(&self, printer: &Printer) { | ||
107 | ShadowView::draw(self, printer); | ||
108 | } | ||
109 | fn required_size(&mut self, x: Vec2) -> Vec2 { | ||
110 | ShadowView::required_size(self, x) | ||
111 | } | ||
112 | |||
113 | fn take_focus(&mut self, d: Direction) -> bool { | ||
114 | ShadowView::take_focus(self, d) | ||
115 | } | ||
116 | |||
117 | fn on_event(&mut self, e: Event) -> EventResult { | ||
118 | ShadowView::on_event(self, e) | ||
119 | } | ||
120 | } | ||
121 | }; | ||
122 | } | ||
123 | |||
124 | auto_view_impl!(Count); | ||
125 | auto_view_impl!(Bit); | ||
diff --git a/src/views/habitview.rs b/src/views/habitview.rs deleted file mode 100644 index c9ca505..0000000 --- a/src/views/habitview.rs +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | use cursive::direction::Direction; | ||
2 | use cursive::event::{Event, EventResult, Key}; | ||
3 | use cursive::theme::{BaseColor, Color, Style}; | ||
4 | use cursive::view::View; | ||
5 | use cursive::{Printer, Vec2}; | ||
6 | |||
7 | use chrono::prelude::*; | ||
8 | use chrono::{Local, NaiveDate}; | ||
9 | |||
10 | use crate::habit::{Habit, HabitTrait, HabitType, TrackEvent}; | ||
11 | |||
12 | use serde::Serialize; | ||
13 | |||
14 | pub struct HabitView { | ||
15 | habit: Habit, | ||
16 | // characters to use | ||
17 | true_chr: char, | ||
18 | false_chr: char, | ||
19 | future_chr: char, | ||
20 | // view dimensions | ||
21 | view_width: u32, | ||
22 | view_height: u32, | ||
23 | // color config | ||
24 | reached_color: Color, | ||
25 | todo_color: Color, | ||
26 | future_color: Color, | ||
27 | } | ||
28 | |||
29 | impl HabitView { | ||
30 | pub fn new(habit: Habit) -> Self { | ||
31 | return HabitView { | ||
32 | habit, | ||
33 | true_chr: '·', | ||
34 | false_chr: '·', | ||
35 | future_chr: '·', | ||
36 | view_width: 25, | ||
37 | view_height: 8, | ||
38 | reached_color: Color::Dark(BaseColor::Cyan), | ||
39 | todo_color: Color::Dark(BaseColor::Magenta), | ||
40 | future_color: Color::Light(BaseColor::Black), | ||
41 | }; | ||
42 | } | ||
43 | pub fn get_name(&self) -> String { | ||
44 | return self.habit.get_name().to_owned(); | ||
45 | } | ||
46 | pub fn get_size(&self) -> Vec2 { | ||
47 | (self.view_width, self.view_height).into() | ||
48 | } | ||
49 | pub fn remaining(&self) -> u32 { | ||
50 | self.habit.remaining(Local::now().naive_utc().date()) | ||
51 | } | ||
52 | pub fn total(&self) -> u32 { | ||
53 | self.habit.total() | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl View for HabitView { | ||
58 | fn draw(&self, printer: &Printer) { | ||
59 | let now = Local::now(); | ||
60 | let year = now.year(); | ||
61 | let month = now.month(); | ||
62 | |||
63 | let goal_reached_style = Style::from(self.reached_color); | ||
64 | let todo_style = Style::from(self.todo_color); | ||
65 | let future_style = Style::from(self.future_color); | ||
66 | |||
67 | printer.with_style( | ||
68 | if !printer.focused { | ||
69 | future_style | ||
70 | } else { | ||
71 | goal_reached_style | ||
72 | }, | ||
73 | |p| { | ||
74 | p.print( | ||
75 | (0, 0), | ||
76 | &format!("{:width$}", self.get_name(), width = self.get_size().x), | ||
77 | ) | ||
78 | }, | ||
79 | ); | ||
80 | |||
81 | for i in 1..=31 { | ||
82 | let day = NaiveDate::from_ymd_opt(year, month, i); | ||
83 | let mut day_style; | ||
84 | |||
85 | if let Some(d) = day { | ||
86 | if self.habit.reached_goal(d) { | ||
87 | day_style = goal_reached_style; | ||
88 | } else { | ||
89 | day_style = todo_style; | ||
90 | } | ||
91 | let coords: Vec2 = ((i % 7) * 3, i / 7 + 2).into(); | ||
92 | let day_chr: Box<dyn std::fmt::Display> = match self.habit.get_by_date(d) { | ||
93 | Some(val) => match val { | ||
94 | HabitType::Bit(b) => { | ||
95 | if *b { | ||
96 | Box::new(self.true_chr) | ||
97 | } else { | ||
98 | Box::new(self.false_chr) | ||
99 | } | ||
100 | } | ||
101 | HabitType::Count(c) => Box::new(c.to_string()), | ||
102 | }, | ||
103 | None => { | ||
104 | day_style = future_style; | ||
105 | Box::new(self.future_chr) | ||
106 | } | ||
107 | }; | ||
108 | printer.with_style(day_style, |p| { | ||
109 | p.print(coords, &format!("{:^3}", day_chr)); | ||
110 | }); | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | fn required_size(&mut self, _: Vec2) -> Vec2 { | ||
116 | (self.view_width, self.view_height).into() | ||
117 | } | ||
118 | |||
119 | fn take_focus(&mut self, _: Direction) -> bool { | ||
120 | true | ||
121 | } | ||
122 | |||
123 | fn on_event(&mut self, e: Event) -> EventResult { | ||
124 | let now = Local::now().naive_utc().date(); | ||
125 | match e { | ||
126 | Event::Key(Key::Enter) | Event::Char('n') => { | ||
127 | self.habit.modify(now, TrackEvent::Increment); | ||
128 | return EventResult::Consumed(None); | ||
129 | } | ||
130 | Event::Key(Key::Backspace) | Event::Char('p') => { | ||
131 | self.habit.modify(now, TrackEvent::Decrement); | ||
132 | return EventResult::Consumed(None); | ||
133 | } | ||
134 | _ => return EventResult::Ignored, | ||
135 | } | ||
136 | } | ||
137 | } | ||
diff --git a/src/views/mod.rs b/src/views/mod.rs deleted file mode 100644 index 1e3732f..0000000 --- a/src/views/mod.rs +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | // pub mod bitview; | ||
2 | // pub mod countview; | ||
3 | |||
4 | pub mod habitview; | ||