Skip to content

Widget: keep the Home-screen widget fresh (publish on background + live battery/connection) (#114)#117

Merged
ryanbr merged 1 commit into
mainfrom
fix-widget-live-freshness
Jul 8, 2026
Merged

Widget: keep the Home-screen widget fresh (publish on background + live battery/connection) (#114)#117
ryanbr merged 1 commit into
mainfrom
fix-widget-live-freshness

Conversation

@ryanbr

@ryanbr ryanbr commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Addresses the data-staleness half of #114 — the iOS Home-screen widget lagging the app (notably "battery not updating").

Cause

WidgetSnapshot.publish only ran on a foreground refreshSeq bump (15-min analyze tick / backfill completion / health sync / .active transition). Two gaps:

  • Live values don't bump refreshSeq. Strap battery % and connection live on model.live, not the repo cache — so while the app was open and battery changed, the widget never refreshed. That's the "battery not updating."
  • Nothing published on the way out — the widget could show a state older than what the user last saw in-app.

Fix

  • Republish on model.live.$batteryPct and $connected changes, foreground-gated (.active). Foreground reloads are budget-exempt, and both are low-frequency (battery ~8 min, connection flips rare), so no throttle needed.
  • Publish once on background/resign, capturing the last in-app state so the widget matches what the user just saw. The app runs bluetooth-central (not suspended in background), so this executes; one reload per app-exit is well within WidgetKit's daily budget.

Honest scope

WidgetKit is still a periodic glance in the background (hard reload budget) — this narrows the app↔widget gap, it doesn't make the widget real-time. Out of scope (separate design calls, not built here): the "Charge" label reading like battery-charge, and the richer illustrations / layout the reporter also asked for. Also worth noting for the reporter: on a WHOOP MG several of these (Charge/HRV) are often No Data/calibrating, so some apparent "inaccuracy" may be the strap, not the widget.

Testing

StrandiOS target — can't build on WSL; a testing build verifies the Swift compiles. Ideally confirmed on-device (widget updates on battery change + after backgrounding).

File: StrandiOS/App/StrandiOSApp.swift.

…+ live battery/connection (#114)

The iOS widget snapshot only republished on a FOREGROUND refreshSeq bump (analyze
tick / backfill / health sync / .active). Two gaps made it lag the app:

- Strap battery % and connection are LIVE state (model.live), not repo-cache, so
  they never bumped refreshSeq — the widget battery never moved while the app was
  open ("battery not updating"). Now republished on those changes, foreground-gated
  (budget-exempt; both low-frequency so no throttle needed).
- Nothing republished on the way out, so the widget could show a state older than
  the user last saw. Now publishes once on background/resign (the app runs
  bluetooth-central so it isn't suspended; one reload per app-exit is budget-safe).

WidgetKit is still a periodic glance in the background (reload budget) — this
narrows the app-vs-widget gap, it doesn't make it real-time. The "Charge reads like
battery" label + richer illustrations from #114 are separate design calls, not here.

StrandiOS target — can't build on WSL; a testing build verifies the Swift compiles.
@ryanbr ryanbr merged commit aa4f2fb into main Jul 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant