1b5c764ee8
Three reliability bugs made data inconsistent: 1. Empty-overwrite: a failed or partial fetch returned an empty UsageData that the worker/app saved unconditionally, wiping the last good reading and blanking the widget. Added UsageData.mergedWith() so a fetch that returns nothing usable keeps the previous snapshot, and a partial fetch falls back per-metric. Never blank again. 2. No in-app auto-refresh: onResume only refreshed when the cache was >5 min old and there was no live timer. Replaced with a foreground lifecycle loop that refreshes on open and every 30s while visible, always painting cached data first. Manual button keeps the spinner; the loop is silent. App refresh now also pushes the widget update. 3. Spurious logout: a single transient 401/403 (e.g. a Cloudflare challenge) called clearSession() immediately, logging the user out and showing "Not signed in". Now clears only after 3 consecutive auth failures; the counter resets on any successful read. Battery-friendly: no foreground service. Background widget refresh stays on the existing alarm + 15-min WorkManager, but with the merge fix the widget always shows the last data it pulled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>