From 8ab15027a521713850384fa87666bb9974f2666b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Feb 2024 13:48:12 -0700 Subject: [PATCH] Add failed operation dialog and dialog queue --- src/app.rs | 62 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/src/app.rs b/src/app.rs index 98c5865..5a68d88 100644 --- a/src/app.rs +++ b/src/app.rs @@ -18,7 +18,7 @@ use cosmic::{ use notify::Watcher; use std::{ any::TypeId, - collections::{BTreeMap, HashMap, HashSet}, + collections::{BTreeMap, HashMap, HashSet, VecDeque}, env, fs, path::PathBuf, process, time, @@ -110,7 +110,7 @@ pub enum Message { Cut(Option), DialogCancel, DialogComplete, - DialogPage(DialogPage), + DialogUpdate(DialogPage), Key(Modifiers, Key), Modifiers(Modifiers), MoveToTrash(Option), @@ -156,6 +156,7 @@ impl ContextPage { #[derive(Clone, Debug, Eq, PartialEq)] pub enum DialogPage { + FailedOperation(u64), NewItem { parent: PathBuf, name: String, @@ -189,7 +190,7 @@ pub struct App { config: Config, app_themes: Vec, context_page: ContextPage, - dialog_page: Option, + dialog_pages: VecDeque, dialog_text_input: widget::Id, key_binds: HashMap, modifiers: Modifiers, @@ -512,7 +513,7 @@ impl Application for App { config: flags.config, app_themes, context_page: ContextPage::Settings, - dialog_page: None, + dialog_pages: VecDeque::new(), dialog_text_input: widget::Id::unique(), key_binds: key_binds(), modifiers: Modifiers::empty(), @@ -581,7 +582,7 @@ impl Application for App { let entity = self.tab_model.active(); // Close dialog if open - if self.dialog_page.take().is_some() { + if self.dialog_pages.pop_front().is_some() { return Command::none(); } @@ -647,11 +648,14 @@ impl Application for App { log::warn!("TODO: CUT"); } Message::DialogCancel => { - self.dialog_page = None; + self.dialog_pages.pop_front(); } Message::DialogComplete => { - if let Some(dialog_page) = self.dialog_page.take() { + if let Some(dialog_page) = self.dialog_pages.pop_front() { match dialog_page { + DialogPage::FailedOperation(id) => { + log::warn!("TODO: retry operation {}", id); + } DialogPage::NewItem { parent, name, dir } => { let path = parent.join(name); self.operation(if dir { @@ -663,8 +667,9 @@ impl Application for App { } } } - Message::DialogPage(dialog_page) => { - self.dialog_page = Some(dialog_page); + Message::DialogUpdate(dialog_page) => { + //TODO: panicless way to do this? + self.dialog_pages[0] = dialog_page; } Message::Key(modifiers, key) => { let entity = self.tab_model.active(); @@ -694,17 +699,15 @@ impl Application for App { } } Message::NewItem(entity_opt, dir) => { - if self.dialog_page.is_none() { - let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); - if let Some(tab) = self.tab_model.data_mut::(entity) { - if let Location::Path(path) = &tab.location { - self.dialog_page = Some(DialogPage::NewItem { - parent: path.clone(), - name: String::new(), - dir, - }); - return widget::text_input::focus(self.dialog_text_input.clone()); - } + let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); + if let Some(tab) = self.tab_model.data_mut::(entity) { + if let Location::Path(path) = &tab.location { + self.dialog_pages.push_back(DialogPage::NewItem { + parent: path.clone(), + name: String::new(), + dir, + }); + return widget::text_input::focus(self.dialog_text_input.clone()); } } } @@ -756,8 +759,8 @@ impl Application for App { } Message::PendingError(id, err) => { if let Some((op, _)) = self.pending_operations.remove(&id) { - //TODO: dialog? self.failed_operations.insert(id, (op, err)); + self.dialog_pages.push_back(DialogPage::FailedOperation(id)); } } Message::PendingProgress(id, new_progress) => { @@ -981,7 +984,7 @@ impl Application for App { } fn dialog(&self) -> Option> { - let dialog_page = match &self.dialog_page { + let dialog_page = match self.dialog_pages.front() { Some(some) => some, None => return None, }; @@ -989,6 +992,19 @@ impl Application for App { let cosmic_theme::Spacing { space_xxs, .. } = self.core().system_theme().cosmic().spacing; let dialog = match dialog_page { + DialogPage::FailedOperation(id) => { + //TODO: try next dialog page (making sure index is used by Dialog messages)? + let (operation, err) = self.failed_operations.get(id)?; + + //TODO: nice description of error + widget::dialog("Failed operation") + .body(format!("{:#?}\n{}", operation, err)) + .icon(widget::icon::from_name("dialog-error").size(64)) + //TODO: retry action + .primary_action( + widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel), + ) + } DialogPage::NewItem { parent, name, dir } => { let mut dialog = widget::dialog(if *dir { fl!("create-new-folder") @@ -1045,7 +1061,7 @@ impl Application for App { widget::text_input("", name.as_str()) .id(self.dialog_text_input.clone()) .on_input(move |name| { - Message::DialogPage(DialogPage::NewItem { + Message::DialogUpdate(DialogPage::NewItem { parent: parent.clone(), name, dir: *dir,