rust_kanban/ui/rendering/view/
load_a_save.rs1use crate::{
2 app::{
3 state::{Focus, KeyBindingEnum},
4 App,
5 },
6 constants::LIST_SELECTED_SYMBOL,
7 io::data_handler::get_available_local_save_files,
8 ui::{
9 rendering::{
10 common::{render_body, render_close_button},
11 utils::{
12 calculate_mouse_list_select_index, check_if_active_and_get_style,
13 check_if_mouse_is_in_area,
14 },
15 view::LoadASave,
16 },
17 Renderable,
18 },
19};
20use ratatui::{
21 layout::{Alignment, Constraint, Direction, Layout},
22 text::{Line, Span},
23 widgets::{Block, BorderType, Borders, List, ListItem, Paragraph},
24 Frame,
25};
26
27impl Renderable for LoadASave {
28 fn render(rect: &mut Frame, app: &mut App, is_active: bool) {
29 let main_chunks = {
30 Layout::default()
31 .direction(Direction::Horizontal)
32 .constraints([Constraint::Length(35), Constraint::Fill(1)].as_ref())
33 .split(rect.area())
34 };
35 let chunks = Layout::default()
36 .direction(Direction::Vertical)
37 .constraints(
38 [
39 Constraint::Length(3),
40 Constraint::Fill(1),
41 Constraint::Length(9),
42 ]
43 .as_ref(),
44 )
45 .split(main_chunks[0]);
46
47 let preview_chunks = Layout::default()
48 .direction(Direction::Vertical)
49 .constraints([Constraint::Length(3), Constraint::Fill(1)].as_ref())
50 .split(main_chunks[1]);
51
52 let title_bar_chunks = Layout::default()
53 .direction(Direction::Horizontal)
54 .constraints([Constraint::Fill(1), Constraint::Length(3)].as_ref())
55 .split(preview_chunks[0]);
56
57 let general_style = check_if_active_and_get_style(
58 is_active,
59 app.current_theme.inactive_text_style,
60 app.current_theme.general_style,
61 );
62 let help_key_style = check_if_active_and_get_style(
63 is_active,
64 app.current_theme.inactive_text_style,
65 app.current_theme.help_key_style,
66 );
67 let help_text_style = check_if_active_and_get_style(
68 is_active,
69 app.current_theme.inactive_text_style,
70 app.current_theme.help_text_style,
71 );
72 let error_text_style = check_if_active_and_get_style(
73 is_active,
74 app.current_theme.inactive_text_style,
75 app.current_theme.error_text_style,
76 );
77 let list_select_style = check_if_active_and_get_style(
78 is_active,
79 app.current_theme.inactive_text_style,
80 app.current_theme.list_select_style,
81 );
82
83 let title_paragraph = Paragraph::new("Load a Save (Local)")
84 .alignment(Alignment::Center)
85 .block(
86 Block::default()
87 .borders(Borders::ALL)
88 .border_type(BorderType::Rounded),
89 )
90 .style(general_style);
91 rect.render_widget(title_paragraph, chunks[0]);
92
93 let item_list = get_available_local_save_files(&app.config);
94 let item_list = item_list.unwrap_or_default();
95 if item_list.is_empty() {
96 let no_saves_paragraph = Paragraph::new("No saves found")
97 .alignment(Alignment::Center)
98 .block(
99 Block::default()
100 .borders(Borders::ALL)
101 .border_type(BorderType::Rounded),
102 )
103 .style(error_text_style);
104 rect.render_widget(no_saves_paragraph, chunks[1]);
105 } else {
106 let items: Vec<ListItem> = item_list
107 .iter()
108 .map(|i| ListItem::new(i.to_string()))
109 .collect();
110 let choice_list = List::new(items)
111 .block(
112 Block::default()
113 .title(format!("Available Saves ({})", item_list.len()))
114 .borders(Borders::ALL)
115 .border_type(BorderType::Rounded),
116 )
117 .highlight_style(list_select_style)
118 .highlight_symbol(LIST_SELECTED_SYMBOL)
119 .style(general_style);
120
121 if is_active
122 && check_if_mouse_is_in_area(&app.state.current_mouse_coordinates, &chunks[1])
123 {
124 app.state.mouse_focus = Some(Focus::LoadSave);
125 app.state.set_focus(Focus::LoadSave);
126 calculate_mouse_list_select_index(
127 app.state.current_mouse_coordinates.1,
128 &item_list,
129 chunks[1],
130 &mut app.state.app_list_states.load_save,
131 );
132 }
133 rect.render_stateful_widget(
134 choice_list,
135 chunks[1],
136 &mut app.state.app_list_states.load_save,
137 );
138 }
139
140 let up_key = app
141 .get_first_keybinding(KeyBindingEnum::Up)
142 .unwrap_or("".to_string());
143 let down_key = app
144 .get_first_keybinding(KeyBindingEnum::Down)
145 .unwrap_or("".to_string());
146 let delete_key = app
147 .get_first_keybinding(KeyBindingEnum::DeleteCard)
148 .unwrap_or("".to_string());
149 let accept_key = app
150 .get_first_keybinding(KeyBindingEnum::Accept)
151 .unwrap_or("".to_string());
152 let cancel_key = app
153 .get_first_keybinding(KeyBindingEnum::GoToPreviousViewOrCancel)
154 .unwrap_or("".to_string());
155
156 let help_text = Line::from(vec![
157 Span::styled("Use ", help_text_style),
158 Span::styled(&up_key, help_key_style),
159 Span::styled(" or ", help_text_style),
160 Span::styled(&down_key, help_key_style),
161 Span::styled(" to navigate. Press ", help_text_style),
162 Span::styled(accept_key, help_key_style),
163 Span::styled(" to Load the selected save file. Press ", help_text_style),
164 Span::styled(cancel_key, help_key_style),
165 Span::styled(" to cancel. Press ", help_text_style),
166 Span::styled(delete_key, help_key_style),
167 Span::styled(
168 " to delete a save file. If using a mouse click on a save file to preview",
169 help_text_style,
170 ),
171 ]);
172 let help_paragraph = Paragraph::new(help_text)
173 .alignment(Alignment::Center)
174 .block(
175 Block::default()
176 .borders(Borders::ALL)
177 .border_type(BorderType::Rounded),
178 )
179 .style(general_style)
180 .wrap(ratatui::widgets::Wrap { trim: true });
181 rect.render_widget(help_paragraph, chunks[2]);
182
183 if app.state.app_list_states.load_save.selected().is_none() {
184 let help_text = Line::from(vec![
185 Span::styled("Select a save file with ", help_text_style),
186 Span::styled(&up_key, help_key_style),
187 Span::styled(" or ", help_text_style),
188 Span::styled(&down_key, help_key_style),
189 Span::styled(
190 " to preview. Click on a save file to preview if using a mouse",
191 help_text_style,
192 ),
193 ]);
194 let preview_paragraph = Paragraph::new(help_text)
195 .alignment(Alignment::Center)
196 .block(
197 Block::default()
198 .borders(Borders::ALL)
199 .border_type(BorderType::Rounded),
200 )
201 .style(general_style)
202 .wrap(ratatui::widgets::Wrap { trim: true });
203 rect.render_widget(preview_paragraph, preview_chunks[1]);
204 } else if app.preview_boards_and_cards.is_none() {
205 let loading_text = if app.config.enable_mouse_support {
206 "Click on a save file to preview"
207 } else {
208 "Loading preview..."
209 };
210 let preview_paragraph = Paragraph::new(loading_text)
211 .alignment(Alignment::Center)
212 .block(
213 Block::default()
214 .borders(Borders::ALL)
215 .border_type(BorderType::Rounded),
216 )
217 .style(general_style)
218 .wrap(ratatui::widgets::Wrap { trim: true });
219 rect.render_widget(preview_paragraph, preview_chunks[1]);
220 } else {
221 render_body(rect, preview_chunks[1], app, true, is_active)
222 }
223
224 let preview_title_paragraph = if let Some(file_name) = &app.state.preview_file_name {
225 Paragraph::new("Previewing: ".to_string() + file_name)
226 .alignment(Alignment::Center)
227 .block(
228 Block::default()
229 .borders(Borders::ALL)
230 .border_type(BorderType::Rounded),
231 )
232 .style(general_style)
233 .wrap(ratatui::widgets::Wrap { trim: true })
234 } else {
235 Paragraph::new("Select a file to preview")
236 .alignment(Alignment::Center)
237 .block(
238 Block::default()
239 .borders(Borders::ALL)
240 .border_type(BorderType::Rounded),
241 )
242 .style(general_style)
243 .wrap(ratatui::widgets::Wrap { trim: true })
244 };
245
246 if app.config.enable_mouse_support {
247 rect.render_widget(preview_title_paragraph, title_bar_chunks[0]);
248 render_close_button(rect, app, is_active);
249 } else {
250 rect.render_widget(preview_title_paragraph, preview_chunks[0]);
251 }
252 }
253}