diff --git a/src/app.rs b/src/app.rs index d5cba63..160d572 100644 --- a/src/app.rs +++ b/src/app.rs @@ -63,11 +63,10 @@ use trash::TrashItem; #[cfg(feature = "wayland")] use wayland_client::{protocol::wl_output::WlOutput, Proxy}; -use crate::mime_app::MimeApp; -use crate::operation::{OperationError, OperationErrorType}; use crate::{ clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste}, config::{AppTheme, Config, DesktopConfig, Favorite, IconSizes, TabConfig, TypeToSearch}, + dialog::{DialogKind, DialogMessage}, fl, home_dir, key_bind::key_binds, localize::LANGUAGE_SORTER, @@ -77,6 +76,11 @@ use crate::{ spawn_detached::spawn_detached, tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION}, }; +use crate::{ + dialog::Dialog, + operation::{OperationError, OperationErrorType}, +}; +use crate::{dialog::DialogResult, mime_app::MimeApp}; #[derive(Clone, Debug)] pub enum Mode { @@ -291,11 +295,13 @@ pub enum Message { DesktopViewOptions, DialogCancel, DialogComplete, + FileDialogMessage(DialogMessage), DialogPush(DialogPage), DialogUpdate(DialogPage), DialogUpdateComplete(DialogPage), ExtractHere(Option), ExtractTo(Option), + ExtractToResult(DialogResult), #[cfg(all(feature = "desktop", feature = "wayland"))] Focused(window::Id), Key(Modifiers, Key, Option), @@ -434,11 +440,6 @@ pub enum DialogPage { archive_type: ArchiveType, password: Option, }, - ExtractTo { - paths: Vec, - to: PathBuf, - password: Option, - }, EmptyTrash, FailedOperation(u64), ExtractPassword { @@ -503,6 +504,7 @@ pub enum WindowKind { Desktop(Entity), DesktopViewOptions, Preview(Option, PreviewKind), + FileDialog(Option>), } pub struct WatcherWrapper { @@ -570,6 +572,7 @@ pub struct App { nav_drag_id: DragId, tab_drag_id: DragId, auto_scroll_speed: Option, + file_dialog_opt: Option>, } impl App { @@ -1794,6 +1797,7 @@ impl Application for App { nav_drag_id: DragId::new(), tab_drag_id: DragId::new(), auto_scroll_speed: None, + file_dialog_opt: None, }; let mut commands = vec![app.update_config()]; @@ -2237,17 +2241,6 @@ impl Application for App { DialogPage::EmptyTrash => { self.operation(Operation::EmptyTrash); } - DialogPage::ExtractTo { - paths, - to, - password, - } => { - self.operation(Operation::Extract { - paths, - to, - password: None, - }); - } DialogPage::FailedOperation(id) => { log::warn!("TODO: retry operation {}", id); } @@ -2402,13 +2395,47 @@ impl Application for App { .and_then(|first| first.parent()) .map(|parent| parent.to_path_buf()) { - self.dialog_pages.push_back(DialogPage::ExtractTo { - paths, - to: destination, - password: None, - }); + let (dialog, command) = Dialog::new( + DialogKind::OpenFolder, + Some(destination), + Message::FileDialogMessage, + Message::ExtractToResult, + ); + self.windows + .insert(dialog.window_id(), WindowKind::FileDialog(Some(paths))); + self.file_dialog_opt = Some(dialog); + return command; }; } + Message::ExtractToResult(result) => { + match result { + DialogResult::Cancel => {} + DialogResult::Open(selected_paths) => { + let mut archive_paths = None; + if let Some(file_dialog) = &self.file_dialog_opt { + let window = self.windows.remove(&file_dialog.window_id()); + if let Some(WindowKind::FileDialog(paths)) = window { + archive_paths = paths; + } + } + if let Some(archive_paths) = archive_paths { + if !selected_paths.is_empty() { + self.operation(Operation::Extract { + paths: archive_paths, + to: selected_paths[0].clone(), + password: None, + }); + } + } + } + } + self.file_dialog_opt = None; + } + Message::FileDialogMessage(dialog_message) => { + if let Some(dialog) = &mut self.file_dialog_opt { + return dialog.update(dialog_message); + } + } Message::Key(modifiers, key, text) => { let entity = self.tab_model.active(); for (key_bind, action) in self.key_binds.iter() { @@ -2935,7 +2962,7 @@ impl Application for App { self.dialog_pages.push_back(match err.kind { OperationErrorType::Generic(_) => DialogPage::FailedOperation(id), OperationErrorType::PasswordRequired => DialogPage::ExtractPassword { - id: id, + id, password: String::from(""), }, }); @@ -4121,30 +4148,6 @@ impl Application for App { .secondary_action( widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel), ), - DialogPage::ExtractTo { - paths, - to, - password, - } => widget::dialog() - .title(fl!("extract-to")) - .body(fl!("extract-to-prompt")) - .control( - widget::text_input("Enter the path to extract to", to.to_string_lossy()) - .on_input(move |to| { - Message::DialogUpdate(DialogPage::ExtractTo { - paths: paths.clone(), - to: PathBuf::from(to), - password: password.clone(), - }) - }), - ) - .primary_action( - widget::button::suggested(fl!("extract-here")) - .on_press(Message::DialogComplete), - ) - .secondary_action( - widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel), - ), DialogPage::FailedOperation(id) => { //TODO: try next dialog page (making sure index is used by Dialog messages)? let (operation, _, err) = self.failed_operations.get(id)?; @@ -4935,6 +4938,10 @@ impl Application for App { Some(WindowKind::Preview(entity_opt, kind)) => self .preview(entity_opt, kind, false) .map(|x| Message::TabMessage(*entity_opt, x)), + Some(WindowKind::FileDialog(..)) => match &self.file_dialog_opt { + Some(dialog) => return dialog.view(id), + None => widget::text("Unknown window ID").into(), + }, None => { //TODO: distinct views per monitor in desktop mode return self.view_main().map(|message| match message {