Workout: restore history/missed/compensations from iCloud (KC-39)
save() pushed all 7 workout keys to iCloud KVS, but init only restored 4 — workout history, missed dates, and rest-day compensations were uploaded yet never restored, so they were lost on reinstall/update. Added the three missing restoreIfMissing calls so restore mirrors save. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1215,3 +1215,33 @@ Added DEBUG-only test hooks (`KISANI_AUTOADD`, `KISANI_VOICE_SIM`) to inject a
|
||||
transcript on the simulator; `#if DEBUG`, compiled out of Release.
|
||||
|
||||
Files: `TodayView.swift` (`NLTaskField.updateUIView`), `ContentView.swift`.
|
||||
|
||||
---
|
||||
|
||||
## KC-39 — Workout state lost on reinstall/update (incomplete iCloud restore)
|
||||
|
||||
**Status:** Fixed (build-verified)
|
||||
**Reported by:** User
|
||||
**Area:** Workout / iCloud sync
|
||||
|
||||
### Description
|
||||
Workout state was lost after app updates / fresh installs.
|
||||
|
||||
### Root cause
|
||||
`save()` pushes 7 workout keys to iCloud KVS (programs, schedule, activePid,
|
||||
completedDates, history, missedDates, compensations), but `WorkoutViewModel.init`
|
||||
only `restoreIfMissing(...)` for the first four. So **history, missed dates, and
|
||||
rest-day compensations** were uploaded to iCloud but never restored on a fresh
|
||||
launch — silently lost on reinstall/update.
|
||||
|
||||
### Fix
|
||||
Added the three missing `restoreIfMissing` calls (`history`, `missedDates`,
|
||||
`compensations`) so restore is symmetric with save. (Per-day `lastActiveDay` is
|
||||
transient set-reset state and intentionally not synced.)
|
||||
|
||||
Files: `ExerciseModels.swift`.
|
||||
|
||||
### Note
|
||||
Cross-device *live* refresh while the app is open isn't wired (`WorkoutViewModel`
|
||||
doesn't observe `kisaniCloudDataRefreshed`) — out of scope; the restore-on-launch
|
||||
path is what preserves state across updates.
|
||||
|
||||
@@ -290,11 +290,15 @@ class WorkoutViewModel: ObservableObject {
|
||||
self.kMissedDates = "kisani.workout.missedDates.\(uid)"
|
||||
self.kCompensations = "kisani.workout.compensations.\(uid)"
|
||||
|
||||
// Restore all workout keys from iCloud if missing locally (fresh install / new build)
|
||||
// Restore all workout keys from iCloud if missing locally (fresh install / new build).
|
||||
// Must cover EVERY key save() pushes, or that state is lost on reinstall/update.
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.programs.\(uid)")
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.schedule.\(uid)")
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.activePid.\(uid)")
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.completedDates.\(uid)")
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.history.\(uid)")
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.missedDates.\(uid)")
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.compensations.\(uid)")
|
||||
|
||||
// ── Attempt to restore persisted state ──
|
||||
if let data = UserDefaults.kisani.data(forKey: kPrograms),
|
||||
|
||||
Reference in New Issue
Block a user