Add failed operation dialog and dialog queue

This commit is contained in:
Jeremy Soller 2024-02-27 13:48:12 -07:00
parent 01a2e13e56
commit 8ab15027a5
No known key found for this signature in database
GPG key ID: D02FD439211AF56F

View file

@ -18,7 +18,7 @@ use cosmic::{
use notify::Watcher; use notify::Watcher;
use std::{ use std::{
any::TypeId, any::TypeId,
collections::{BTreeMap, HashMap, HashSet}, collections::{BTreeMap, HashMap, HashSet, VecDeque},
env, fs, env, fs,
path::PathBuf, path::PathBuf,
process, time, process, time,
@ -110,7 +110,7 @@ pub enum Message {
Cut(Option<segmented_button::Entity>), Cut(Option<segmented_button::Entity>),
DialogCancel, DialogCancel,
DialogComplete, DialogComplete,
DialogPage(DialogPage), DialogUpdate(DialogPage),
Key(Modifiers, Key), Key(Modifiers, Key),
Modifiers(Modifiers), Modifiers(Modifiers),
MoveToTrash(Option<segmented_button::Entity>), MoveToTrash(Option<segmented_button::Entity>),
@ -156,6 +156,7 @@ impl ContextPage {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum DialogPage { pub enum DialogPage {
FailedOperation(u64),
NewItem { NewItem {
parent: PathBuf, parent: PathBuf,
name: String, name: String,
@ -189,7 +190,7 @@ pub struct App {
config: Config, config: Config,
app_themes: Vec<String>, app_themes: Vec<String>,
context_page: ContextPage, context_page: ContextPage,
dialog_page: Option<DialogPage>, dialog_pages: VecDeque<DialogPage>,
dialog_text_input: widget::Id, dialog_text_input: widget::Id,
key_binds: HashMap<KeyBind, Action>, key_binds: HashMap<KeyBind, Action>,
modifiers: Modifiers, modifiers: Modifiers,
@ -512,7 +513,7 @@ impl Application for App {
config: flags.config, config: flags.config,
app_themes, app_themes,
context_page: ContextPage::Settings, context_page: ContextPage::Settings,
dialog_page: None, dialog_pages: VecDeque::new(),
dialog_text_input: widget::Id::unique(), dialog_text_input: widget::Id::unique(),
key_binds: key_binds(), key_binds: key_binds(),
modifiers: Modifiers::empty(), modifiers: Modifiers::empty(),
@ -581,7 +582,7 @@ impl Application for App {
let entity = self.tab_model.active(); let entity = self.tab_model.active();
// Close dialog if open // Close dialog if open
if self.dialog_page.take().is_some() { if self.dialog_pages.pop_front().is_some() {
return Command::none(); return Command::none();
} }
@ -647,11 +648,14 @@ impl Application for App {
log::warn!("TODO: CUT"); log::warn!("TODO: CUT");
} }
Message::DialogCancel => { Message::DialogCancel => {
self.dialog_page = None; self.dialog_pages.pop_front();
} }
Message::DialogComplete => { Message::DialogComplete => {
if let Some(dialog_page) = self.dialog_page.take() { if let Some(dialog_page) = self.dialog_pages.pop_front() {
match dialog_page { match dialog_page {
DialogPage::FailedOperation(id) => {
log::warn!("TODO: retry operation {}", id);
}
DialogPage::NewItem { parent, name, dir } => { DialogPage::NewItem { parent, name, dir } => {
let path = parent.join(name); let path = parent.join(name);
self.operation(if dir { self.operation(if dir {
@ -663,8 +667,9 @@ impl Application for App {
} }
} }
} }
Message::DialogPage(dialog_page) => { Message::DialogUpdate(dialog_page) => {
self.dialog_page = Some(dialog_page); //TODO: panicless way to do this?
self.dialog_pages[0] = dialog_page;
} }
Message::Key(modifiers, key) => { Message::Key(modifiers, key) => {
let entity = self.tab_model.active(); let entity = self.tab_model.active();
@ -694,17 +699,15 @@ impl Application for App {
} }
} }
Message::NewItem(entity_opt, dir) => { Message::NewItem(entity_opt, dir) => {
if self.dialog_page.is_none() { let entity = entity_opt.unwrap_or_else(|| self.tab_model.active());
let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) { if let Location::Path(path) = &tab.location {
if let Location::Path(path) = &tab.location { self.dialog_pages.push_back(DialogPage::NewItem {
self.dialog_page = Some(DialogPage::NewItem { parent: path.clone(),
parent: path.clone(), name: String::new(),
name: String::new(), dir,
dir, });
}); return widget::text_input::focus(self.dialog_text_input.clone());
return widget::text_input::focus(self.dialog_text_input.clone());
}
} }
} }
} }
@ -756,8 +759,8 @@ impl Application for App {
} }
Message::PendingError(id, err) => { Message::PendingError(id, err) => {
if let Some((op, _)) = self.pending_operations.remove(&id) { if let Some((op, _)) = self.pending_operations.remove(&id) {
//TODO: dialog?
self.failed_operations.insert(id, (op, err)); self.failed_operations.insert(id, (op, err));
self.dialog_pages.push_back(DialogPage::FailedOperation(id));
} }
} }
Message::PendingProgress(id, new_progress) => { Message::PendingProgress(id, new_progress) => {
@ -981,7 +984,7 @@ impl Application for App {
} }
fn dialog(&self) -> Option<Element<Message>> { fn dialog(&self) -> Option<Element<Message>> {
let dialog_page = match &self.dialog_page { let dialog_page = match self.dialog_pages.front() {
Some(some) => some, Some(some) => some,
None => return None, None => return None,
}; };
@ -989,6 +992,19 @@ impl Application for App {
let cosmic_theme::Spacing { space_xxs, .. } = self.core().system_theme().cosmic().spacing; let cosmic_theme::Spacing { space_xxs, .. } = self.core().system_theme().cosmic().spacing;
let dialog = match dialog_page { 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 } => { DialogPage::NewItem { parent, name, dir } => {
let mut dialog = widget::dialog(if *dir { let mut dialog = widget::dialog(if *dir {
fl!("create-new-folder") fl!("create-new-folder")
@ -1045,7 +1061,7 @@ impl Application for App {
widget::text_input("", name.as_str()) widget::text_input("", name.as_str())
.id(self.dialog_text_input.clone()) .id(self.dialog_text_input.clone())
.on_input(move |name| { .on_input(move |name| {
Message::DialogPage(DialogPage::NewItem { Message::DialogUpdate(DialogPage::NewItem {
parent: parent.clone(), parent: parent.clone(),
name, name,
dir: *dir, dir: *dir,