diff options
| author | Joe Carstairs <me@joeac.net> | 2026-02-07 11:52:08 +0000 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2026-02-07 12:02:27 +0000 |
| commit | 1664e741ad35ce52a01788c34029f0b2ea477e32 (patch) | |
| tree | dd6bd7c83a7e834c75815a786d67b5188cdd1f48 /schist_desktop_gui/src/gui/screens/files_screen | |
| parent | 179878d12ba10ac242da2044f4c6dfe4d4829e59 (diff) | |
task-001: can navigate file screen options with keyboard
Diffstat (limited to 'schist_desktop_gui/src/gui/screens/files_screen')
| -rw-r--r-- | schist_desktop_gui/src/gui/screens/files_screen/update_files_screen.rs | 143 | ||||
| -rw-r--r-- | schist_desktop_gui/src/gui/screens/files_screen/view_files_screen.rs | 101 |
2 files changed, 92 insertions, 152 deletions
diff --git a/schist_desktop_gui/src/gui/screens/files_screen/update_files_screen.rs b/schist_desktop_gui/src/gui/screens/files_screen/update_files_screen.rs index 9c45d6e..82ca7b6 100644 --- a/schist_desktop_gui/src/gui/screens/files_screen/update_files_screen.rs +++ b/schist_desktop_gui/src/gui/screens/files_screen/update_files_screen.rs @@ -4,34 +4,20 @@ use itertools::Itertools; use crate::{ database_connection::DatabaseConnectionResult, dialog::{import_from_actualbudget_dialog, new_file_dialog, pick_file_dialog}, + gui::components::{navigation, Panel}, paths::get_schist_database_directory, traits::Component, DatabaseConnection, }; -use super::{Action, FilesScreen, Message}; +use super::{Action, FilesScreen, Message, OptionId}; impl<'a> Component<'a, Message, Action> for FilesScreen { fn update(&mut self, message: Message) -> Action { match message { - Message::NewFile => match self.new_file() { - Some(Ok(file)) => Action::OpenedFile(file), - Some(Err(_)) | None => Action::None, - }, - - Message::OpenFile(file_path) => self - .open_file(file_path) - .map_or(Action::None, Action::OpenedFile), - - Message::PickFile => match self.pick_file() { - Some(Ok(file)) => Action::OpenedFile(file), - Some(Err(_)) | None => Action::None, - }, - - Message::ImportFromActualbudget => match self.import_from_actualbudget() { - Some(Ok(file)) => Action::OpenedFile(file), - Some(Err(_)) | None => Action::None, - }, + Message::NavigationMessage(message) => self.update_options(message), + Message::NextOption => self.update_options(navigation::Message::SelectNext), + Message::PrevOption => self.update_options(navigation::Message::SelectPrev), } } } @@ -41,13 +27,12 @@ impl FilesScreen { &mut self, ) -> Option<Result<DatabaseConnection, (std::path::PathBuf, anyhow::Error)>> { pick_file_dialog(get_schist_database_directory().ok()).map(|db_connection_result| { - db_connection_result.ok().inspect_err(|(path, err)| { - self.open_file_err = Some((path.clone(), err.to_string())); - rfd::MessageDialog::new() - .set_title("Failed to import from Actualbudget") - .set_level(rfd::MessageLevel::Error) - .set_description(format!("{}", err.chain().join("\n | "))) - .show(); + db_connection_result.ok().inspect_err(|(_path, err)| { + self.report_err( + super::OptionId::PickFile, + format!("{}", err.chain().join("\n | ")).as_str(), + "Failed to open file", + ); }) }) } @@ -59,12 +44,11 @@ impl FilesScreen { DatabaseConnection::establish(file_path.clone()) .ok() .inspect_err(|(_path, err)| { - self.open_file_err = Some((file_path, err.to_string())); - rfd::MessageDialog::new() - .set_title("Failed to import from Actualbudget") - .set_level(rfd::MessageLevel::Error) - .set_description(format!("{}", err.chain().join("\n | "))) - .show(); + self.report_err( + OptionId::OpenFile(file_path), + format!("{}", err.chain().join("\n | ")).as_str(), + "Failed to open file", + ); }) } @@ -72,13 +56,12 @@ impl FilesScreen { &mut self, ) -> Option<Result<DatabaseConnection, (std::path::PathBuf, anyhow::Error)>> { new_file_dialog(get_schist_database_directory().ok()).map(|result| { - result.ok().inspect_err(|(path, err)| { - self.new_file_err = Some((path.clone(), err.to_string())); - rfd::MessageDialog::new() - .set_title("Failed to import from Actualbudget") - .set_level(rfd::MessageLevel::Error) - .set_description(format!("{}", err.chain().join("\n | "))) - .show(); + result.ok().inspect_err(|(_path, err)| { + self.report_err( + OptionId::NewFile, + "Failed to create new file", + format!("{}", err.chain().join("\n | ")).as_str(), + ); }) }) } @@ -86,13 +69,12 @@ impl FilesScreen { fn import_from_actualbudget(&mut self) -> Option<anyhow::Result<DatabaseConnection>> { match import_from_actualbudget_dialog() { Some(Ok(state)) => self.new_file_with_state(&state), - Some(Err((path, err))) => Some({ - self.open_file_err = Some((path, err.to_string())); - rfd::MessageDialog::new() - .set_title("Failed to import from Actualbudget") - .set_level(rfd::MessageLevel::Error) - .set_description(format!("{}", err.chain().join("\n | "))) - .show(); + Some(Err((_path, err))) => Some({ + self.report_err( + OptionId::ImportFromActualbudget, + "Failed to import from Actualbudget", + format!("{}", err.chain().join("\n | ")).as_str(), + ); Err(err) }), None => None, @@ -110,16 +92,71 @@ impl FilesScreen { export_schist_state(state, &mut file.connection).ok()?; Ok(file) }), - Some(Err((path, err))) => Some({ - self.new_file_err = Some((path, err.to_string())); - rfd::MessageDialog::new() - .set_title("Failed to import from Actualbudget") - .set_level(rfd::MessageLevel::Error) - .set_description(format!("{}", err.chain().join("\n | "))) - .show(); + Some(Err((_path, err))) => Some({ + self.report_err( + OptionId::NewFile, + format!("{}", err.chain().join("\n | ")).as_str(), + "Failed to create new file", + ); Err(err) }), None => None, } } + + fn report_err(&mut self, id: OptionId, err: &str, dialog_title: &str) { + let old_panel = self.options.find(|o| o.id == id); + let file_panel_with_err = Panel::new( + id.clone(), + old_panel.as_ref().map(|p| p.name.as_str()).unwrap_or(""), + old_panel.as_ref().map(|p| p.small.clone()).flatten(), + Some(err.to_string()), + ); + self.options + .replace_first(|o| o.id == id, &vec![file_panel_with_err]); + + rfd::MessageDialog::new() + .set_title(dialog_title) + .set_level(rfd::MessageLevel::Error) + .set_description(err) + .show(); + } + + fn update_options(&mut self, message: navigation::Message<Panel<OptionId>>) -> Action { + match self.options.update(message) { + navigation::Action::ActivateOption(option) => match option { + Panel { + id: OptionId::NewFile, + .. + } => match self.new_file() { + Some(Ok(file)) => Action::OpenedFile(file), + Some(Err(_)) | None => Action::None, + }, + + Panel { + id: OptionId::OpenFile(file_path), + .. + } => self + .open_file(file_path.clone()) + .map_or(Action::None, Action::OpenedFile), + + Panel { + id: OptionId::PickFile, + .. + } => match self.pick_file() { + Some(Ok(file)) => Action::OpenedFile(file), + Some(Err(_)) | None => Action::None, + }, + + Panel { + id: OptionId::ImportFromActualbudget, + .. + } => match self.import_from_actualbudget() { + Some(Ok(file)) => Action::OpenedFile(file), + Some(Err(_)) | None => Action::None, + }, + }, + navigation::Action::SelectOption(_) | navigation::Action::None => Action::None, + } + } } diff --git a/schist_desktop_gui/src/gui/screens/files_screen/view_files_screen.rs b/schist_desktop_gui/src/gui/screens/files_screen/view_files_screen.rs index 3cbd939..8ff9f63 100644 --- a/schist_desktop_gui/src/gui/screens/files_screen/view_files_screen.rs +++ b/schist_desktop_gui/src/gui/screens/files_screen/view_files_screen.rs @@ -1,106 +1,9 @@ -use std::path::PathBuf; - -use iced::widget::column; - -use crate::{ - gui::components::{panel_button, Text}, - style::*, - traits::Viewable, -}; +use crate::traits::Viewable; use super::{FilesScreen, Message}; impl<'a> Viewable<'a, Message> for FilesScreen { fn view(&'a self) -> iced::Element<'a, Message> { - let mut cols = Vec::new(); - if let Some(col) = self.view_new_file_err() { - cols.push(col); - }; - if let Some(col) = self.view_open_file_err() { - cols.push(col); - }; - cols.push(self.view_new_file_button()); - cols.push(self.view_open_file_button()); - cols.push(self.view_import_from_actualbudget_button()); - cols.append(&mut self.view_files()); - column(cols).padding(SPACING_LG).spacing(SPACING_MD).into() - } -} - -impl<'a> FilesScreen { - fn view_new_file_err(&'a self) -> Option<iced::Element<'a, Message>> { - self.new_file_err.as_ref().map(|(path, err)| { - let msg = format!("Failed to open new file {:#?}: {:#?}", path, err); - Text::new(&msg).danger().into() - }) - } - - fn view_open_file_err(&'a self) -> Option<iced::Element<'a, Message>> { - self.open_file_err - .as_ref() - .filter(|(file_path, _err)| !self.file_paths.iter().any(|fp| *fp == *file_path)) - .map(|(file_path, err)| { - let msg = format!("Failed to open new file {:#?}: {:#?}", file_path, err); - Text::new(&msg).danger().into() - }) - } - - fn view_files(&'a self) -> Vec<iced::Element<'a, Message>> { - self.file_paths - .iter() - .map(|f| { - view_file( - f, - self.open_file_err - .clone() - .filter(|(file, _err)| *file == *f) - .map(|(_file, err)| err), - ) - }) - .collect() - } - - fn view_new_file_button(&'a self) -> iced::Element<'a, Message> { - panel_button::<Text, Message>(Text::default("New file").into(), Message::NewFile).into() - } - - fn view_open_file_button(&'a self) -> iced::Element<'a, Message> { - panel_button::<Text, Message>(Text::default("Open file").into(), Message::PickFile).into() - } - - fn view_import_from_actualbudget_button(&'a self) -> iced::Element<'a, Message> { - panel_button::<Text, Message>( - Text::default("Import from Actualbudget").into(), - Message::ImportFromActualbudget, - ) - .into() + self.options.view().map(Message::NavigationMessage) } } - -fn view_file<'a>(file_path: &'a PathBuf, err: Option<String>) -> iced::Element<'a, Message> { - let mut cols: Vec<iced::Element<'a, Message>> = err - .map(|err| { - let msg = format!("Failed to open new file {:#?}: {:#?}", file_path, err); - vec![Text::new(&msg).danger().small().into()] - }) - .unwrap_or_else(Vec::new); - - cols.push( - Text::default(file_path.to_str().unwrap_or("")) - .small() - .weak() - .into(), - ); - - cols.push( - Text::default( - file_path - .file_name() - .map(|os_str| os_str.to_str().unwrap_or("[invalid Unicode]")) - .unwrap_or("[invalid filename]"), - ) - .into(), - ); - - panel_button(column(cols), Message::OpenFile(file_path.clone())).into() -} |
