Bundling the background-refresh worker (originally planned as
vc=60) into the same release as cache controls — they're both
storage-and-refresh user-facing knobs, ships cleaner together.
- StrawApp.onCreate calls FeedRefreshScheduler.applyFromSettings
- R8 keep rule for FeedRefreshWorker (same reason as
UpdateCheckWorker — WorkManager instantiates via reflection)
- Settings UI: 'Auto-refresh subs' toggle (default off) +
interval chip-row (30min / 1h / 6h) shown when enabled. Lives
in the existing Local cache section since it's the same
storage-and-refresh theme.
Worker calls uniffi.strawcore.subscriptionFeed which fans out 50
parallel RSS fetches in Rust — 50 subs refreshes in ~1-2s in the
background. Writes per-channel into FeedCacheStore so next cold
open of Subs paints instantly.
WorkManager periodic worker hits the repo's index-v2.json, parses
the highest versionCode for our package, compares with
BuildConfig.VERSION_CODE. When newer: posts a notification with
ACTION_VIEW on the APK URL — Android's DownloadManager picks it up
and the system installer takes over. No INSTALL_PACKAGES perm
needed.
Settings:
- Check for updates toggle (default on — closing NewPipe's silent
staleness gap is the explicit motivation)
- Interval picker (1h / 6h / 24h, default 6h — WorkManager has a
15-min periodic floor anyway)
- Last-checked timestamp + 'update available' tag when caught-up
state is dirty
- Check now button — runs the same path as the worker so behaviors
stay identical
Cold start fires one check too so users see pending updates without
waiting a full interval.
R8 keep-rule for UpdateCheckWorker added — WorkManager instantiates
workers by name via reflection.
R8 (minify + resource-shrink) flipped on for BOTH debug AND release
variants — we publish the debug APK to fdroid (per existing
pipeline), and the audit-flagged Log.d strip discipline required R8
to actually run on the variant we ship.
New strawApp/proguard-rules.pro covers:
* UniFFI bindings (uniffi.strawcore.*) — reflective FFI dispatch
from Rust side, must survive minification
* JNA — Library subclasses reflectively loaded by name
* kotlinx-serialization @Serializable — generated $$serializer
companions, kept via both the package-anchored rule and the
annotation-wildcard rule for belt + suspenders
* Media3 session Parcelables (cross-process via Binder)
* Compose runtime + Strawcore exception hierarchy
Surface-handoff polish on inline ↔ fullscreen transitions:
setKeepContentOnPlayerReset(true) on both PlayerViews (inline in
VideoDetail + fullscreen Player). When the detaching view's player
is nulled on dispose, it holds the last rendered frame instead of
flashing black. The receiving view's surface takeover then renders
the next frame without the ~1-frame black gap. Round-4 audit
HIGH-5 was the closest writeup.
Expected APK-size win from R8: ~30-40%. Need real-device
verification post-install — the keep rules are best-effort and a
missing rule manifests as runtime ClassNotFoundException or
silently-broken kotlinx-serialization decoding.