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