tlc: Sprint 3 C3 — delete dialog shows total recursive size
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).
This commit is contained in:
@@ -25,6 +25,10 @@ use crate::widget::button::{ButtonKind, ButtonSpec};
|
||||
pub struct DeleteDialog {
|
||||
/// Paths to be deleted.
|
||||
pub paths: Vec<PathBuf>,
|
||||
/// 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<PathBuf>) -> 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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user