Commit Graph

9 Commits

Author SHA1 Message Date
312d87f15d gtauri: pinch zoom about pointer midpoint + live filesystem watching
Pinch: the image now follows the hand (midpoint drift) and zooms
ABOUT the midpoint — the image point under the fingers stays put
while the scale changes. Per-frame delta math, clamped as before
(fit min, image-edge pan limits).

Live watching: new photos appear in the grid within ~2s of being
written. inotify does not work on Android's FUSE-backed external
storage, so the watcher polls a tree signature (dir mtimes only —
a few dozen stats/s) every second; on change (or a 30s safety-net
full pass) it debounces 600ms for the write burst, then runs the
incremental rescan (walk + DB diff + emit) off the main thread.

Supporting changes:
- Staged corruption: a decode failure no longer marks an id broken
  immediately — 3 consecutive failures are required, and a success
  clears the count. A photo still being written fails once or twice
  and then decodes; genuine garbage gives up and stays gray.
- Grid rebuild preserves the viewport across a live rescan (pins to
  the cell that was on top), so a new photo landing at the top does
  not jump the scroll position.
2026-11-01 18:02:09 -05:00
8f700e7f66 gtauri: clamp viewer pan/zoom to image edges
Pan is now limited to the image bounds (|offset| <= (rendered -
viewport)/2 per axis), so the image can never be dragged off-screen
leaving blank space around it; on a letterboxed axis panning is
locked to centered. Pinch can no longer zoom out past fit. Clamping
lives in vApply() so pan, pinch and reset all share it; still
compositor-only (transform only).
2026-11-01 17:44:14 -05:00
d990627200 gtauri: distance-from-viewport drop policy for ALL jobs
The backlog must never delay on-screen work. Urgent jobs (real
Chromium requests) are now stale-dropped too, not just prefetch:
a fast fling queues urgent work for every band it crosses, and all
of it except the final band is dead — it filled the queue cap and
made fresh on-screen requests wait for the JS retry timer.

Safe because the anchor now settles at the final scroll position
(trailing send), and on-screen cells have idx >= VPORT so they can
never be dropped. A pure LIFO would not fix this: stale jobs sit
at the stack bottom, never popped, still blocking the cap.

Emulator fling test: 309 stale urgent jobs purged, queue peak 28,
all 850 decodable images loaded.
2026-11-01 15:38:22 -05:00
02d1f097ac gtauri: fix deep-scroll stall + instant viewer
Root causes found via per-event tracing (trace.log) + heartbeats:

1. Decode backlog: single worker at ~300ms/photo could not keep up with
   fast long scrolls — phone session ended with a 2400-deep queue
   draining at ~3 cells/s (13+ min to catch up). That was the
   'scroll far down and nothing loads no matter how long I wait' zone.
   - 4 parallel decode workers (~12 photos/s)
   - viewport-aware stale drops: prefetch jobs more than 60 rows behind
     the viewport are dropped, not decoded (fleeing leaves no backlog)
   - Q_CAP bounds the queue; JS 1.5s safety net re-requests
   - queue peak in repro test: 42 (was 2405); all 850 decodable
     emulator images now load (708 before)

2. Stale-anchor bug: sendAnchor was leading-edge throttled with no
   trailing call — if a scroll ended inside the 150ms window the Rust
   anchor stayed stale forever, and the worker then dropped fresh
   URGENT jobs (tap → full read) as 'off-screen'. Fix: trailing
   anchor send; and URGENT jobs are never stale-dropped (only
   prefetch work is droppable).

3. Viewer latency: full-res read ran on Chromium's main thread
   (wry shouldInterceptRequest is synchronous) — 30-50MB flash read
   froze the whole WebView. Now: thumb shown instantly (mem cache,
   ~1ms), full read queued urgent and done off-main; full-ready event
   swaps in the full-res (256MB full-res LRU makes re-opens instant).
   Measured click→full-res: 4ms on emulator.

4. Scan: skip OS junk (._* AppleDouble forks, dotfiles) — the phone's
   DCIM carried 72 of them, rendering as permanent gray cells.

5. Viewer for a corrupt file now shows 'image unavailable' instead of
   'loading…' forever; grid retry timers skip far-off-screen cells.
