vault_tasks_time_management/
lib.rs1use std::time::Duration;
2
3use pomodoro::Pomodoro;
4use time_management_technique::TimeManagementTechnique;
5
6pub mod flow_time;
7pub mod pomodoro;
8pub mod time_management_technique;
9
10#[derive(Debug, PartialEq, Clone)]
11pub enum State {
12 Focus(Option<Duration>),
13 Break(Option<Duration>),
14}
15#[derive(Debug)]
16pub struct TimeManagementEngine {
18 pub mode: Box<dyn TimeManagementTechnique>,
19 pub state: Option<State>,
20}
21impl Default for TimeManagementEngine {
22 fn default() -> Self {
23 Self {
24 mode: Box::new(Pomodoro::classic_pomodoro()),
25 state: None,
26 }
27 }
28}
29impl TimeManagementEngine {
30 pub fn new(technique: Box<dyn TimeManagementTechnique>) -> Self {
32 Self {
33 mode: technique,
34 state: None,
35 }
36 }
37
38 pub fn switch(&mut self, time_spent: Duration) -> State {
45 let new_state = self.mode.switch(&self.state, time_spent);
46 self.state = Some(new_state.clone());
47 new_state
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use color_eyre::eyre::Result;
54
55 use crate::{flow_time::FlowTime, pomodoro::Pomodoro, State, TimeManagementEngine};
56
57 use std::time::Duration;
58
59 #[test]
60 fn test_run_pomodoro() {
61 let mut time_tracker = TimeManagementEngine::new(Box::new(Pomodoro::classic_pomodoro()));
62 let focus_time = Duration::from_secs(60 * 25);
63 let short_break_time = Duration::from_secs(60 * 5);
64 assert!(time_tracker.state.is_none());
65
66 let to_spend_opt = time_tracker.switch(Duration::default());
67 assert!(time_tracker.state.is_some());
68 assert_eq!(
69 time_tracker.state.clone().unwrap(),
70 State::Focus(Some(focus_time))
71 );
72 assert_eq!(State::Focus(Some(focus_time)), to_spend_opt);
73
74 let to_spend_opt = time_tracker.switch(Duration::default());
75 assert!(time_tracker.state.is_some());
76 assert_eq!(
77 time_tracker.state.clone().unwrap(),
78 State::Break(Some(short_break_time))
79 );
80 assert_eq!(State::Break(Some(short_break_time)), to_spend_opt);
81 }
82 #[test]
83 fn test_full_run_pomodoro() {
84 let mut time_tracker = TimeManagementEngine::new(Box::new(Pomodoro::classic_pomodoro()));
85 assert!(time_tracker.state.is_none());
86
87 let mut to_spend_opt = State::Focus(None);
88
89 for _i in 0..2 {
90 for _j in 0..(3 * 2) {
92 let to_spend_opt2 = time_tracker.switch(Duration::from_secs(0));
93 to_spend_opt = to_spend_opt2;
94 }
95
96 assert!(time_tracker.state.is_some());
97 assert_eq!(time_tracker.state.clone().unwrap(), to_spend_opt);
98 }
99 }
100 #[test]
101 fn test_run_flowtime() -> Result<()> {
102 let break_factor = 5;
103 let mut time_tracker = TimeManagementEngine::new(Box::new(FlowTime::new(break_factor)?));
104
105 assert!(time_tracker.state.is_none());
106
107 let focus_time = Duration::from_secs(25);
108 let break_time = focus_time / break_factor;
109
110 let to_spend_opt = time_tracker.switch(Duration::from_secs(0));
111
112 assert_eq!(State::Focus(None), to_spend_opt);
113 assert!(time_tracker.state.is_some());
114 assert_eq!(time_tracker.state.clone().unwrap(), State::Focus(None));
115
116 let to_spend_opt = time_tracker.switch(focus_time);
117 assert!(time_tracker.state.is_some());
118 assert_eq!(
119 time_tracker.state.clone().unwrap(),
120 State::Break(Some(break_time))
121 );
122 assert_eq!(State::Break(Some(break_time)), to_spend_opt);
123 Ok(())
124 }
125 #[test]
126 fn test_run_flowtime_excess_break_time() -> Result<()> {
127 let break_factor = 5;
128 let mut time_tracker = TimeManagementEngine::new(Box::new(FlowTime::new(break_factor)?));
129
130 assert!(time_tracker.state.is_none());
131
132 let focus_time = Duration::from_secs(25);
133 let break_time = focus_time / break_factor;
134
135 let to_spend_opt = time_tracker.switch(Duration::from_secs(0));
136
137 assert_eq!(State::Focus(None), to_spend_opt);
138 assert!(time_tracker.state.is_some());
139 assert_eq!(time_tracker.state.clone().unwrap(), State::Focus(None));
140
141 let to_spend_opt = time_tracker.switch(focus_time);
142 assert!(time_tracker.state.is_some());
143 assert_eq!(
144 time_tracker.state.clone().unwrap(),
145 State::Break(Some(break_time))
146 );
147 assert_eq!(State::Break(Some(break_time)), to_spend_opt);
148
149 let break_time_skipped = Duration::from_secs(3);
151 time_tracker.switch(break_time - break_time_skipped);
152 let to_spend_opt = time_tracker.switch(focus_time);
153 assert!(time_tracker.state.is_some());
154 assert_eq!(
155 time_tracker.state.clone().unwrap(),
156 State::Break(Some(break_time + break_time_skipped))
157 );
158 assert_eq!(
159 State::Break(Some(break_time + break_time_skipped)),
160 to_spend_opt
161 );
162
163 let to_spend_opt = time_tracker.switch(break_time + break_time_skipped);
165 assert_eq!(State::Focus(None), to_spend_opt);
166 assert!(time_tracker.state.is_some());
167 assert_eq!(time_tracker.state.clone().unwrap(), State::Focus(None));
168
169 let to_spend_opt = time_tracker.switch(focus_time);
171 assert!(time_tracker.state.is_some());
172 assert_eq!(
173 time_tracker.state.clone().unwrap(),
174 State::Break(Some(break_time))
175 );
176 assert_eq!(State::Break(Some(break_time)), to_spend_opt);
177 Ok(())
178 }
179 #[test]
180 fn test_run_pomodoro_excess_break_time() {
181 let mut time_tracker = TimeManagementEngine::new(Box::new(Pomodoro::classic_pomodoro()));
182
183 assert!(time_tracker.state.is_none());
184
185 let focus_time = Duration::from_secs(1500);
186 let break_time = Duration::from_secs(1500 / 5);
187
188 let to_spend_opt = time_tracker.switch(Duration::from_secs(0));
190
191 assert_eq!(State::Focus(Some(focus_time)), to_spend_opt);
192 assert!(time_tracker.state.is_some());
193 assert_eq!(
194 time_tracker.state.clone().unwrap(),
195 State::Focus(Some(focus_time))
196 );
197
198 let to_spend_opt = time_tracker.switch(focus_time);
200 assert!(time_tracker.state.is_some());
201 assert_eq!(
202 time_tracker.state.clone().unwrap(),
203 State::Break(Some(break_time))
204 );
205 assert_eq!(State::Break(Some(break_time)), to_spend_opt);
206
207 let break_time_skipped = Duration::from_secs(3);
209 time_tracker.switch(break_time - break_time_skipped);
210
211 let focus_time_skipped = Duration::from_secs(9);
213 let to_spend_opt = time_tracker.switch(focus_time - focus_time_skipped);
214
215 assert!(time_tracker.state.is_some());
217 assert_eq!(
218 time_tracker.state.clone().unwrap(),
219 State::Break(Some(break_time + break_time_skipped))
220 );
221 assert_eq!(
222 State::Break(Some(break_time + break_time_skipped)),
223 to_spend_opt
224 );
225
226 let to_spend_opt = time_tracker.switch(break_time + break_time_skipped);
228
229 assert_eq!(
231 State::Focus(Some(focus_time + focus_time_skipped)),
232 to_spend_opt
233 );
234 assert!(time_tracker.state.is_some());
235 assert_eq!(
236 time_tracker.state.clone().unwrap(),
237 State::Focus(Some(focus_time + focus_time_skipped))
238 );
239
240 let to_spend_opt = time_tracker.switch(focus_time + focus_time_skipped);
242 assert!(time_tracker.state.is_some());
243 assert_eq!(
244 time_tracker.state.clone().unwrap(),
245 State::Break(Some(break_time))
246 );
247 assert_eq!(State::Break(Some(break_time)), to_spend_opt);
248
249 let to_spend_opt = time_tracker.switch(break_time);
251 assert!(time_tracker.state.is_some());
252 assert_eq!(
253 time_tracker.state.clone().unwrap(),
254 State::Focus(Some(focus_time))
255 );
256 assert_eq!(State::Focus(Some(focus_time)), to_spend_opt);
257 }
258}