Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude = ["gui"]
resolver = "2"

[workspace.package]
version = "0.9.1"
version = "0.9.2"
edition = "2021"
license = "MIT"
authors = ["kingchenc"]
Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,19 @@ A modern Tauri UI lives in `gui/`:
duplicate minimum size, Recycle Bin vs. permanent delete, window size at start
(1440p if it fits the screen, otherwise maximized; or 1080p / 4K / maximized),
language. The version is shown next to the name.
- **Find duplicates** to sort/filter groups and reclaim their space with one
click. Every complete scan is kept as a snapshot (in the background, so the
result shows at once); **Changes** lists them with their size on disk,
compares the folder on screen against any of them — folders and single files
— and tints the treemap and folder rows by what grew or shrank.
- **Find duplicates** — every group is byte-identical content (BLAKE3 over the
whole file), whatever the names. Copies inside installed programs and games
(Steam, Epic, Battle.net, Program Files, …; DLLs, game archives) are there on
purpose, so they are hidden by default, shown with a lock when asked for, and
never removed while hidden; the program's copy is the one kept. **Folder
pairs** sums up which folders share identical files; filter by category or
name, then reclaim with one click (dry-run first).
- **What changed** — every complete scan is kept as a snapshot (in the
background, so the result shows at once), and right after a scan a **Since
last scan** card compares it with the previous one. **Compare** / **Changes**
lists the snapshots with their size on disk, compares the folder on screen
against any of them — folders and single files — and tints the treemap and
folder rows by what grew or shrank.
- **Never blocking** — every command runs off the UI thread and each scan has
its own lock, so browsing one scan never waits for another.

Expand Down Expand Up @@ -188,6 +196,7 @@ Diskghost/
- [x] Snapshots & "what grew since last time" (CLI `--save`/`--since`/`diff`, GUI history)
- [x] GUI dashboard: parallel scans + queue, drives, nested treemap, file-type and size-range charts, exclude templates, settings
- [x] Own parallel walker (no per-file open), file-level snapshots (zstd, streaming diff), non-blocking GUI
- [x] Automatic "since last scan" comparison; duplicate finder that protects program and game files, folder pairs

## Development

Expand Down
4 changes: 2 additions & 2 deletions gui/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion gui/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

[package]
name = "diskghost-gui"
version = "0.9.1"
version = "0.9.2"
edition = "2021"
license = "MIT"
description = "Diskghost desktop GUI (Tauri) — modern disk usage & duplicate finder."
Expand Down
27 changes: 14 additions & 13 deletions gui/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,19 @@ struct Cached {
/// Views already computed, by folder and list length — going back to a
/// folder is answered without touching the tree again.
views: HashMap<(PathBuf, usize), Arc<View>>,
/// The tree captured as a snapshot (for comparisons), once taken.
current: Option<Arc<Snapshot>>,
/// The tree captured as a snapshot (for comparisons), once taken. A
/// mutex of its own, so it can be filled under the tree's read lock and a
/// second caller waits for the first capture instead of repeating it.
current: Mutex<Option<Arc<Snapshot>>>,
}

impl Cached {
/// Forget everything derived from the tree (it was changed).
fn changed(&mut self) {
self.views.clear();
self.current = None;
if let Ok(c) = self.current.get_mut() {
*c = None;
}
}
}

Expand Down Expand Up @@ -238,16 +242,13 @@ fn store_snapshot(dir: &Path, snap: &Snapshot, keep: usize) -> Result<(), String

/// Capture the tree as a snapshot once and keep it for comparisons.
fn current_snapshot(shared: &Shared) -> Result<Arc<Snapshot>, String> {
if let Some(s) = shared.read().map_err(|e| e.to_string())?.current.clone() {
return Ok(s);
}
let snap = {
let c = shared.read().map_err(|e| e.to_string())?;
Arc::new(Snapshot::capture(&c.tree))
};
if let Ok(mut c) = shared.write() {
c.current = Some(snap.clone());
let c = shared.read().map_err(|e| e.to_string())?;
let mut current = c.current.lock().map_err(|e| e.to_string())?;
if let Some(s) = current.as_ref() {
return Ok(s.clone());
}
let snap = Arc::new(Snapshot::capture(&c.tree));
*current = Some(snap.clone());
Ok(snap)
}

Expand Down Expand Up @@ -277,7 +278,7 @@ async fn scan_dir(
let shared: Shared = Arc::new(RwLock::new(Cached {
tree,
views: HashMap::new(),
current: None,
current: Mutex::new(None),
}));
if let Ok(mut trees) = app.state::<AppState>().trees.lock() {
trees.insert(job, shared.clone());
Expand Down
2 changes: 1 addition & 1 deletion gui/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Diskghost",
"version": "0.9.1",
"version": "0.9.2",
"identifier": "org.diskghost.app",
"build": {
"frontendDist": "../ui"
Expand Down
Loading
Loading