Skip to main content

tix/ui/
dialog.rs

1use crossterm::event::KeyCode;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct RolloverDialog {
5    pub plans: Vec<(String, String, usize)>,
6    pub choice: DialogChoice,
7    pub dismissed: bool,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum DialogChoice {
12    DoRollover,
13    Ignore,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum DialogEvent {
18    None,
19    ConfirmDo,
20    ConfirmIgnore,
21    Dismiss,
22}
23
24impl RolloverDialog {
25    pub fn new(plans: Vec<(String, String, usize)>) -> Self {
26        Self {
27            plans,
28            choice: DialogChoice::DoRollover,
29            dismissed: false,
30        }
31    }
32
33    pub fn is_active(&self) -> bool {
34        !self.plans.is_empty() && !self.dismissed
35    }
36
37    pub fn handle_key(&mut self, key: KeyCode) -> DialogEvent {
38        if !self.is_active() {
39            return DialogEvent::Dismiss;
40        }
41        match key {
42            KeyCode::Left | KeyCode::Right | KeyCode::Tab => {
43                self.choice = match self.choice {
44                    DialogChoice::DoRollover => DialogChoice::Ignore,
45                    DialogChoice::Ignore => DialogChoice::DoRollover,
46                };
47                DialogEvent::None
48            }
49            KeyCode::Esc => {
50                self.dismissed = true;
51                DialogEvent::Dismiss
52            }
53            KeyCode::Enter => {
54                self.dismissed = true;
55                match self.choice {
56                    DialogChoice::DoRollover => DialogEvent::ConfirmDo,
57                    DialogChoice::Ignore => DialogEvent::ConfirmIgnore,
58                }
59            }
60            _ => DialogEvent::None,
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn dialog_choice_toggles() {
71        let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
72        assert_eq!(dialog.choice, DialogChoice::DoRollover);
73        dialog.handle_key(KeyCode::Tab);
74        assert_eq!(dialog.choice, DialogChoice::Ignore);
75    }
76
77    #[test]
78    fn enter_confirms_active_choice() {
79        let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
80        assert_eq!(dialog.handle_key(KeyCode::Enter), DialogEvent::ConfirmDo);
81
82        let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
83        dialog.handle_key(KeyCode::Right);
84        assert_eq!(
85            dialog.handle_key(KeyCode::Enter),
86            DialogEvent::ConfirmIgnore
87        );
88    }
89
90    #[test]
91    fn esc_dismisses_dialog() {
92        let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
93        assert_eq!(dialog.handle_key(KeyCode::Esc), DialogEvent::Dismiss);
94        assert!(!dialog.is_active());
95    }
96}