diff --git a/src/app.rs b/src/app.rs index 6c658745..f57aae57 100644 --- a/src/app.rs +++ b/src/app.rs @@ -61,7 +61,6 @@ use trash::TrashItem; #[cfg(feature = "wayland")] use wayland_client::{protocol::wl_output::WlOutput, Proxy}; -use crate::operation::{OperationError, OperationErrorType}; use crate::{ clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste}, config::{AppTheme, Config, DesktopConfig, Favorite, IconSizes, TabConfig}, @@ -74,6 +73,10 @@ use crate::{ spawn_detached::spawn_detached, tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION}, }; +use crate::{ + operation::{OperationError, OperationErrorType}, + tab::Item, +}; #[derive(Clone, Debug)] pub enum Mode { @@ -1488,16 +1491,21 @@ impl App { PreviewKind::Selected => { if let Some(tab) = self.tab_model.data::(entity) { if let Some(items) = tab.items_opt() { - for item in items.iter() { - if item.selected { - children.push(item.preview_view( - Some(&self.mime_app_cache), - tab.config.icon_sizes, - military_time, - )); - // Only show one property view to avoid issues like hangs when generating - // preview images on thousands of files - break; + let items_selected = items.iter().filter(|v| v.selected).count(); + if items_selected > 1 { + children.push(Item::preview_view_multiple(items)) + } else { + for item in items.iter() { + if item.selected { + children.push(item.preview_view( + Some(&self.mime_app_cache), + tab.config.icon_sizes, + military_time, + )); + // Only show one property view to avoid issues like hangs when generating + // preview images on thousands of files + break; + } } } if children.is_empty() { diff --git a/src/tab.rs b/src/tab.rs index f6d3f587..31455818 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1518,6 +1518,51 @@ impl Item { row } + pub fn preview_view_multiple<'a>(items: &[Item]) -> Element<'a, Message> { + let cosmic_theme::Spacing { space_m, .. } = theme::active().cosmic().spacing; + let mut column = widget::column().spacing(space_m); + + let items_selected: Vec<&Item> = items.iter().filter(|v| v.selected).collect(); + let (dirs_selected, files_selected) = + items_selected + .iter() + .fold((0u32, 0u32), |(dirs, files), &v| match &v.metadata { + ItemMetadata::Path { metadata, .. } => { + if metadata.is_dir() { + (dirs + 1, files) + } else { + (dirs, files + 1) + } + } + _ => (dirs, files), + }); + + let dirs_text = if dirs_selected == 1 { + "folder" + } else { + "folders" + }; + let files_text = if files_selected == 1 { "file" } else { "files" }; + let text: String; + + if dirs_selected >= 1 && files_selected >= 1 { + text = format!( + "{} {}, {} {} selected", + dirs_selected, dirs_text, files_selected, files_text + ); + } else if dirs_selected >= 1 && files_selected == 0 { + text = format!("{} {} selected", dirs_selected, dirs_text); + } else if dirs_selected == 0 && files_selected >= 1 { + text = format!("{} {} selected", files_selected, files_text); + } else { + log::error!("folder or a file should have been selected."); + text = String::new(); // do not crash if we somehow reach here. + } + + column = column.push(widget::text::heading(text)); + column.into() + } + pub fn preview_view<'a>( &'a self, mime_app_cache_opt: Option<&'a mime_app::MimeAppCache>,