From 8ca31beee3e814045d7213427c901e0dce797d8a Mon Sep 17 00:00:00 2001 From: kellito Date: Sun, 5 Jul 2026 17:50:09 +0300 Subject: [PATCH] =?UTF-8?q?tlc:=20Sprint=203=20C3=20=E2=80=94=20delete=20d?= =?UTF-8?q?ialog=20shows=20total=20recursive=20size?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeleteDialog header now includes the total recursive size of all paths to be deleted (formatted via format_size). For example: 'Delete 3 (1.2 MB) ?' instead of just 'Delete ?'. Computed eagerly at construction via crate::ops::count_bytes so render() does not block on filesystem traversal. DeleteDialog (delete_dialog.rs): - New field total_bytes: u64 (cached at construction) - new() calls crate::ops::count_bytes(&paths) to populate it - render() prepends '(N items)' to header and appends size when > 0 Tests (3 new in delete_dialog::tests): - new_computes_total_bytes_for_directory (recursive dir sum) - new_total_bytes_zero_for_missing_paths - new_total_bytes_sums_multiple_paths Total: 1271 passing (was 1268; +3 new). --- .../source/src/filemanager/delete_dialog.rs | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/local/recipes/tui/tlc/source/src/filemanager/delete_dialog.rs b/local/recipes/tui/tlc/source/src/filemanager/delete_dialog.rs index 1ba2ebfd1c..8cc24fda8e 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/delete_dialog.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/delete_dialog.rs @@ -25,6 +25,10 @@ use crate::widget::button::{ButtonKind, ButtonSpec}; pub struct DeleteDialog { /// Paths to be deleted. pub paths: Vec, + /// Cached total size in bytes (recursive sum across all paths). + /// Computed at construction via `crate::ops::count_bytes` so the + /// dialog renders without blocking on filesystem traversal. + pub total_bytes: u64, /// True after Y confirms. pub confirmed: bool, /// True after N / Esc cancels. @@ -36,11 +40,16 @@ pub struct DeleteDialog { } impl DeleteDialog { - /// Create a new delete dialog for the given paths. + /// Create a new delete dialog for the given paths. The total + /// recursive size is computed eagerly (filesystem walk) so the + /// dialog header can display "Delete N items (X MB)?" without + /// blocking at render time. #[must_use] pub fn new(paths: Vec) -> Self { + let total_bytes = crate::ops::count_bytes(&paths); Self { paths, + total_bytes, confirmed: false, cancelled: false, width_pct: 0.5, @@ -105,7 +114,16 @@ impl DeleteDialog { ]) .split(inner); - let header_text = format!("{} ?", crate::locale::t("dialog_title_delete")); + let header_text = if self.total_bytes > 0 { + format!( + "{} {} ({} ?)", + crate::locale::t("dialog_title_delete"), + self.paths.len(), + crate::filemanager::format_utils::format_size(self.total_bytes) + ) + } else { + format!("{} {} ?", crate::locale::t("dialog_title_delete"), self.paths.len()) + }; let header = Line::from(Span::styled( header_text, Style::default() @@ -207,4 +225,34 @@ mod tests { assert!(d.is_cancelled()); assert!(!d.is_confirmed()); } + + #[test] + fn new_computes_total_bytes_for_directory() { + let dir = tempfile::tempdir().unwrap(); + let sub = dir.path().join("sub"); + std::fs::create_dir(&sub).unwrap(); + std::fs::write(sub.join("a.txt"), b"hello").unwrap(); + std::fs::write(sub.join("b.txt"), b"world!!").unwrap(); + let d = DeleteDialog::new(vec![dir.path().to_path_buf()]); + // Recursive sum: 5 + 7 = 12 bytes (directories don't count + // their own entries). + assert_eq!(d.total_bytes, 12); + } + + #[test] + fn new_total_bytes_zero_for_missing_paths() { + let d = DeleteDialog::new(vec![std::path::PathBuf::from("/no/such/path/xyz")]); + assert_eq!(d.total_bytes, 0); + } + + #[test] + fn new_total_bytes_sums_multiple_paths() { + let dir = tempfile::tempdir().unwrap(); + let p1 = dir.path().join("a"); + let p2 = dir.path().join("b"); + std::fs::write(&p1, b"12345").unwrap(); + std::fs::write(&p2, b"678").unwrap(); + let d = DeleteDialog::new(vec![p1, p2]); + assert_eq!(d.total_bytes, 8); + } }