node_launchpad/components/popup/
reset_nodes.rs1use super::super::{utils::centered_rect_fixed, Component};
10use crate::{
11 action::{Action, OptionsActions},
12 mode::{InputMode, Scene},
13 style::{clear_area, EUCALYPTUS, GHOST_WHITE, INDIGO, LIGHT_PERIWINKLE, VIVID_SKY_BLUE},
14};
15use color_eyre::Result;
16use crossterm::event::{Event, KeyCode, KeyEvent};
17use ratatui::{prelude::*, widgets::*};
18use tui_input::{backend::crossterm::EventHandler, Input};
19
20const INPUT_SIZE: u16 = 5;
21const INPUT_AREA: u16 = INPUT_SIZE + 2; #[derive(Default)]
24pub struct ResetNodesPopup {
25 active: bool,
27 confirmation_input_field: Input,
28 can_reset: bool,
29}
30
31impl Component for ResetNodesPopup {
32 fn handle_key_events(&mut self, key: KeyEvent) -> Result<Vec<Action>> {
33 if !self.active {
34 return Ok(vec![]);
35 }
36 let send_back = match key.code {
37 KeyCode::Enter => {
38 if self.can_reset {
39 debug!("Got reset, sending Reset action and switching to Options");
40 vec![
41 Action::OptionsActions(OptionsActions::ResetNodes),
42 Action::SwitchScene(Scene::Options),
43 ]
44 } else {
45 vec![]
46 }
47 }
48 KeyCode::Esc => {
49 debug!("Got Esc, switching to Options");
50 vec![Action::SwitchScene(Scene::Options)]
51 }
52 KeyCode::Char(' ') => vec![],
53 KeyCode::Backspace => {
54 self.confirmation_input_field.handle_event(&Event::Key(key));
56 let input = self.confirmation_input_field.value().to_string();
57 self.can_reset = input.to_lowercase() == "reset";
58 vec![]
59 }
60 _ => {
61 if self.confirmation_input_field.value().chars().count() < INPUT_SIZE as usize {
63 self.confirmation_input_field.handle_event(&Event::Key(key));
64 }
65 let input = self.confirmation_input_field.value().to_string();
66 self.can_reset = input.to_lowercase() == "reset";
67 vec![]
68 }
69 };
70 Ok(send_back)
71 }
72
73 fn update(&mut self, action: Action) -> Result<Option<Action>> {
74 let send_back = match action {
75 Action::SwitchScene(scene) => match scene {
76 Scene::ResetNodesPopUp => {
77 self.active = true;
78 self.confirmation_input_field = self
79 .confirmation_input_field
80 .clone()
81 .with_value(String::new());
82 Some(Action::SwitchInputMode(InputMode::Entry))
85 }
86 _ => {
87 self.active = false;
88 None
89 }
90 },
91 _ => None,
92 };
93 Ok(send_back)
94 }
95
96 fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> {
97 if !self.active {
98 return Ok(());
99 }
100
101 let layer_zero = centered_rect_fixed(52, 15, area);
102
103 let layer_one = Layout::new(
104 Direction::Vertical,
105 [
106 Constraint::Length(2),
108 Constraint::Min(1),
110 Constraint::Length(1),
112 ],
113 )
114 .split(layer_zero);
115
116 let pop_up_border = Paragraph::new("").block(
118 Block::default()
119 .borders(Borders::ALL)
120 .title(" Reset Nodes ")
121 .bold()
122 .title_style(Style::new().fg(VIVID_SKY_BLUE))
123 .padding(Padding::uniform(2))
124 .border_style(Style::new().fg(VIVID_SKY_BLUE)),
125 );
126 clear_area(f, layer_zero);
127
128 let layer_two = Layout::new(
130 Direction::Vertical,
131 [
132 Constraint::Length(4),
134 Constraint::Length(2),
136 Constraint::Length(3),
138 Constraint::Length(3),
140 Constraint::Length(1),
142 ],
143 )
144 .split(layer_one[1]);
145
146 let prompt = Paragraph::new("Type in 'reset' and press Enter to Reset all your nodes")
147 .wrap(Wrap { trim: false })
148 .block(Block::new().padding(Padding::horizontal(2)))
149 .alignment(Alignment::Center)
150 .fg(GHOST_WHITE);
151
152 f.render_widget(prompt, layer_two[0]);
153
154 let spaces =
155 " ".repeat((INPUT_AREA - 1) as usize - self.confirmation_input_field.value().len());
156
157 let input = Paragraph::new(Span::styled(
158 format!("{}{} ", spaces, self.confirmation_input_field.value()),
159 Style::default().fg(VIVID_SKY_BLUE).bg(INDIGO).underlined(),
160 ))
161 .alignment(Alignment::Center);
162
163 f.render_widget(input, layer_two[1]);
164
165 let text = Paragraph::new("This will clear out all the nodes and all the stored data. You should still keep all your earned rewards.")
166 .wrap(Wrap { trim: false })
167 .block(Block::new().padding(Padding::horizontal(2)))
168 .alignment(Alignment::Center)
169 .fg(GHOST_WHITE);
170 f.render_widget(text, layer_two[2]);
171
172 let dash = Block::new()
173 .borders(Borders::BOTTOM)
174 .border_style(Style::new().fg(GHOST_WHITE));
175 f.render_widget(dash, layer_two[3]);
176
177 let buttons_layer =
178 Layout::horizontal(vec![Constraint::Percentage(50), Constraint::Percentage(50)])
179 .split(layer_two[4]);
180
181 let button_no = Line::from(vec![Span::styled(
182 "No, Cancel [Esc]",
183 Style::default().fg(LIGHT_PERIWINKLE),
184 )]);
185
186 f.render_widget(
187 Paragraph::new(button_no)
188 .block(Block::default().padding(Padding::horizontal(2)))
189 .alignment(Alignment::Left),
190 buttons_layer[0],
191 );
192
193 let button_yes = Line::from(vec![Span::styled(
194 "Reset Nodes [Enter]",
195 if self.can_reset {
196 Style::default().fg(EUCALYPTUS)
197 } else {
198 Style::default().fg(LIGHT_PERIWINKLE)
199 },
200 )])
201 .alignment(Alignment::Right);
202
203 f.render_widget(
204 Paragraph::new(button_yes)
205 .block(Block::default().padding(Padding::horizontal(2)))
206 .alignment(Alignment::Right),
207 buttons_layer[1],
208 );
209
210 f.render_widget(pop_up_border, layer_zero);
211
212 Ok(())
213 }
214}