rust_kanban/ui/rendering/view/
load_a_save.rs

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