From 5f944a3059496977eceb8d40fd599d53ec92b704 Mon Sep 17 00:00:00 2001 From: francesco-gaglione <94604837+francesco-gaglione@users.noreply.github.com> Date: Fri, 15 Nov 2024 23:24:52 +0100 Subject: [PATCH] Directories sizes in details view (#656) * translations * folder size in details view * dir size subscription * waldir instead of recursion * opitonal size with calculating label waiting for subscription * removed not necessary code * Bug fixes --------- Co-authored-by: Jeremy Soller --- i18n/en/cosmic_files.ftl | 7 +++ i18n/it/cosmic_files.ftl | 8 +++ src/mounter/gvfs.rs | 1 + src/tab.rs | 107 ++++++++++++++++++++++++++++++++++----- 4 files changed, 109 insertions(+), 14 deletions(-) diff --git a/i18n/en/cosmic_files.ftl b/i18n/en/cosmic_files.ftl index 7b6409b..a05cd2d 100644 --- a/i18n/en/cosmic_files.ftl +++ b/i18n/en/cosmic_files.ftl @@ -201,6 +201,13 @@ default-app = {$name} (default) ## Show details show-details = Show details +type = Type: {$mime} +items = Items: {$items} +item-size = Size: {$size} +item-created = Created: {$created} +item-modified = Modified: {$modified} +item-accessed = Accessed: {$accessed} +calculating = Calculating... ## Settings settings = Settings diff --git a/i18n/it/cosmic_files.ftl b/i18n/it/cosmic_files.ftl index acef35a..e8b521b 100644 --- a/i18n/it/cosmic_files.ftl +++ b/i18n/it/cosmic_files.ftl @@ -189,6 +189,14 @@ default-app = {$name} (default) ## Show details show-details = Mostra dettagli +type = Tipo: {$mime} +items = Elementi: {$items} +item-size = Dimensione: {$size} +item-created = Creato: {$created} +item-modified = Modificato: {$modified} +item-accessed = Ultimo accesso: {$accessed} +calculating = Calcolando... + ## Settings settings = Impostazioni diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs index c36191e..a58b6db 100644 --- a/src/mounter/gvfs.rs +++ b/src/mounter/gvfs.rs @@ -135,6 +135,7 @@ fn network_scan(uri: &str, sizes: IconSizes) -> Result, String> { selected: false, highlighted: false, overlaps_drag_rect: false, + size: None, }); } Ok(items) diff --git a/src/tab.rs b/src/tab.rs index 3a8012d..5034d6e 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -55,6 +55,7 @@ use std::{ time::{Duration, Instant, SystemTime}, }; use tokio::sync::mpsc; +use walkdir::WalkDir; use crate::{ app::{self, Action, PreviewItem, PreviewKind}, @@ -302,6 +303,7 @@ fn format_permissions_owner(metadata: &Metadata, owner: PermissionOwner) -> Stri PermissionOwner::Other => String::from(""), }; } + fn format_permissions(metadata: &Metadata, owner: PermissionOwner) -> String { let mut perms: Vec = Vec::new(); if match owner { @@ -489,6 +491,7 @@ pub fn item_from_entry( selected: false, highlighted: false, overlaps_drag_rect: false, + size: None, } } @@ -718,6 +721,7 @@ pub fn scan_trash(sizes: IconSizes) -> Vec { selected: false, highlighted: false, overlaps_drag_rect: false, + size: None, }); } } @@ -901,6 +905,7 @@ pub fn scan_desktop( selected: false, highlighted: false, overlaps_drag_rect: false, + size: None, }) } @@ -1074,6 +1079,7 @@ pub enum Message { ZoomOut, HighlightDeactivate(usize), HighlightActivate(usize), + DirectorySize(PathBuf, u64), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -1303,6 +1309,7 @@ pub struct Item { pub selected: bool, pub highlighted: bool, pub overlaps_drag_rect: bool, + pub size: Option, } impl Item { @@ -1396,33 +1403,43 @@ impl Item { let mut details = widget::column().spacing(space_xxxs); details = details.push(widget::text::heading(self.name.clone())); - details = details.push(widget::text(format!("Type: {}", self.mime))); + details = details.push(widget::text(fl!("type", mime = self.mime.to_string()))); let mut settings = Vec::new(); - //TODO: translate! - //TODO: correct display of folder size? match &self.metadata { ItemMetadata::Path { metadata, children } => { if metadata.is_dir() { - details = details.push(widget::text(format!("Items: {}", children))); + details = details.push(widget::text(fl!("items", items = children))); + let size = match self.size { + Some(size) => format_size(size), + None => fl!("calculating"), + }; + details = details.push(widget::text(fl!("item-size", size = size))); } else { - details = details.push(widget::text(format!( - "Size: {}", - format_size(metadata.len()) + details = details.push(widget::text(fl!( + "item-size", + size = format_size(metadata.len()) ))); } if let Ok(time) = metadata.created() { - details = details.push(widget::text(format!("Created: {}", format_time(time)))); + details = details.push(widget::text(fl!( + "item-created", + created = format_time(time).to_string() + ))); } if let Ok(time) = metadata.modified() { - details = - details.push(widget::text(format!("Modified: {}", format_time(time)))); + details = details.push(widget::text(fl!( + "item-modified", + modified = format_time(time).to_string() + ))); } if let Ok(time) = metadata.accessed() { - details = - details.push(widget::text(format!("Accessed: {}", format_time(time)))); + details = details.push(widget::text(fl!( + "item-accessed", + accessed = format_time(time).to_string() + ))); } #[cfg(not(target_os = "windows"))] @@ -1636,6 +1653,16 @@ pub struct Tab { search_context: Option, } +fn calculate_dir_size(path: &Path) -> u64 { + WalkDir::new(path) + .into_iter() + .filter_map(|entry| entry.ok()) + .filter_map(|entry| fs::metadata(entry.path()).ok()) + .filter(|metadata| metadata.is_file()) + .map(|metadata| metadata.len()) + .sum() +} + fn folder_name>(path: P) -> (String, bool) { let path = path.as_ref(); let mut found_home = false; @@ -2886,6 +2913,22 @@ impl Tab { Message::ZoomOut => { commands.push(Command::Action(Action::ZoomOut)); } + Message::DirectorySize(path, dir_size) => { + let location = Location::Path(path); + if let Some(ref mut item) = self.parent_item_opt { + if item.location_opt.as_ref() == Some(&location) { + item.size = Some(dir_size); + } + } + if let Some(ref mut items) = self.items_opt { + for item in items.iter_mut() { + if item.location_opt.as_ref() == Some(&location) { + item.size = Some(dir_size); + break; + } + } + } + } } // Scroll to top if needed @@ -4394,8 +4437,9 @@ impl Tab { continue; }; let mime = item.mime.clone(); + subscriptions.push(Subscription::run_with_id( - path.clone(), + ("thumbnail", path.clone()), stream::channel(1, |mut output| async move { let message = { let path = path.clone(); @@ -4413,7 +4457,7 @@ impl Tab { match output.send(message).await { Ok(()) => {} Err(err) => { - log::warn!("failed to send thumbnail for {:?}: {}", path, err); + log::warn!("failed to send thumbnail for {:?}: {}", &path, err); } } @@ -4426,6 +4470,41 @@ impl Tab { } } + // Load directory size for selected items + for item in items + .iter() + .filter(|item| { + // Item must be a selected directory + item.selected && item.metadata.is_dir() + }) + .chain(&self.parent_item_opt) + { + // Item must have a path + let Some(path) = item.path_opt().map(|path| path.to_path_buf()) else { + continue; + }; + subscriptions.push(Subscription::run_with_id( + ("dir_size", path.clone()), + stream::channel(1, |mut output| async move { + let total_size = calculate_dir_size(&path); + + match output + .send(Message::DirectorySize(path.clone(), total_size)) + .await + { + Ok(()) => {} + Err(err) => { + log::warn!("failed to send dirsize for {:?}: {}", &path, err); + } + } + + std::future::pending().await + }), + )); + // Only calculate size for one directory + break; + } + // Load search items incrementally if let Location::Search(path, term, show_hidden, start) = &self.location { let location = self.location.clone();