fix: reset workout log each new day + new app logo
KC-1: Set completion was stored permanently on the program, so the same program scheduled on back-to-back days (e.g. Shoulders Mon + Tue) kept yesterday's checkmarks. Add resetSetsForNewDayIfNeeded() to clear every set's isDone when the calendar day changes (cold launch, onAppear, and scenePhase active). Streak history is untouched. KC-2: Replace all 12 AppIcon sizes with the new KisaniCal mark, alpha flattened onto RGB(26,29,34) so the 1024 App Store icon is fully opaque. Add KisaniCal/ISSUES.md tracker (KC-1, KC-2: In Progress). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -208,6 +208,7 @@ class WorkoutViewModel: ObservableObject {
|
||||
private let kSchedule: String
|
||||
private let kActivePid: String
|
||||
private let kWorkoutDates: String
|
||||
private let kLastActiveDay: String
|
||||
|
||||
init() {
|
||||
let uid = AuthManager.shared.currentUser?.id ?? "shared"
|
||||
@@ -215,6 +216,7 @@ class WorkoutViewModel: ObservableObject {
|
||||
self.kSchedule = "kisani.workout.schedule.\(uid)"
|
||||
self.kActivePid = "kisani.workout.activePid.\(uid)"
|
||||
self.kWorkoutDates = "kisani.workout.completedDates.\(uid)"
|
||||
self.kLastActiveDay = "kisani.workout.lastActiveDay.\(uid)"
|
||||
|
||||
// Restore all workout keys from iCloud if missing locally (fresh install / new build)
|
||||
CloudSyncManager.shared.restoreIfMissing(key: "kisani.workout.programs.\(uid)")
|
||||
@@ -284,6 +286,7 @@ class WorkoutViewModel: ObservableObject {
|
||||
activeSections = blank.sections
|
||||
}
|
||||
workoutDates = UserDefaults.kisani.stringArray(forKey: kWorkoutDates) ?? []
|
||||
resetSetsForNewDayIfNeeded()
|
||||
}
|
||||
|
||||
private func save() {
|
||||
@@ -300,6 +303,36 @@ class WorkoutViewModel: ObservableObject {
|
||||
CloudSyncManager.shared.push(value: workoutDates, forKey: kWorkoutDates)
|
||||
}
|
||||
|
||||
// MARK: - Daily Reset
|
||||
/// A fresh calendar day starts a clean log. If the checkbox state currently on
|
||||
/// screen belongs to an earlier day, wipe every set's `isDone` so re-running the
|
||||
/// same program on back-to-back days (e.g. Shoulders on Mon AND Tue) starts
|
||||
/// unchecked. Streak history (`workoutDates`) is never touched here.
|
||||
/// Safe to call repeatedly — it only does work when the day actually changes.
|
||||
func resetSetsForNewDayIfNeeded() {
|
||||
let today = iso.string(from: Date())
|
||||
let last = UserDefaults.kisani.string(forKey: kLastActiveDay)
|
||||
guard last != today else { return }
|
||||
if last != nil { clearAllDoneSets() } // skip the wipe on the very first launch
|
||||
UserDefaults.kisani.set(today, forKey: kLastActiveDay)
|
||||
}
|
||||
|
||||
/// Unchecks every set across all programs and clears the in-progress session.
|
||||
private func clearAllDoneSets() {
|
||||
for pi in programs.indices {
|
||||
for si in programs[pi].sections.indices {
|
||||
for ei in programs[pi].sections[si].exercises.indices {
|
||||
for setIdx in programs[pi].sections[si].exercises[ei].sets.indices {
|
||||
programs[pi].sections[si].exercises[ei].sets[setIdx].isDone = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
activeSections = programs.first { $0.id == activeProgramId }?.sections ?? activeSections
|
||||
sessionStartDate = nil
|
||||
save()
|
||||
}
|
||||
|
||||
func logWorkoutCompleted(on date: Date = Date()) {
|
||||
let key = iso.string(from: date)
|
||||
guard !workoutDates.contains(key) else { return }
|
||||
@@ -452,6 +485,8 @@ class WorkoutViewModel: ObservableObject {
|
||||
else { return }
|
||||
let wasMarkedDone = !activeSections[si].exercises[ei].sets[setIdx].isDone
|
||||
activeSections[si].exercises[ei].sets[setIdx].isDone.toggle()
|
||||
// The current checkbox state now belongs to today.
|
||||
UserDefaults.kisani.set(iso.string(from: Date()), forKey: kLastActiveDay)
|
||||
if sessionStartDate == nil, activeSections[si].exercises[ei].sets[setIdx].isDone {
|
||||
sessionStartDate = Date()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user