Widget: .widgetURL(platform://add-food) on all widget sizes
App: .onOpenURL handles platform://add-food → switches to Fitness
tab and opens the food assistant sheet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Session expires: widget gets 401 → clears stale cookie from
App Group → stops retrying with bad auth → shows cached data
until user opens app and re-authenticates
2. Account switch: login() now calls clearWidgetAuth() BEFORE
syncCookieToWidget() — clears previous user's cached calories
before writing new user's cookie. No brief display of wrong data.
3. Logout: already correct — clearWidgetAuth removes cookie +
cached data, widget shows 0/2000
4. Minimum data: only session cookie + 2 cached numbers + timestamp
in App Group. No passwords, no user IDs, no PII.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widget:
- Fetches /api/fitness/entries/totals and /api/fitness/goals/for-date
directly from gateway using shared session cookie
- Falls back to cached data in App Group UserDefaults if network fails
- Refreshes every 15 minutes via WidgetKit timeline
- Each phone shows the logged-in user's own data
Auth sharing:
- AuthManager.syncCookieToWidget() copies the session cookie to
App Group UserDefaults on login and auth check
- Widget reads cookie and makes authenticated API calls
- Logout clears widget auth + cached data
Data in App Group (group.com.quadjourney.platform):
- widget_sessionCookie: auth token for API calls
- widget_totalCalories: cached fallback
- widget_calorieGoal: cached fallback
- widget_lastUpdate: cache timestamp
HomeViewModel also writes cache on each loadTodayData() as fallback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widget displays:
- systemSmall: calorie ring + "X left" text
- systemMedium: ring + "Calories" / "X of Y" / "X remaining"
- accessoryCircular: gauge ring for lock screen
- accessoryInline: "🔥 845 / 2000 cal" text for lock screen
- accessoryRectangular: linear gauge + calorie count
Data flow: main app writes totalCalories + calorieGoal to
UserDefaults on each loadTodayData(), then calls
WidgetCenter.shared.reloadAllTimelines(). Widget reads on
15-minute refresh cycle.
Note: currently uses standard UserDefaults (same app container).
For production, migrate to App Group UserDefaults so widget
process can read the data. Requires Xcode App Group setup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>