Merge pull request #885 from johnoye742/master

Introduces feature mentioned in #749
This commit is contained in:
Jeremy Soller 2025-03-19 15:54:27 +00:00 committed by GitHub
commit ca7b55bf0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 0 deletions

View file

@ -42,6 +42,8 @@ create-archive = Create archive
## Extract Dialog ## Extract Dialog
extract-password-required = Password required extract-password-required = Password required
extract-to = Extract To...
extract-to-prompt = Input a location to extract the archive to.
## Empty Trash Dialog ## Empty Trash Dialog
empty-trash = Empty trash empty-trash = Empty trash

View file

@ -111,6 +111,7 @@ pub enum Action {
#[cfg(feature = "desktop")] #[cfg(feature = "desktop")]
ExecEntryAction(usize), ExecEntryAction(usize),
ExtractHere, ExtractHere,
ExtractTo,
Gallery, Gallery,
HistoryNext, HistoryNext,
HistoryPrevious, HistoryPrevious,
@ -173,6 +174,7 @@ impl Action {
} }
Action::EmptyTrash => Message::TabMessage(None, tab::Message::EmptyTrash), Action::EmptyTrash => Message::TabMessage(None, tab::Message::EmptyTrash),
Action::ExtractHere => Message::ExtractHere(entity_opt), Action::ExtractHere => Message::ExtractHere(entity_opt),
Action::ExtractTo => Message::ExtractTo(entity_opt),
#[cfg(feature = "desktop")] #[cfg(feature = "desktop")]
Action::ExecEntryAction(action) => { Action::ExecEntryAction(action) => {
Message::TabMessage(entity_opt, tab::Message::ExecEntryAction(None, *action)) Message::TabMessage(entity_opt, tab::Message::ExecEntryAction(None, *action))
@ -294,6 +296,7 @@ pub enum Message {
DialogUpdate(DialogPage), DialogUpdate(DialogPage),
DialogUpdateComplete(DialogPage), DialogUpdateComplete(DialogPage),
ExtractHere(Option<Entity>), ExtractHere(Option<Entity>),
ExtractTo(Option<Entity>),
#[cfg(all(feature = "desktop", feature = "wayland"))] #[cfg(all(feature = "desktop", feature = "wayland"))]
Focused(window::Id), Focused(window::Id),
Key(Modifiers, Key, Option<SmolStr>), Key(Modifiers, Key, Option<SmolStr>),
@ -432,6 +435,11 @@ pub enum DialogPage {
archive_type: ArchiveType, archive_type: ArchiveType,
password: Option<String>, password: Option<String>,
}, },
ExtractTo {
paths: Vec<PathBuf>,
to: PathBuf,
password: Option<String>
},
EmptyTrash, EmptyTrash,
FailedOperation(u64), FailedOperation(u64),
ExtractPassword { ExtractPassword {
@ -2214,6 +2222,13 @@ impl Application for App {
DialogPage::EmptyTrash => { DialogPage::EmptyTrash => {
self.operation(Operation::EmptyTrash); self.operation(Operation::EmptyTrash);
} }
DialogPage::ExtractTo { paths, to, password } => {
self.operation(Operation::Extract {
paths,
to,
password: None,
});
},
DialogPage::FailedOperation(id) => { DialogPage::FailedOperation(id) => {
log::warn!("TODO: retry operation {}", id); log::warn!("TODO: retry operation {}", id);
} }
@ -2361,6 +2376,21 @@ impl Application for App {
}); });
} }
} }
Message::ExtractTo(entity_opt) => {
let paths = self.selected_paths(entity_opt);
if let Some(destination) = paths
.first()
.and_then(|first| first.parent())
.map(|parent| parent.to_path_buf())
{
self.dialog_pages.push_back(DialogPage::ExtractTo {
paths,
to: destination,
password: None,
});
};
}
Message::Key(modifiers, key, text) => { Message::Key(modifiers, key, text) => {
let entity = self.tab_model.active(); let entity = self.tab_model.active();
for (key_bind, action) in self.key_binds.iter() { for (key_bind, action) in self.key_binds.iter() {
@ -4073,6 +4103,24 @@ impl Application for App {
.secondary_action( .secondary_action(
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel), 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) => { DialogPage::FailedOperation(id) => {
//TODO: try next dialog page (making sure index is used by Dialog messages)? //TODO: try next dialog page (making sure index is used by Dialog messages)?
let (operation, _, err) = self.failed_operations.get(id)?; let (operation, _, err) = self.failed_operations.get(id)?;

View file

@ -200,6 +200,7 @@ pub fn context_menu<'a>(
selected_types.retain(|t| !supported_archive_types.contains(t)); selected_types.retain(|t| !supported_archive_types.contains(t));
if selected_types.is_empty() { if selected_types.is_empty() {
children.push(menu_item(fl!("extract-here"), Action::ExtractHere).into()); children.push(menu_item(fl!("extract-here"), Action::ExtractHere).into());
children.push(menu_item(fl!("extract-to"), Action::ExtractTo).into());
} }
children.push(menu_item(fl!("compress"), Action::Compress).into()); children.push(menu_item(fl!("compress"), Action::Compress).into());
children.push(divider::horizontal::light().into()); children.push(divider::horizontal::light().into());