• v2026.08.01 — Home veil: change-triggered, settle-driven, with refresh feedback
    android / Build + lint + test (push) Successful in 4m42s
    release / Build signed APK (tag releases only) (push) Successful in 4m34s
    release / Build + push container image (push) Successful in 1m37s
    Stable

    bvandeusen released this 2026-07-31 23:38:11 -04:00 | 3 commits to main since this release

    Per-day CalVer. Android-only — no server or web changes, no schema migrations. main CI green on 0cea8298 (lint + detekt + unit tests + signed-debug assemble, plus the image build). Merged via PR #114; closes issue #2327.

    The "Updating your mixes…" veil from v2026.07.14 was reported as "swipes on and off before the update completes in most cases", with "a number of other times where the contents will visibly update without the veil triggering." This is that, fixed at the root rather than re-tuned.

    Most of the churn no longer happens at all

    The veil was papering over a data-layer bug. replaceSection was delete-then-insert, per section and un-transacted, so the observing Flow genuinely emitted emptyList() — a real, visible collapse — before the new ids landed, and did it seven times in sequence. Even unchanged tiles flickered.

    • One @Transaction swap across all seven sections. Room notifies observers only on commit, so the empty gap is never observed and Home swaps in a single emission. (CachedQuarantineDao already carried this exact fix for this exact reason; Home never got it.)
    • distinctUntilChanged on the id list ahead of flatMapLatest, so a section whose contents didn't move no longer tears down and rebuilds every tile's hydration flow.

    The veil is now driven by the screen, not a stopwatch

    Three separate reasons it used to lower early: the old refresh().join() + 500ms measured the network pull, which finishes long before the visible work (ids land → tiles hydrate → artwork loads); a plain isUpdating Boolean cleared in a finally got cleared by whichever of two overlapping refreshes finished first (reconnect and the 03:00 rebuild routinely arrive together); and failures were swallowed, so a failed pull reported success with no retry.

    It now raises, works (retrying behind the veil), then holds until the content has been still for a quiet window and nothing is still loading — with a floor so it can't flash and a hard ceiling so it can never strand you. The ceiling caps the veil, never the refresh.

    It only appears when something actually changed

    A refresh that returns what's already cached raises nothing, so a launch over a warm cache is immediate — no veil hiding an update that isn't happening.

    Artwork no longer pops in after the veil lifts

    Art was the most visible offender and the refresh coroutine can't see it, so the composition reports upward: ServerImage — the single choke point behind every album, artist and playlist cover — counts its in-flight loads into a tracker the veil waits on. Art also crossfades app-wide now, with the placeholder fading out over the same window, which softens the pop everywhere the veil isn't involved.

    And it tells you when nothing changed

    Because an unchanged refresh raises no veil, a pull that found nothing new would otherwise give no response at all. A pull now always produces exactly one piece of feedback: the veil if something changed, "Already up to date" if not, "Couldn't check for updates" if it couldn't reach the server. Only for refreshes you asked for — background checks stay silent rather than toasting on every launch.

    Also veiled now: library-scan completion (Home never reacted to it before), playlist create/update/delete/tracks-changed, manual pull, and the initial load over a warm cache.

    Install

    Install the attached signed APK. Redeploying the server image is optional — it carries no changes in this release; it only matters for offering the new APK to other devices via in-app update.

    Verify on device

    This release is almost entirely about feel, which is the part CI cannot sign off:

    • Open the app on a warm cache → content appears immediately. No veil, no sections collapsing and refilling.
    • Pull to refresh with nothing new → "Already up to date".
    • Pull to refresh after the 03:00 rebuild → the veil wipes on and holds until tiles and their artwork have landed, then wipes off. Nothing should pop in after it lifts.
    • Pull with the server unreachable → "Couldn't check for updates" after it retries; your cached content stays put.
    • First run / cleared cache → skeleton as before, no veil over an empty screen.

    Known and deliberate

    The background freshness sweeper still re-fetches stale metadata, so a single tile can change unannounced. Left unveiled on purpose — raising a full-screen panel for one tile would be worse than the pop, and the new crossfade softens it. Worth revisiting only if it's noticeable in use.

    🤖 Generated with Claude Code

    Downloads