Root causes found by reproducing each on the emulator (2.8k-file fixture with mixed jpg/mp4): 1. walk_dir_nostats (incremental rescan of >2000-file dirs) had NO image-extension filter: it re-enumerated every file, injecting all ~1,727 videos into the DB. This is what made the count swing 8,439 -> 10,166 and the grid full of blank cells (404 rows). Now filters through is_image_path() like every other walk. 2. walk_dir aborted the ENTIRE walk on any per-file stat failure (file deleted mid-walk), so an error during the walk meant the walk was never applied and deletions were never detected. Per-file stat errors are now skipped; only readdir/root errors fail the walk (an errored walk is still not applied). 3. dir_sig stat'ed every entry of every root dir every watch tick: 10k+ stats/second on the phone = 10s+ of FUSE I/O per second = the long delays. On Android the MediaStore URI payloads already carry the exact change signal, so the mtime-diff machinery now runs desktop-only. The Android watch tick is a single read_dir of our own app dir (no-op when empty): 1s backstop, 30s-throttled fallback full rescan for events with no payload, 5-min full pass. 4. TOCTOU: a delete consumed while a full rescan was mid-walk lost to the walk's stale snapshot (walk re-added the row). RESCANNING gate parks payloads during the walk; they apply after it, so mid-walk deletions always win. Reproduced deterministically (churn during the startup walk), fixed, re-verified. Emulator stress (all passing): full-walk convergence, add +1s, delete +1s, video add/delete = zero rows, 60-op churn converges to exact disk count, 3x relaunch idempotency, startup-walk race converges (1s normally, 5-min backstop when the OS scanner drops burst events), no-blank-cells visual check, 0.00% dropped frames. Phone verified: 10,166 -> 8,439 on first launch (all video phantoms purged), add appears ~2s after the OS indexes it, delete same, DB returns to 8,439 exactly. ContentObserver registration + onChange logging added (it fired reliably once the stale instance was replaced). |
||
|---|---|---|
| docs/BUGS | ||
| harnesses | ||
| scripts | ||
| shim/out | ||
| src | ||
| tools | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| HANDOFF.md | ||
| LICENSE | ||
| README.md | ||
gallery
A high-performance image gallery for Android (primary), Linux and macOS —
Rust + egui 0.31 (egui_glow / winit 0.30 / glow 0.16).
Ported from Slint 1.18 after the zero-jank campaign showed Slint-on-Mali
janky at its base level while egui measured 3–7× cleaner (HANDOFF.md
§8.11–8.12). The Slint tree is preserved in git history and
docs/BUGS/.
Status: M0–M4 ported to egui, zero-jank tuning in progress. See HANDOFF.md — the development hand-off: architecture, thumbnail pipeline, milestones M1–M7, the Slint jank campaign, the egui port, and the sltest/egtest/tttest harnesses (A/B/C: Slint/egui/WebView).
Build
./scripts/build.sh debug # debug x86_64 APK + install on emulator
./scripts/build.sh # release x86_64 (emulator)
./scripts/build.sh aarch64 # release aarch64 (device)
cargo run # desktop (Linux needs libfontconfig1 + pkg-config)
Requires: Rust (rustup), cargo-apk2, Android SDK + NDK 27 (see HANDOFF.md §3
for exact paths/env).
License
GPL-3.0 (see LICENSE). Built on egui (MIT/Apache-2.0).