aboutsummaryrefslogtreecommitdiff
path: root/src/habit.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/habit.rs')
-rw-r--r--src/habit.rs248
1 files changed, 174 insertions, 74 deletions
diff --git a/src/habit.rs b/src/habit.rs
index 7d50adf..3716183 100644
--- a/src/habit.rs
+++ b/src/habit.rs
@@ -3,130 +3,230 @@ use std::collections::HashMap;
3use chrono::NaiveDate; 3use chrono::NaiveDate;
4use serde::Serialize; 4use serde::Serialize;
5 5
6#[derive(Serialize, Debug, Clone, Copy)] 6use cursive::direction::Direction;
7pub enum HabitType { 7use cursive::event::{Event, EventResult};
8 Bit(bool), 8use cursive::{Printer, Vec2};
9 Count(u32), 9
10use crate::views::ShadowView;
11use crate::CONFIGURATION;
12
13pub enum TrackEvent {
14 Increment,
15 Decrement,
10} 16}
11 17
12impl HabitType { 18#[derive(Copy, Clone, Debug, Serialize)]
13 fn inner_bit(&self) -> bool { 19pub struct CustomBool(bool);
14 if let HabitType::Bit(v) = self { 20
15 *v 21use std::fmt;
16 } else { 22impl fmt::Display for CustomBool {
17 panic!("why"); 23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 } 24 write!(
25 f,
26 "{}",
27 if self.0 {
28 CONFIGURATION.true_chr
29 } else {
30 CONFIGURATION.false_chr
31 }
32 )
19 } 33 }
20 fn inner_count(&self) -> u32 { 34}
21 if let HabitType::Count(v) = self { 35
22 *v 36impl From<bool> for CustomBool {
23 } else { 37 fn from(b: bool) -> Self {
24 panic!("why"); 38 CustomBool(b)
25 }
26 } 39 }
27} 40}
28 41
29pub trait HabitTrait { 42pub trait Habit {
43 type HabitType;
44
30 fn set_name(&mut self, name: impl AsRef<str>); 45 fn set_name(&mut self, name: impl AsRef<str>);
31 fn set_goal(&mut self, goal: HabitType); 46 fn set_goal(&mut self, goal: Self::HabitType);
32 fn get_name(&self) -> String; 47 fn name(&self) -> String;
33 fn get_by_date(&self, date: NaiveDate) -> Option<&HabitType>; 48 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType>;
34 fn insert_entry(&mut self, date: NaiveDate, val: HabitType); 49 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType);
35 fn reached_goal(&self, date: NaiveDate) -> bool; 50 fn reached_goal(&self, date: NaiveDate) -> bool;
36 fn remaining(&self, date: NaiveDate) -> u32; 51 fn remaining(&self, date: NaiveDate) -> u32;
37 fn total(&self) -> u32; 52 fn total(&self) -> u32;
53 fn modify(&mut self, date: NaiveDate, event: TrackEvent);
38} 54}
39 55
40#[derive(Serialize, Debug)] 56pub trait HabitWrapper {
41pub struct Habit { 57 fn remaining(&self, date: NaiveDate) -> u32;
42 name: String, 58 fn total(&self) -> u32;
43 stats: HashMap<NaiveDate, HabitType>, 59 fn modify(&mut self, date: NaiveDate, event: TrackEvent);
44 goal: HabitType, 60 fn draw(&self, printer: &Printer);
61 fn on_event(&mut self, event: Event) -> EventResult;
62 fn required_size(&mut self, _: Vec2) -> Vec2;
63 fn take_focus(&mut self, _: Direction) -> bool;
45} 64}
46 65
47pub enum TrackEvent { 66impl<T> HabitWrapper for T
48 Increment, 67where
49 Decrement, 68 T: Habit + ShadowView,
69 T::HabitType: std::fmt::Display,
70{
71 fn remaining(&self, date: NaiveDate) -> u32 {
72 Habit::remaining(self, date)
73 }
74 fn total(&self) -> u32 {
75 Habit::total(self)
76 }
77 fn modify(&mut self, date: NaiveDate, event: TrackEvent) {
78 Habit::modify(self, date, event);
79 }
80 fn draw(&self, printer: &Printer) {
81 ShadowView::draw(self, printer)
82 }
83 fn on_event(&mut self, event: Event) -> EventResult {
84 ShadowView::on_event(self, event)
85 }
86 fn required_size(&mut self, x: Vec2) -> Vec2 {
87 ShadowView::required_size(self, x)
88 }
89 fn take_focus(&mut self, d: Direction) -> bool {
90 ShadowView::take_focus(self, d)
91 }
50} 92}
51 93
52impl Habit { 94#[derive(Debug, Serialize)]
53 pub fn new(name: impl AsRef<str>, goal: HabitType) -> Self { 95pub struct Count {
54 return Habit { 96 name: String,
97 stats: HashMap<NaiveDate, u32>,
98 goal: u32,
99}
100
101impl Count {
102 pub fn new(name: impl AsRef<str>, goal: u32) -> Self {
103 return Count {
55 name: name.as_ref().to_owned(), 104 name: name.as_ref().to_owned(),
56 stats: HashMap::new(), 105 stats: HashMap::new(),
57 goal, 106 goal,
58 }; 107 };
59 } 108 }
109}
60 110
61 pub fn modify(&mut self, date: NaiveDate, event: TrackEvent) { 111impl Habit for Count {
62 if let Some(val) = self.stats.get_mut(&date) { 112 type HabitType = u32;
63 match val { 113
64 HabitType::Bit(b) => *b ^= true, 114 fn name(&self) -> String {
65 HabitType::Count(c) => match event { 115 return self.name.clone();
66 TrackEvent::Increment => *c += 1, 116 }
67 TrackEvent::Decrement => { 117 fn set_name(&mut self, n: impl AsRef<str>) {
68 if *c > 0 { 118 self.name = n.as_ref().to_owned();
69 *c -= 1; 119 }
70 } else { 120 fn set_goal(&mut self, g: Self::HabitType) {
71 *c = 0; 121 self.goal = g;
72 } 122 }
73 } 123 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType> {
74 }, 124 self.stats.get(&date)
125 }
126 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType) {
127 *self.stats.entry(date).or_insert(val) = val;
128 }
129 fn reached_goal(&self, date: NaiveDate) -> bool {
130 if let Some(val) = self.stats.get(&date) {
131 if val >= &self.goal {
132 return true;
75 } 133 }
134 }
135 return false;
136 }
137 fn remaining(&self, date: NaiveDate) -> u32 {
138 if self.reached_goal(date) {
139 return 0;
76 } else { 140 } else {
77 match self.goal { 141 if let Some(val) = self.stats.get(&date) {
78 HabitType::Bit(_) => self.insert_entry(date, HabitType::Bit(true)), 142 return self.goal - val;
79 HabitType::Count(_) => self.insert_entry(date, HabitType::Count(1)), 143 } else {
144 return self.goal;
80 } 145 }
81 } 146 }
82 } 147 }
148 fn total(&self) -> u32 {
149 return self.goal;
150 }
151 fn modify(&mut self, date: NaiveDate, event: TrackEvent) {
152 if let Some(val) = self.stats.get_mut(&date) {
153 match event {
154 TrackEvent::Increment => *val += 1,
155 TrackEvent::Decrement => {
156 if *val > 0 {
157 *val -= 1
158 } else {
159 *val = 0
160 };
161 }
162 }
163 } else {
164 self.insert_entry(date, 1);
165 }
166 }
167}
168
169#[derive(Debug, Serialize)]
170pub struct Bit {
171 name: String,
172 stats: HashMap<NaiveDate, CustomBool>,
173 goal: CustomBool,
83} 174}
84 175
85impl HabitTrait for Habit { 176impl Bit {
86 fn get_name(&self) -> String { 177 pub fn new(name: impl AsRef<str>) -> Self {
87 return self.name.to_owned(); 178 return Bit {
179 name: name.as_ref().to_owned(),
180 stats: HashMap::new(),
181 goal: CustomBool(true),
182 };
183 }
184}
185
186impl Habit for Bit {
187 type HabitType = CustomBool;
188 fn name(&self) -> String {
189 return self.name.clone();
88 } 190 }
89 fn set_name(&mut self, n: impl AsRef<str>) { 191 fn set_name(&mut self, n: impl AsRef<str>) {
90 self.name = n.as_ref().to_owned(); 192 self.name = n.as_ref().to_owned();
91 } 193 }
92 fn set_goal(&mut self, g: HabitType) { 194 fn set_goal(&mut self, g: Self::HabitType) {
93 self.goal = g; 195 self.goal = g;
94 } 196 }
95 fn get_by_date(&self, date: NaiveDate) -> Option<&HabitType> { 197 fn get_by_date(&self, date: NaiveDate) -> Option<&Self::HabitType> {
96 self.stats.get(&date) 198 self.stats.get(&date)
97 } 199 }
98 fn insert_entry(&mut self, date: NaiveDate, val: HabitType) { 200 fn insert_entry(&mut self, date: NaiveDate, val: Self::HabitType) {
99 *self.stats.entry(date).or_insert(val) = val; 201 *self.stats.entry(date).or_insert(val) = val;
100 } 202 }
101 fn reached_goal(&self, date: NaiveDate) -> bool { 203 fn reached_goal(&self, date: NaiveDate) -> bool {
102 if let Some(val) = self.stats.get(&date) { 204 if let Some(val) = self.stats.get(&date) {
103 match val { 205 if val.0 >= self.goal.0 {
104 HabitType::Bit(b) => return *b, 206 return true;
105 HabitType::Count(c) => { 207 }
106 if *c >= self.goal.inner_count() {
107 return true;
108 }
109 }
110 };
111 } 208 }
112 return false; 209 return false;
113 } 210 }
114 fn remaining(&self, date: NaiveDate) -> u32 { 211 fn remaining(&self, date: NaiveDate) -> u32 {
115 if self.reached_goal(date) { 212 if let Some(val) = self.stats.get(&date) {
116 return 0; 213 if val.0 {
117 } else if let Some(val) = self.stats.get(&date) { 214 return 0;
118 match val { 215 } else {
119 HabitType::Bit(_) => return 1, 216 return 1;
120 HabitType::Count(c) => return self.goal.inner_count() - *c,
121 } 217 }
122 } else { 218 } else {
123 return self.total(); 219 return 1;
124 } 220 }
125 } 221 }
126 fn total(&self) -> u32 { 222 fn total(&self) -> u32 {
127 match self.goal { 223 return 1;
128 HabitType::Bit(_) => return 1, 224 }
129 HabitType::Count(c) => return c, 225 fn modify(&mut self, date: NaiveDate, _: TrackEvent) {
226 if let Some(val) = self.stats.get_mut(&date) {
227 *val = (val.0 ^ true).into();
228 } else {
229 self.insert_entry(date, CustomBool(true));
130 } 230 }
131 } 231 }
132} 232}