adding in support to extract/compress zip files with passwords

This commit is contained in:
ellieplayswow 2025-01-29 21:19:03 +00:00
parent 6a6a494012
commit 22552c658f
2 changed files with 220 additions and 92 deletions

View file

@ -71,6 +71,7 @@ use crate::{
spawn_detached::spawn_detached,
tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION},
};
use crate::operation::{OperationError, OperationErrorType};
#[derive(Clone, Debug)]
pub enum Mode {
@ -319,7 +320,7 @@ pub enum Message {
PendingCancelAll,
PendingComplete(u64, OperationSelection),
PendingDismiss,
PendingError(u64, String),
PendingError(u64, OperationError),
PendingPause(u64, bool),
PendingPauseAll(bool),
Preview(Option<Entity>),
@ -417,9 +418,14 @@ pub enum DialogPage {
to: PathBuf,
name: String,
archive_type: ArchiveType,
password: Option<String>
},
EmptyTrash,
FailedOperation(u64),
ExtractPassword {
id: u64,
password: String
},
MountError {
mounter_key: MounterKey,
item: MounterItem,
@ -1869,6 +1875,7 @@ impl Application for App {
to,
name,
archive_type,
password: None
});
return widget::text_input::focus(self.dialog_text_input.clone());
}
@ -1944,6 +1951,7 @@ impl Application for App {
to,
name,
archive_type,
password
} => {
let extension = archive_type.extension();
let name = format!("{}{}", name, extension);
@ -1952,6 +1960,7 @@ impl Application for App {
paths,
to,
archive_type,
password
})
}
DialogPage::EmptyTrash => {
@ -1960,6 +1969,21 @@ impl Application for App {
DialogPage::FailedOperation(id) => {
log::warn!("TODO: retry operation {}", id);
}
DialogPage::ExtractPassword {
id,
password
} => {
let (operation, _, _err) = self.failed_operations.get(&id).unwrap();
let new_op = match &operation {
Operation::Extract { to, paths, .. } => Operation::Extract {
to: to.clone(),
paths: paths.clone(),
password: Some(password)
},
_ => unreachable!()
};
self.operation(new_op);
}
DialogPage::MountError {
mounter_key,
item,
@ -2076,6 +2100,7 @@ impl Application for App {
self.operation(Operation::Extract {
paths,
to: destination,
password: None
});
}
}
@ -2566,11 +2591,19 @@ impl Application for App {
if let Some((op, controller)) = self.pending_operations.remove(&id) {
// Only show dialog if not cancelled
if !controller.is_cancelled() {
self.dialog_pages.push_back(DialogPage::FailedOperation(id));
self.dialog_pages.push_back(
match err.kind {
OperationErrorType::Generic(_) => DialogPage::FailedOperation(id),
OperationErrorType::PasswordRequired => DialogPage::ExtractPassword {
id: id,
password: String::from("")
}
}
);
}
// Remove from progress
self.progress_operations.remove(&id);
self.failed_operations.insert(id, (op, controller, err));
self.failed_operations.insert(id, (op, controller, err.to_string()));
}
// Close progress notification if all relavent operations are finished
if !self
@ -3564,6 +3597,7 @@ impl Application for App {
to,
name,
archive_type,
password
} => {
let mut dialog = widget::dialog().title(fl!("create-archive"));
@ -3596,7 +3630,7 @@ impl Application for App {
let archive_types = ArchiveType::all();
let selected = archive_types.iter().position(|&x| x == *archive_type);
dialog
dialog = dialog
.primary_action(
widget::button::suggested(fl!("create"))
.on_press_maybe(complete_maybe.clone()),
@ -3616,9 +3650,10 @@ impl Application for App {
to: to.clone(),
name: name.clone(),
archive_type: *archive_type,
password: password.clone(),
})
})
.on_submit_maybe(complete_maybe)
.on_submit_maybe(complete_maybe.clone())
.into(),
widget::dropdown(archive_types, selected, move |index| {
Message::DialogUpdate(DialogPage::Compress {
@ -3626,6 +3661,7 @@ impl Application for App {
to: to.clone(),
name: name.clone(),
archive_type: archive_types[index],
password: password.clone(),
})
})
.into(),
@ -3635,7 +3671,29 @@ impl Application for App {
.into(),
])
.spacing(space_xxs),
)
);
if *archive_type == ArchiveType::Zip {
let password_unwrapped = password.clone().unwrap_or_else(String::default);
dialog = dialog.control(
widget::column::with_children(vec![
widget::text::body("Password").into(),
widget::text_input("", password_unwrapped).password().on_input(move |password_unwrapped| {
Message::DialogUpdate(DialogPage::Compress {
paths: paths.clone(),
to: to.clone(),
name: name.clone(),
archive_type: *archive_type,
password: Some(password_unwrapped),
})
})
.on_submit_maybe(complete_maybe)
.into(),
])
);
}
dialog
}
DialogPage::EmptyTrash => widget::dialog()
.title(fl!("empty-trash"))
@ -3660,6 +3718,23 @@ impl Application for App {
widget::button::standard(fl!("cancel")).on_press(Message::DialogCancel),
)
}
DialogPage::ExtractPassword {
id,
password
} => {
widget::dialog()
.title("Password required")
.icon(widget::icon::from_name("dialog-error").size(64))
.control(widget::text_input("", password).password().on_input(move |password| {
Message::DialogUpdate(DialogPage::ExtractPassword {
id: *id,
password
})
}))
.primary_action(
widget::button::suggested(fl!("create")).on_press(Message::DialogComplete),
)
}
DialogPage::MountError {
mounter_key: _,
item: _,
@ -4661,8 +4736,9 @@ impl Application for App {
let _ = msg_tx
.lock()
.await
.send(Message::PendingError(id, err.to_string()))
.send(Message::PendingError(id, err))
.await;
}
}