Persist listened places, fix restart-on-reopen bug, add stats/reset
Five behavior changes from live testing feedback: 1. Narration no longer leads with the place title — the body text already opens with the name, so it was read twice. 2. "Done" is now derived from a persisted set of listened place IDs (UserPrefsDataStore.listenedPlaceIds), not an in-memory index set that got wiped on every load. A place that's ever been narrated to completion — in the guide list or the detail screen — is never auto-narrated again, including across the 60s re-scan and app restarts. Auto-advance now skips straight to the next unlistened place instead of walking sequentially. Settings has a new "reset listened places" button. 3. TtsManager is now keyed by place id: calling speak() for the place that's already playing just re-attaches the onDone callback instead of restarting via QUEUE_FLUSH. Fixes opening a place's detail screen while the guide list is already narrating it restarting playback from the beginning. Marking a place "listened" now also lives in TtsManager itself (on natural onDone, not onError/onStop), so it's correct regardless of which screen was driving playback. 4. Settings now shows "Listened: X of Y (Z%)" against the total place count for the city. 5. Search radius changed from 10km to 2km (client default in PlacesRepository/MapViewModel, and the backend's own default for consistency) — but the result count is uncapped, same as before; every place within the radius is returned regardless of how many that is. Caught a real bug while testing the "skip listened" change: the new listenedPlaceIds collector ran in a separate coroutine that hadn't necessarily delivered its first value before the initial loadNearby() call, so freshly-loaded listened state could be missed on cold start. Fixed by awaiting listenedPlaceIds.first() synchronously before the first load, with a separate .drop(1) collector for later changes (e.g. the reset button). Also hardened GuideViewModelTest with try/finally around viewModelScope.cancel() — a failing assertion was skipping cleanup and turning into a 5+ minute hang instead of a fast failure, since the 60s re-scan loop was never cancelled. Verified: testDebugUnitTest passes (4/4), assembleDebug produces a working APK, sent to Telegram. Backend pytest still passes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
f6735db46f
commit
cd428d0fb7
13 changed files with 254 additions and 56 deletions
|
|
@ -25,7 +25,7 @@ def nearby(
|
|||
min_results: int = Query(default=5, ge=1, le=50),
|
||||
initial_radius_m: int = Query(default=300, ge=50, le=5000),
|
||||
step_m: int = Query(default=200, ge=50, le=5000),
|
||||
max_radius_m: int = Query(default=5000, ge=100, le=20000),
|
||||
max_radius_m: int = Query(default=2000, ge=100, le=20000),
|
||||
speed: float | None = Query(
|
||||
default=None,
|
||||
description="Reserved for v2: user's speed in m/s. Currently accepted but ignored.",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue