rust_kanban/ui/rendering/view/
load_cloud_save.rs

1use 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}