feat(slint): real offline session entry, token-survival fix, grace producers

Start offline on the login screen now enters a full offline session instead
of an empty shell: session scaffolding at the last user, local library DB +
mixtape migrations, offline cache + cached-ids warm, per-user pref stores,
tray and media controls, playback poll loop, settings snapshot - mirroring
Tauri's activate_offline_session checklist. Refuses when no previous session
exists (never opens the empty user-0 profile).

New offline_mode glue binds the shared engine + connectivity actor for the
app lifetime and owns the per-user SubscriptionStateStore: mark_valid on
every successful login, mark_invalid only on an explicit IneligibleUser
verdict, binary 30-day-grace playback predicate, and the Tauri-mirrored
purge-at-activation consumer (previously the Slint build never opened the
store, leaving the grace model inert).

Token-survival fix: a network-failed session restore no longer clears the
saved OAuth token; only an explicit auth rejection does. login_with_token
now preserves the typed ApiError (CoreError::Api) so callers can tell the
two classes apart.

cc
This commit is contained in:
vicrodh committed 2026-06-09 20:14:35 -06:00
1 parent 35403028da
commit 904b5f7b40
4 files changed
+439 -58

No files matched your search

+5 -1
View File
@@ -297,7 +297,11 @@ impl<A: FrontendAdapter + Send + Sync + 'static> QbzCore<A> {
recoverable: true,
})
.await;
Err(CoreError::AuthFailed(e.to_string()))
// Preserve the typed ApiError: callers must distinguish an
// explicit auth rejection (clear the saved token) from a
// network-class failure (keep it) — stringifying here made
// that impossible and caused the token-clearing-on-boot bug.
Err(CoreError::Api(e))
}
}
}