aboutsummaryrefslogtreecommitdiff
path: root/src/habit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/habit.rs')
-rw-r--r--src/habit.rs319
1 files changed, 0 insertions, 319 deletions
diff --git a/src/habit.rs b/src/habit.rs
deleted file mode 100644
index 725e15f..0000000
--- a/src/habit.rs
+++ /dev/null
@@ -1,319 +0,0 @@
1use std::collections::HashMap;
2
3use chrono::NaiveDate;
4use serde::{Deserialize, Serialize};
5
6use cursive::direction::Direction;
7use cursive::event::{Event, EventResult};
8use cursive::{Printer, Vec2};
9
10use crate::views::ShadowView;
11use crate::CONFIGURATION;
12
13pub enum TrackEvent {
14 Increment,
15 Decrement,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
19pub enum ViewMode {
20 Day,
21 Week,
22 Month,
23 Year,
24}
25
26impl std::default::Default for ViewMode {
27 fn default() -> Self {
28 ViewMode::Day
29 }
30}
31
32#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
33pub struct CustomBool(bool);
34
35use std::fmt;
36impl fmt::Display for CustomBool {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(
39 f,
40 "{:^3}",
41 if self.0 {
42 CONFIGURATION.true_chr
43 } else {
44 CONFIGURATION.false_chr
45 }
46 )
47 }
48}
49
50impl From<bool> for CustomBool {
51 fn from(b: bool) -> Self {
52 CustomBool(b)
53 }
54}
55
56pub trait Habit {
57 type HabitType;
58
59 fn set_name(&mut self, name: impl AsRef<str>);
60 fn set_goal(&mut self, goal: Self::HabitType);
61 fn name(&self) -> String;
62 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType>;
63 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType);
64 fn reached_goal(&self, date: NaiveDate) -> bool;
65 fn remaining(&self, date: NaiveDate) -> u32;
66 fn goal(&self) -> u32;
67 fn modify(&mut self, date: NaiveDate, event: TrackEvent);
68
69 fn set_view_month_offset(&mut self, offset: u32);
70 fn view_month_offset(&self) -> u32;
71
72 fn set_view_mode(&mut self, mode: ViewMode);
73 fn view_mode(&self) -> ViewMode;
74}
75
76#[typetag::serde(tag = "type")]
77pub trait HabitWrapper: erased_serde::Serialize {
78 fn remaining(&self, date: NaiveDate) -> u32;
79 fn goal(&self) -> u32;
80 fn modify(&mut self, date: NaiveDate, event: TrackEvent);
81 fn draw(&self, printer: &Printer);
82 fn on_event(&mut self, event: Event) -> EventResult;
83 fn required_size(&mut self, _: Vec2) -> Vec2;
84 fn take_focus(&mut self, _: Direction) -> bool;
85 fn get_name(&self) -> String;
86
87 fn set_view_month_offset(&mut self, offset: u32);
88 fn view_month_offset(&self) -> u32;
89
90 fn set_view_mode(&mut self, mode: ViewMode);
91 fn view_mode(&self) -> ViewMode;
92}
93
94macro_rules! auto_habit_impl {
95 ($struct_name:ident) => {
96 #[typetag::serde]
97 impl HabitWrapper for $struct_name {
98 fn remaining(&self, date: NaiveDate) -> u32 {
99 Habit::remaining(self, date)
100 }
101 fn goal(&self) -> u32 {
102 Habit::goal(self)
103 }
104 fn modify(&mut self, date: NaiveDate, event: TrackEvent) {
105 Habit::modify(self, date, event);
106 }
107 fn draw(&self, printer: &Printer) {
108 ShadowView::draw(self, printer)
109 }
110 fn on_event(&mut self, event: Event) -> EventResult {
111 ShadowView::on_event(self, event)
112 }
113 fn required_size(&mut self, x: Vec2) -> Vec2 {
114 ShadowView::required_size(self, x)
115 }
116 fn take_focus(&mut self, d: Direction) -> bool {
117 ShadowView::take_focus(self, d)
118 }
119 fn get_name(&self) -> String {
120 Habit::name(self)
121 }
122 fn set_view_month_offset(&mut self, offset: u32) {
123 Habit::set_view_month_offset(self, offset)
124 }
125 fn view_month_offset(&self) -> u32 {
126 Habit::view_month_offset(self)
127 }
128 fn set_view_mode(&mut self, mode: ViewMode) {
129 Habit::set_view_mode(self, mode)
130 }
131 fn view_mode(&self) -> ViewMode {
132 Habit::view_mode(self)
133 }
134 }
135 };
136}
137
138auto_habit_impl!(Count);
139auto_habit_impl!(Bit);
140
141#[derive(Debug, Serialize, Deserialize)]
142pub struct Count {
143 name: String,
144 stats: HashMap<NaiveDate, u32>,
145 goal: u32,
146
147 #[serde(skip)]
148 view_month_offset: u32,
149
150 #[serde(skip)]
151 view_mode: ViewMode,
152}
153
154impl Count {
155 pub fn new(name: impl AsRef<str>, goal: u32) -> Self {
156 return Count {
157 name: name.as_ref().to_owned(),
158 stats: HashMap::new(),
159 goal,
160 view_month_offset: 0,
161 view_mode: ViewMode::Day,
162 };
163 }
164}
165
166impl Habit for Count {
167 type HabitType = u32;
168
169 fn name(&self) -> String {
170 return self.name.clone();
171 }
172 fn set_name(&mut self, n: impl AsRef<str>) {
173 self.name = n.as_ref().to_owned();
174 }
175 fn set_goal(&mut self, g: Self::HabitType) {
176 self.goal = g;
177 }
178 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType> {
179 self.stats.get(&date)
180 }
181 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType) {
182 *self.stats.entry(date).or_insert(val) = val;
183 }
184 fn reached_goal(&self, date: NaiveDate) -> bool {
185 if let Some(val) = self.stats.get(&date) {
186 if val >= &self.goal {
187 return true;
188 }
189 }
190 return false;
191 }
192 fn remaining(&self, date: NaiveDate) -> u32 {
193 if self.reached_goal(date) {
194 return 0;
195 } else {
196 if let Some(val) = self.stats.get(&date) {
197 return self.goal - val;
198 } else {
199 return self.goal;
200 }
201 }
202 }
203 fn goal(&self) -> u32 {
204 return self.goal;
205 }
206 fn modify(&mut self, date: NaiveDate, event: TrackEvent) {
207 if let Some(val) = self.stats.get_mut(&date) {
208 match event {
209 TrackEvent::Increment => *val += 1,
210 TrackEvent::Decrement => {
211 if *val > 0 {
212 *val -= 1
213 } else {
214 *val = 0
215 };
216 }
217 }
218 } else {
219 self.insert_entry(date, 1);
220 }
221 }
222 fn set_view_month_offset(&mut self, offset: u32) {
223 self.view_month_offset = offset;
224 }
225 fn view_month_offset(&self) -> u32 {
226 self.view_month_offset
227 }
228 fn set_view_mode(&mut self, mode: ViewMode) {
229 self.view_mode = mode;
230 }
231 fn view_mode(&self) -> ViewMode {
232 self.view_mode
233 }
234}
235
236#[derive(Debug, Serialize, Deserialize)]
237pub struct Bit {
238 name: String,
239 stats: HashMap<NaiveDate, CustomBool>,
240 goal: CustomBool,
241
242 #[serde(skip)]
243 view_month_offset: u32,
244
245 #[serde(skip)]
246 view_mode: ViewMode,
247}
248
249impl Bit {
250 pub fn new(name: impl AsRef<str>) -> Self {
251 return Bit {
252 name: name.as_ref().to_owned(),
253 stats: HashMap::new(),
254 goal: CustomBool(true),
255 view_month_offset: 0,
256 view_mode: ViewMode::Day,
257 };
258 }
259}
260
261impl Habit for Bit {
262 type HabitType = CustomBool;
263 fn name(&self) -> String {
264 return self.name.clone();
265 }
266 fn set_name(&mut self, n: impl AsRef<str>) {
267 self.name = n.as_ref().to_owned();
268 }
269 fn set_goal(&mut self, g: Self::HabitType) {
270 self.goal = g;
271 }
272 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType> {
273 self.stats.get(&date)
274 }
275 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType) {
276 *self.stats.entry(date).or_insert(val) = val;
277 }
278 fn reached_goal(&self, date: NaiveDate) -> bool {
279 if let Some(val) = self.stats.get(&date) {
280 if val.0 >= self.goal.0 {
281 return true;
282 }
283 }
284 return false;
285 }
286 fn remaining(&self, date: NaiveDate) -> u32 {
287 if let Some(val) = self.stats.get(&date) {
288 if val.0 {
289 return 0;
290 } else {
291 return 1;
292 }
293 } else {
294 return 1;
295 }
296 }
297 fn goal(&self) -> u32 {
298 return 1;
299 }
300 fn modify(&mut self, date: NaiveDate, _: TrackEvent) {
301 if let Some(val) = self.stats.get_mut(&date) {
302 *val = (val.0 ^ true).into();
303 } else {
304 self.insert_entry(date, CustomBool(true));
305 }
306 }
307 fn set_view_month_offset(&mut self, offset: u32) {
308 self.view_month_offset = offset;
309 }
310 fn view_month_offset(&self) -> u32 {
311 self.view_month_offset
312 }
313 fn set_view_mode(&mut self, mode: ViewMode) {
314 self.view_mode = mode;
315 }
316 fn view_mode(&self) -> ViewMode {
317 self.view_mode
318 }
319}