Add support for compressing to .tgz, add gio network mount example
This commit is contained in:
parent
c4c92be708
commit
4374132e2f
6 changed files with 219 additions and 135 deletions
35
src/app.rs
35
src/app.rs
|
|
@ -303,19 +303,32 @@ impl ContextPage {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub enum ArchiveType {
|
||||
Tgz,
|
||||
#[default]
|
||||
Zip,
|
||||
}
|
||||
|
||||
impl ArchiveType {
|
||||
pub fn extension(&self) -> String {
|
||||
pub fn all() -> &'static [Self] {
|
||||
&[Self::Tgz, Self::Zip]
|
||||
}
|
||||
|
||||
pub fn extension(&self) -> &str {
|
||||
match self {
|
||||
ArchiveType::Zip => ".zip".to_string(),
|
||||
ArchiveType::Tgz => ".tgz",
|
||||
ArchiveType::Zip => ".zip",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for ArchiveType {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.extension()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum DialogPage {
|
||||
Compress {
|
||||
|
|
@ -1299,7 +1312,7 @@ impl Application for App {
|
|||
if let Some(destination) = current_path.parent().zip(current_path.file_stem()) {
|
||||
let to = destination.0.to_path_buf();
|
||||
let name = destination.1.to_str().unwrap_or_default().to_string();
|
||||
let archive_type = ArchiveType::Zip;
|
||||
let archive_type = ArchiveType::default();
|
||||
self.dialog_pages.push_back(DialogPage::Compress {
|
||||
paths,
|
||||
to,
|
||||
|
|
@ -2436,6 +2449,8 @@ impl Application for App {
|
|||
}
|
||||
};
|
||||
|
||||
let archive_types = ArchiveType::all();
|
||||
let selected = archive_types.iter().position(|&x| x == *archive_type);
|
||||
dialog
|
||||
.primary_action(
|
||||
widget::button::suggested(fl!("create"))
|
||||
|
|
@ -2455,12 +2470,20 @@ impl Application for App {
|
|||
paths: paths.clone(),
|
||||
to: to.clone(),
|
||||
name: name.clone(),
|
||||
archive_type: archive_type.clone(),
|
||||
archive_type: *archive_type,
|
||||
})
|
||||
})
|
||||
.on_submit_maybe(complete_maybe)
|
||||
.into(),
|
||||
widget::text::body(".zip").into(),
|
||||
widget::dropdown(archive_types, selected, move |index| {
|
||||
Message::DialogUpdate(DialogPage::Compress {
|
||||
paths: paths.clone(),
|
||||
to: to.clone(),
|
||||
name: name.clone(),
|
||||
archive_type: archive_types[index],
|
||||
})
|
||||
})
|
||||
.into(),
|
||||
])
|
||||
.align_items(Alignment::Center)
|
||||
.spacing(space_xxs)
|
||||
|
|
|
|||
12
src/menu.rs
12
src/menu.rs
|
|
@ -126,10 +126,14 @@ pub fn context_menu<'a>(
|
|||
children.push(menu_item(fl!("copy"), Action::Copy).into());
|
||||
|
||||
children.push(container(horizontal_rule(1)).padding([0, 8]).into());
|
||||
let supported_archive_types = ["application/x-tar", "application/zip"]
|
||||
.iter()
|
||||
.filter_map(|mime_type| mime_type.parse::<Mime>().ok())
|
||||
.collect::<Vec<_>>();
|
||||
let supported_archive_types = [
|
||||
"application/x-compressed-tar",
|
||||
"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());
|
||||
|
|
|
|||
141
src/operation.rs
141
src/operation.rs
|
|
@ -15,7 +15,9 @@ use walkdir::WalkDir;
|
|||
use crate::{
|
||||
app::{ArchiveType, DialogPage, Message},
|
||||
config::IconSizes,
|
||||
fl, tab,
|
||||
fl,
|
||||
mime_icon::mime_for_path,
|
||||
tab,
|
||||
};
|
||||
|
||||
fn err_str<T: ToString>(err: T) -> String {
|
||||
|
|
@ -374,26 +376,31 @@ impl Operation {
|
|||
} => {
|
||||
let msg_tx = msg_tx.clone();
|
||||
tokio::task::spawn_blocking(move || -> Result<(), String> {
|
||||
let Some(relative_root) = to.parent() else {
|
||||
return Err(format!("path {:?} has no parent directory", to));
|
||||
};
|
||||
|
||||
let mut paths = paths;
|
||||
for path in paths.clone().iter() {
|
||||
if path.is_dir() {
|
||||
let new_paths_it = WalkDir::new(path).into_iter();
|
||||
for entry in new_paths_it.skip(1) {
|
||||
let entry = entry.map_err(err_str)?;
|
||||
paths.push(entry.path().to_path_buf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match archive_type {
|
||||
ArchiveType::Zip => {
|
||||
ArchiveType::Tgz => {
|
||||
let mut archive = fs::File::create(&to)
|
||||
.map(io::BufWriter::new)
|
||||
.map(zip::ZipWriter::new)
|
||||
.map(|w| {
|
||||
flate2::write::GzEncoder::new(w, flate2::Compression::default())
|
||||
})
|
||||
.map(tar::Builder::new)
|
||||
.map_err(err_str)?;
|
||||
|
||||
let zip_options = zip::write::SimpleFileOptions::default();
|
||||
|
||||
let mut paths = paths;
|
||||
for path in paths.clone().iter() {
|
||||
if path.is_dir() {
|
||||
let new_paths_it = WalkDir::new(path).into_iter();
|
||||
for entry in new_paths_it.skip(1) {
|
||||
let entry = entry.map_err(err_str)?;
|
||||
paths.push(entry.path().to_path_buf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let total_paths = paths.len();
|
||||
for (i, path) in paths.iter().enumerate() {
|
||||
executor::block_on(async {
|
||||
|
|
@ -405,27 +412,56 @@ impl Operation {
|
|||
.await;
|
||||
});
|
||||
|
||||
if let Some(relative_root) = to.parent() {
|
||||
if let Some(relative_path) =
|
||||
path.strip_prefix(relative_root).map_err(err_str)?.to_str()
|
||||
{
|
||||
if path.is_file() {
|
||||
archive
|
||||
.start_file(relative_path, zip_options)
|
||||
.map_err(err_str)?;
|
||||
if let Some(relative_path) =
|
||||
path.strip_prefix(relative_root).map_err(err_str)?.to_str()
|
||||
{
|
||||
archive
|
||||
.append_path_with_name(path, relative_path)
|
||||
.map_err(err_str)?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
let mut file = fs::File::open(&path)
|
||||
.map(io::BufReader::new)
|
||||
.map_err(err_str)?;
|
||||
archive.finish().map_err(err_str)?;
|
||||
}
|
||||
ArchiveType::Zip => {
|
||||
let mut archive = fs::File::create(&to)
|
||||
.map(io::BufWriter::new)
|
||||
.map(zip::ZipWriter::new)
|
||||
.map_err(err_str)?;
|
||||
|
||||
file.read_to_end(&mut buffer).map_err(err_str)?;
|
||||
archive.write_all(&buffer).map_err(err_str)?;
|
||||
} else {
|
||||
archive
|
||||
.add_directory(relative_path, zip_options)
|
||||
.map_err(err_str)?;
|
||||
}
|
||||
//TODO: set unix_permissions per file?
|
||||
let zip_options = zip::write::SimpleFileOptions::default();
|
||||
|
||||
let total_paths = paths.len();
|
||||
for (i, path) in paths.iter().enumerate() {
|
||||
executor::block_on(async {
|
||||
let total_progress = (i as f32) / total_paths as f32;
|
||||
let _ = msg_tx
|
||||
.lock()
|
||||
.await
|
||||
.send(Message::PendingProgress(id, 100.0 * total_progress))
|
||||
.await;
|
||||
});
|
||||
|
||||
if let Some(relative_path) =
|
||||
path.strip_prefix(relative_root).map_err(err_str)?.to_str()
|
||||
{
|
||||
if path.is_file() {
|
||||
archive
|
||||
.start_file(relative_path, zip_options)
|
||||
.map_err(err_str)?;
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
let mut file = fs::File::open(&path)
|
||||
.map(io::BufReader::new)
|
||||
.map_err(err_str)?;
|
||||
|
||||
file.read_to_end(&mut buffer).map_err(err_str)?;
|
||||
archive.write_all(&buffer).map_err(err_str)?;
|
||||
} else {
|
||||
archive
|
||||
.add_directory(relative_path, zip_options)
|
||||
.map_err(err_str)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -611,21 +647,26 @@ impl Operation {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(mime) = mime_guess::from_path(&path).first() {
|
||||
match mime.essence_str() {
|
||||
"application/x-tar" => 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" => 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))?,
|
||||
}
|
||||
let mime = mime_for_path(&path);
|
||||
match mime.essence_str() {
|
||||
"application/x-compressed-tar" => fs::File::open(path)
|
||||
.map(io::BufReader::new)
|
||||
.map(flate2::read::GzDecoder::new)
|
||||
.map(tar::Archive::new)
|
||||
.and_then(|mut archive| archive.unpack(new_dir))
|
||||
.map_err(err_str)?,
|
||||
"application/x-tar" => 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" => 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))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue