Enable extracting zip files to current folder
This commit is contained in:
parent
e4c65883fd
commit
ef23ff77e1
6 changed files with 360 additions and 0 deletions
15
src/app.rs
15
src/app.rs
|
|
@ -71,6 +71,7 @@ pub enum Action {
|
|||
Cut,
|
||||
EditHistory,
|
||||
EditLocation,
|
||||
ExtractHere,
|
||||
HistoryNext,
|
||||
HistoryPrevious,
|
||||
ItemDown,
|
||||
|
|
@ -119,6 +120,7 @@ impl Action {
|
|||
Action::Cut => Message::Cut(entity_opt),
|
||||
Action::EditHistory => Message::ToggleContextPage(ContextPage::EditHistory),
|
||||
Action::EditLocation => Message::EditLocation(entity_opt),
|
||||
Action::ExtractHere => Message::ExtractHere(entity_opt),
|
||||
Action::HistoryNext => Message::TabMessage(entity_opt, tab::Message::GoNext),
|
||||
Action::HistoryPrevious => Message::TabMessage(entity_opt, tab::Message::GoPrevious),
|
||||
Action::ItemDown => Message::TabMessage(entity_opt, tab::Message::ItemDown),
|
||||
|
|
@ -216,6 +218,7 @@ pub enum Message {
|
|||
DialogPush(DialogPage),
|
||||
DialogUpdate(DialogPage),
|
||||
EditLocation(Option<Entity>),
|
||||
ExtractHere(Option<Entity>),
|
||||
Key(Modifiers, Key),
|
||||
LaunchUrl(String),
|
||||
MaybeExit,
|
||||
|
|
@ -1333,6 +1336,18 @@ impl Application for App {
|
|||
));
|
||||
}
|
||||
}
|
||||
Message::ExtractHere(entity_opt) => {
|
||||
let paths = self.selected_paths(entity_opt);
|
||||
if let Some(current_path) = paths.get(0) {
|
||||
if let Some(destination) = current_path.parent().zip(current_path.file_stem()) {
|
||||
let destination_path = destination.0.to_path_buf();
|
||||
self.operation(Operation::Extract {
|
||||
paths,
|
||||
to: destination_path,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::Key(modifiers, key) => {
|
||||
let entity = self.tab_model.active();
|
||||
for (key_bind, action) in self.key_binds.iter() {
|
||||
|
|
|
|||
15
src/menu.rs
15
src/menu.rs
|
|
@ -9,6 +9,7 @@ use cosmic::{
|
|||
widget::menu::{self, key_bind::KeyBind, ItemHeight, ItemWidth, MenuBar},
|
||||
Element,
|
||||
};
|
||||
use mime_guess::Mime;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -79,6 +80,7 @@ pub fn context_menu<'a>(
|
|||
|
||||
let mut selected_dir = 0;
|
||||
let mut selected = 0;
|
||||
let mut selected_types: Vec<Mime> = vec![];
|
||||
tab.items_opt().map(|items| {
|
||||
for item in items.iter() {
|
||||
if item.selected {
|
||||
|
|
@ -86,9 +88,12 @@ pub fn context_menu<'a>(
|
|||
if item.metadata.is_dir() {
|
||||
selected_dir += 1;
|
||||
}
|
||||
selected_types.push(item.mime.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
selected_types.sort_unstable();
|
||||
selected_types.dedup();
|
||||
|
||||
let mut children: Vec<Element<_>> = Vec::new();
|
||||
match tab.location {
|
||||
|
|
@ -119,6 +124,16 @@ pub fn context_menu<'a>(
|
|||
children.push(menu_item(fl!("rename"), Action::Rename).into());
|
||||
children.push(menu_item(fl!("cut"), Action::Cut).into());
|
||||
children.push(menu_item(fl!("copy"), Action::Copy).into());
|
||||
|
||||
let supported_archive_types = ["application/x-tar", "application/zip"]
|
||||
.iter()
|
||||
.filter_map(|mime_type| mime_type.parse::<Mime>().ok())
|
||||
.collect::<Vec<_>>();
|
||||
selected_types.retain(|t| !supported_archive_types.contains(t));
|
||||
if selected_types.is_empty() {
|
||||
children.push(menu_item(fl!("extract-here"), Action::ExtractHere).into());
|
||||
}
|
||||
|
||||
//TODO: Print?
|
||||
children.push(container(horizontal_rule(1)).padding([0, 8]).into());
|
||||
children.push(menu_item(fl!("show-details"), Action::Properties).into());
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use cosmic::iced::futures::{channel::mpsc::Sender, executor, SinkExt};
|
||||
use mime_guess::MimeGuess;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs,
|
||||
io::{self, Error},
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
sync::{
|
||||
atomic::{self, AtomicU64},
|
||||
Arc,
|
||||
|
|
@ -138,6 +141,11 @@ pub enum Operation {
|
|||
},
|
||||
/// Empty the trash
|
||||
EmptyTrash,
|
||||
/// Uncompress files
|
||||
Extract {
|
||||
paths: Vec<PathBuf>,
|
||||
to: PathBuf,
|
||||
},
|
||||
/// Move items
|
||||
Move {
|
||||
paths: Vec<PathBuf>,
|
||||
|
|
@ -246,6 +254,12 @@ impl Operation {
|
|||
to = fl!("trash")
|
||||
),
|
||||
Self::EmptyTrash => fl!("emptying-trash"),
|
||||
Self::Extract { paths, to } => fl!(
|
||||
"extracting",
|
||||
items = paths.len(),
|
||||
from = paths_parent_name(paths),
|
||||
to = file_name(to)
|
||||
),
|
||||
Self::Move { paths, to } => fl!(
|
||||
"moving",
|
||||
items = paths.len(),
|
||||
|
|
@ -284,6 +298,12 @@ impl Operation {
|
|||
to = fl!("trash")
|
||||
),
|
||||
Self::EmptyTrash => fl!("emptied-trash"),
|
||||
Self::Extract { paths, to } => fl!(
|
||||
"extracted",
|
||||
items = paths.len(),
|
||||
from = paths_parent_name(paths),
|
||||
to = file_name(to)
|
||||
),
|
||||
Self::Move { paths, to } => fl!(
|
||||
"moved",
|
||||
items = paths.len(),
|
||||
|
|
@ -473,6 +493,50 @@ impl Operation {
|
|||
.send(Message::PendingProgress(id, 100.0))
|
||||
.await;
|
||||
}
|
||||
Self::Extract { paths, to } => {
|
||||
for path in paths {
|
||||
let to = to.to_owned();
|
||||
|
||||
tokio::task::spawn_blocking(move || -> Result<(), String> {
|
||||
if let Some(file_stem) = path.file_stem() {
|
||||
let mut new_dir = to.join(file_stem);
|
||||
if new_dir.exists() {
|
||||
let mut extensionless_path = path.to_owned();
|
||||
extensionless_path.set_extension("");
|
||||
if let Some(new_dir_parent) = new_dir.parent() {
|
||||
new_dir = copy_unique_path(&extensionless_path, new_dir_parent);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mime) = mime_guess::from_path(&path).first() {
|
||||
match mime.essence_str() {
|
||||
"application/x-tar" => {
|
||||
return fs::File::open(path)
|
||||
.map(io::BufReader::new)
|
||||
.map(tar::Archive::new)
|
||||
.and_then(|mut archive| archive.unpack(new_dir))
|
||||
.map_err(err_str)
|
||||
}
|
||||
"application/zip" => {
|
||||
return fs::File::open(path)
|
||||
.map(io::BufReader::new)
|
||||
.map(zip::ZipArchive::new)
|
||||
.map_err(err_str)?
|
||||
.and_then(|mut archive| archive.extract(new_dir))
|
||||
.map_err(err_str)
|
||||
}
|
||||
_ => Err(format!("unsupported mime type {:?}", mime))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.map_err(err_str)?
|
||||
.map_err(err_str)?;
|
||||
}
|
||||
}
|
||||
Self::Move { paths, to } => {
|
||||
let msg_tx = msg_tx.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue