Add rest timer with toggle — auto-starts after each set when enabled

Floating banner shows circular progress + MM:SS countdown with skip button.
Haptic + system sound fires when timer reaches zero. Duration and on/off
toggle live in Settings → Rest Timer sheet.

Co-Authored-By: Kutesir <tqwyy79vzn@privaterelay.appleid.com>
This commit is contained in:
Robin Kutesa
2026-06-01 03:30:00 +03:00
parent 0e085f7fec
commit 228607fde6
3 changed files with 243 additions and 34 deletions

View File

@@ -178,6 +178,9 @@ class WorkoutViewModel: ObservableObject {
@Published var activeSections: [WorkoutSection]
@Published var workoutDates: [String] = []
@Published var restTimerSeconds: Int = 60
@Published var restTimerEnabled: Bool = false
@Published var restCountdown: Int = 0
@Published var restTimerTotal: Int = 0
@Published var sessionStartDate: Date? = nil
var streakDays: Int {
@@ -404,12 +407,14 @@ class WorkoutViewModel: ObservableObject {
let ei = activeSections[si].exercises.firstIndex(where: { $0.id == exerciseId }),
let setIdx = activeSections[si].exercises[ei].sets.firstIndex(where: { $0.id == setId })
else { return }
let wasMarkedDone = !activeSections[si].exercises[ei].sets[setIdx].isDone
activeSections[si].exercises[ei].sets[setIdx].isDone.toggle()
if sessionStartDate == nil, activeSections[si].exercises[ei].sets[setIdx].isDone {
sessionStartDate = Date()
}
syncBack()
if doneSets == totalSets && totalSets > 0 { logWorkoutCompleted() }
if wasMarkedDone && restTimerEnabled { startRestTimer() }
}
func addSet(sectionId: UUID, to exerciseId: UUID) {
@@ -495,6 +500,18 @@ class WorkoutViewModel: ObservableObject {
syncBack()
}
// MARK: - Rest Timer
func startRestTimer() {
restTimerTotal = restTimerSeconds
restCountdown = restTimerSeconds
}
func stopRestTimer() {
restCountdown = 0
restTimerTotal = 0
}
private func syncBack() {
guard let idx = programs.firstIndex(where: { $0.id == activeProgramId }) else { return }
programs[idx].sections = activeSections