vault_tasks_time_management/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::time::Duration;

use pomodoro::Pomodoro;
use time_management_technique::TimeManagementTechnique;

pub mod flow_time;
pub mod pomodoro;
pub mod time_management_technique;

#[derive(Debug, PartialEq, Clone)]
pub enum State {
    Focus(Option<Duration>),
    Break(Option<Duration>),
}
#[derive(Debug)]
/// Provides tracking methods using a generic `TimeTrackingTechnique`
pub struct TimeManagementEngine {
    pub mode: Box<dyn TimeManagementTechnique>,
    pub state: Option<State>,
}
impl Default for TimeManagementEngine {
    fn default() -> Self {
        Self {
            mode: Box::new(Pomodoro::classic_pomodoro()),
            state: None,
        }
    }
}
impl TimeManagementEngine {
    /// Creates a new [`TimeTrackingEngine<T>`].
    pub fn new(technique: Box<dyn TimeManagementTechnique>) -> Self {
        Self {
            mode: technique,
            state: None,
        }
    }

    /// Returns the next state of the time tracking engine.
    /// # Argument
    /// - `time_spent: Duration`: The duration of the previous session.
    /// # Returns
    /// - `Option<Duration>`: Whether there is or not an explicit duration for the next session
    /// - `TimeManagementEngine<T>`: The next state of the engine
    pub fn switch(&mut self, time_spent: Duration) -> State {
        let new_state = self.mode.switch(&self.state, time_spent);
        self.state = Some(new_state.clone());
        new_state
    }
}

#[cfg(test)]
mod tests {
    use color_eyre::eyre::Result;

    use crate::{flow_time::FlowTime, pomodoro::Pomodoro, State, TimeManagementEngine};

    use std::time::Duration;

    #[test]
    fn test_run_pomodoro() {
        let mut time_tracker = TimeManagementEngine::new(Box::new(Pomodoro::classic_pomodoro()));
        let focus_time = Duration::from_secs(60 * 25);
        let short_break_time = Duration::from_secs(60 * 5);
        assert!(time_tracker.state.is_none());

        let to_spend_opt = time_tracker.switch(Duration::default());
        assert!(time_tracker.state.is_some());
        assert_eq!(
            time_tracker.state.clone().unwrap(),
            State::Focus(Some(focus_time))
        );
        assert_eq!(State::Focus(Some(focus_time)), to_spend_opt);

        let to_spend_opt = time_tracker.switch(Duration::default());
        assert!(time_tracker.state.is_some());
        assert_eq!(
            time_tracker.state.clone().unwrap(),
            State::Break(Some(short_break_time))
        );
        assert_eq!(State::Break(Some(short_break_time)), to_spend_opt);
    }
    #[test]
    fn test_full_run_pomodoro() {
        let mut time_tracker = TimeManagementEngine::new(Box::new(Pomodoro::classic_pomodoro()));
        assert!(time_tracker.state.is_none());

        let mut to_spend_opt = State::Focus(None);

        for _i in 0..2 {
            // (Focus -> Break) 3 times
            for _j in 0..(3 * 2) {
                let to_spend_opt2 = time_tracker.switch(Duration::from_secs(0));
                to_spend_opt = to_spend_opt2;
            }

            assert!(time_tracker.state.is_some());
            assert_eq!(time_tracker.state.clone().unwrap(), to_spend_opt);
        }
    }
    #[test]
    fn test_run_flowtime() -> Result<()> {
        let break_factor = 5;
        let mut time_tracker = TimeManagementEngine::new(Box::new(FlowTime::new(break_factor)?));

        assert!(time_tracker.state.is_none());

        let focus_time = Duration::from_secs(25);
        let break_time = focus_time / break_factor;

        let to_spend_opt = time_tracker.switch(Duration::from_secs(0));

        assert_eq!(State::Focus(None), to_spend_opt);
        assert!(time_tracker.state.is_some());
        assert_eq!(time_tracker.state.clone().unwrap(), State::Focus(None));

        let to_spend_opt = time_tracker.switch(focus_time);
        assert!(time_tracker.state.is_some());
        assert_eq!(
            time_tracker.state.clone().unwrap(),
            State::Break(Some(break_time))
        );
        assert_eq!(State::Break(Some(break_time)), to_spend_opt);
        Ok(())
    }
}