Merge pull request #896 from jasonrhansen/extract-archives

Use Open Folder dialog for Extract To
This commit is contained in:
Jeremy Soller 2025-03-24 01:34:49 +00:00 committed by GitHub
commit 17971a5d70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 52 deletions

View file

@ -43,7 +43,7 @@ create-archive = Create archive
## Extract Dialog
extract-password-required = Password required
extract-to = Extract To...
extract-to-prompt = Input a location to extract the archive to.
extract-to-title = Extract to folder
## Empty Trash Dialog
empty-trash = Empty trash

View file

@ -43,7 +43,6 @@ create-archive = Tömörített fájl létrehozása
## Extract Dialog
extract-password-required = Jelszó szükséges
extract-to = Kibontás ide...
extract-to-prompt = Adja meg a helyet, ahová ki szeretné bontani a tömörített fájlt.
## Empty Trash Dialog
empty-trash = Kuka ürítése
@ -321,4 +320,4 @@ sort-z-a = Z-A
sort-newest-first = Legújabb előre
sort-oldest-first = Legrégibb előre
sort-smallest-to-largest = Legkisebbtől a legnagyobbig
sort-largest-to-smallest = Legnagyobbtól a legkisebbig
sort-largest-to-smallest = Legnagyobbtól a legkisebbig

View file

@ -43,7 +43,6 @@ create-archive = Maak een archiefbestand
## Extract Dialog
extract-password-required = Wachtwoord vereist
extract-to = Uitpakken naar...
extract-to-prompt = Voer een locatie in om dit archief naar uit te pakken.
## Empty Trash Dialog
empty-trash = Prullenbak legen?

View file

@ -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<Entity>),
ExtractTo(Option<Entity>),
ExtractToResult(DialogResult),
#[cfg(all(feature = "desktop", feature = "wayland"))]
Focused(window::Id),
Key(Modifiers, Key, Option<SmolStr>),
@ -434,11 +440,6 @@ pub enum DialogPage {
archive_type: ArchiveType,
password: Option<String>,
},
ExtractTo {
paths: Vec<PathBuf>,
to: PathBuf,
password: Option<String>,
},
EmptyTrash,
FailedOperation(u64),
ExtractPassword {
@ -503,6 +504,7 @@ pub enum WindowKind {
Desktop(Entity),
DesktopViewOptions,
Preview(Option<Entity>, PreviewKind),
FileDialog(Option<Vec<PathBuf>>),
}
pub struct WatcherWrapper {
@ -570,6 +572,7 @@ pub struct App {
nav_drag_id: DragId,
tab_drag_id: DragId,
auto_scroll_speed: Option<i16>,
file_dialog_opt: Option<Dialog<Message>>,
}
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,49 @@ 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 (mut dialog, dialog_task) = Dialog::new(
DialogKind::OpenFolder,
Some(destination),
Message::FileDialogMessage,
Message::ExtractToResult,
);
let set_title_task = dialog.set_title(fl!("extract-to-title"));
dialog.set_accept_label(fl!("extract-here"));
self.windows
.insert(dialog.window_id(), WindowKind::FileDialog(Some(paths)));
self.file_dialog_opt = Some(dialog);
return Task::batch([set_title_task, dialog_task]);
};
}
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() {
@ -2887,6 +2916,12 @@ impl Application for App {
)
.map(cosmic::Action::App),
);
} else {
commands.push(
self.toasts
.push(widget::toaster::Toast::new(description))
.map(cosmic::Action::App),
);
}
}
@ -2935,7 +2970,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 +4156,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 +4946,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 {