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 #[allow(clippy::wildcard_imports)]
68 use super::*;
69
70 #[test]
71 fn dialog_choice_toggles() {
72 let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
73 assert_eq!(dialog.choice, DialogChoice::DoRollover);
74 dialog.handle_key(KeyCode::Tab);
75 assert_eq!(dialog.choice, DialogChoice::Ignore);
76 }
77
78 #[test]
79 fn enter_confirms_active_choice() {
80 let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
81 assert_eq!(dialog.handle_key(KeyCode::Enter), DialogEvent::ConfirmDo);
82
83 let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
84 dialog.handle_key(KeyCode::Right);
85 assert_eq!(
86 dialog.handle_key(KeyCode::Enter),
87 DialogEvent::ConfirmIgnore
88 );
89 }
90
91 #[test]
92 fn esc_dismisses_dialog() {
93 let mut dialog = RolloverDialog::new(vec![("Cycle 1".into(), "Cycle 2".into(), 2)]);
94 assert_eq!(dialog.handle_key(KeyCode::Esc), DialogEvent::Dismiss);
95 assert!(!dialog.is_active());
96 }
97}