2026-11-01 09:11:11 -05:00
gmp
e019a950b1 gtauri: Tauri v2 gallery harness WORKING on emulator
Chromium owns scroll/compositor/lazy-load/image-cache; Rust owns
scan/SQLite/thumbnail-decode behind a gallery:// custom protocol.

Hard-won gotchas (see in-code comments):
- Android: no native custom-scheme support → wry rewrites the URL to
  http://gallery.localhost/... (custom_protocol_workaround). The JS
  MUST request that form; the handler receives the reverted
  gallery://localhost/... and must strip the authority.
- tauri_build::build() in build.rs must run UNCONDITIONALLY (build
  scripts run on the host: a cfg(target_os) gate silently disables it,
  which skips the rustc-cfg=mobile emission → no mobile_entry_point →
  .so with no JNI symbols → UnsatisfiedLinkError).
- build.rs must list frontend files for rerun-if-changed (a dir-level
  directive only watches the dir mtime, not content edits) — the .so
  bakes the frontend at compile time and cargo otherwise ships stale
  UI with a 'successful' build.
- logcat drops ~75% of lines under load: use the file trace.
- fetch() is CORS-restricted (page origin http://tauri.localhost);
  <img> is not — add ACAO:* anyway.

Emulator (5853 real files): grid renders, lazy thumbs via
gallery:// with on-disk cache (87 files 35-72KB), FR log clean at
60Hz, viewer opens full-res with compositor-only pan/zoom. The single
'broken' cell is a 17-byte fake test JPEG (correct behavior).
2026-10-31 18:59:51 -04:00
d82ecf74ac harness: tttest — Tauri 2 / WebView scroll-jank testbed (third stack)
The A/B/C harness series: sltest (Slint) / egtest (egui) / tttest
(Tauri 2 → wry → Android WebView/Chromium). Identical scene to
sltest: 8580 full-width rows, 150 px + 2 px divider, alternating
colors, virtualized (26-element DOM pool), custom touch drag +
exponential-decay fling (sltest decay constant 7.42), rAF-driven
frame loop.

FR logging: the rAF callback records gap/cost exactly like the Rust
harnesses; lines batch (~120) and cross the Tauri event bridge once
per second (JNI round trip kept off the per-frame path). Rust side
drains to a dedicated writer thread →
/sdcard/Android/data/wow.gmp.tttest/files/Documents/fr.log
(Tauri document_dir = getExternalFilesDir(DOCUMENTS) — the framework
CREATES it; a raw std::fs mkdir of the app's external tree is
SELinux-denied on Android 11+). Same FR-line format → fr_capture.py
is the referee (its launch check now falls back to the package's
LAUNCHER activity via monkey for non-NativeActivity apps).

Gotchas learned (see frontend/dist/index.html comments):
- touch-action is NOT inherited: touches land on .row, so each row
  must declare touch-action:none or the WebView claims the pan and
  cancels the page's drag (only a few px register).
- Fling velocity must be a per-EVENT EMA; frame-based tracking dies
  when touch events sample slower than rAF (adb swipe ≈ 17 Hz).
- Drag sign: finger up → offset grows (offset -= finger dy).
- Tauri v2 'brownfield' is the NORMAL direct-IPC mode (not an
  app-provides-content mode); the mobile schema rejects
  security.pattern entirely.
- Custom #[tauri::command]s hit the two-pass app-command ACL
  chicken-and-egg; the core:default event bridge avoids it.
- Rust log output needs a logcat backend (log/std +
  __android_log_write) or it is invisible.

Emulator (60 Hz, scripted swipes): 1319 frames, median 16.70 ms,
5 isolated drops (0.38%), all at swipe-injection moments, render
cost med 2 ms. aarch64 phone build compiles (11 MB APK); phone
testing pending (personal-device policy).

Build: harnesses/tttest/scripts/build.sh [x86_64|aarch64] —
cargo-tauri CLI (v2.12.4, prebuilt) drives the gradle build; signed
with the debug keystore.
2026-10-31 13:53:43 -04:00
73f27262f7 harness: sync egtest spin-driver build 2026-10-31 06:18:42 -04:00
47c5c972fe egtest: spin-driver frame pacing + nice -10; fr_capture.py tool; 0.12% drops at 120Hz (vs sltest 0.33-0.83%) 2026-10-31 06:18:20 -04:00
2cfb32c746 harness: egtest — egui 8580-row grid (egui port control experiment) 2026-10-31 00:22:02 -04:00