import SwiftUI import SwiftData import WatchKit // Enum to track the current phase of the exercise enum ExercisePhase { case notStarted case exercising(setNumber: Int) case resting(setNumber: Int, elapsedSeconds: Int) case completed } struct ExerciseProgressView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss let log: WorkoutLog @State private var phase: ExercisePhase = .notStarted @State private var hapticSeconds: Int = 0 @State private var restSeconds: Int = 0 @State private var hapticTimer: Timer? = nil @State private var restTimer: Timer? = nil var body: some View { ScrollView { VStack(spacing: 15) { exerciseHeader switch phase { case .notStarted: startPhaseView case .exercising(let setNumber): exercisingPhaseView(setNumber: setNumber) case .resting(let setNumber, let elapsedSeconds): restingPhaseView(setNumber: setNumber, elapsedSeconds: elapsedSeconds) case .completed: completedPhaseView } } .padding() } .navigationTitle(log.exerciseName) .navigationBarTitleDisplayMode(.inline) .onDisappear { stopTimers() } .gesture( DragGesture(minimumDistance: 50) .onEnded { gesture in if gesture.translation.width < 0 { // Swipe left - progress to next phase handleSwipeLeft() } else if gesture.translation.height < 0 && gesture.translation.height < -50 { // Swipe up - cancel current set handleSwipeUp() } } ) } // MARK: - View Components private var exerciseHeader: some View { VStack(alignment: .leading, spacing: 5) { Text(log.exerciseName) .font(.headline) .foregroundColor(.primary) Text("\(log.sets) sets × \(log.reps) reps") .font(.subheadline) .foregroundColor(.secondary) Text("\(log.weight) lbs") .font(.subheadline) .foregroundColor(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.bottom, 5) } private var startPhaseView: some View { VStack(spacing: 20) { Text("Ready to start?") .font(.headline) Button(action: startFirstSet) { Text("Start First Set") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .tint(.blue) } } private func exercisingPhaseView(setNumber: Int) -> some View { VStack(spacing: 20) { Text("Set \(setNumber) of \(log.sets)") .font(.headline) Text("Exercising...") .foregroundColor(.secondary) HStack(spacing: 20) { Button(action: completeSet) { Text("Complete") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .tint(.green) Button(action: cancelSet) { Text("Cancel") .frame(maxWidth: .infinity) } .buttonStyle(.bordered) .tint(.red) } Text("Or swipe left to complete") .font(.caption) .foregroundColor(.secondary) Text("Swipe up to cancel") .font(.caption) .foregroundColor(.secondary) } } private func restingPhaseView(setNumber: Int, elapsedSeconds: Int) -> some View { VStack(spacing: 20) { Text("Rest after Set \(setNumber)") .font(.headline) Text("Rest time: \(formatSeconds(elapsedSeconds))") .foregroundColor(.secondary) if setNumber < (log.sets) { Button(action: { startNextSet(after: setNumber) }) { Text("Start Set \(setNumber + 1)") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .tint(.blue) Text("Or swipe left to start next set") .font(.caption) .foregroundColor(.secondary) } else { Button(action: completeExercise) { Text("Complete Exercise") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .tint(.green) Text("Or swipe left to complete") .font(.caption) .foregroundColor(.secondary) } } } private var completedPhaseView: some View { VStack(spacing: 20) { Text("Exercise Completed!") .font(.headline) .foregroundColor(.green) Image(systemName: "checkmark.circle.fill") .font(.system(size: 50)) .foregroundColor(.green) Button(action: { dismiss() }) { Text("Return to Workout") .frame(maxWidth: .infinity) } .buttonStyle(.borderedProminent) .tint(.blue) } } // MARK: - Action Handlers private func handleSwipeLeft() { switch phase { case .notStarted: startFirstSet() case .exercising: completeSet() case .resting(let setNumber, _): if setNumber < (log.sets) { startNextSet(after: setNumber) } else { completeExercise() } case .completed: dismiss() } } private func handleSwipeUp() { if case .exercising = phase { cancelSet() } } private func startFirstSet() { phase = .exercising(setNumber: 1) startHapticTimer() } private func startNextSet(after completedSetNumber: Int) { stopTimers() let nextSetNumber = completedSetNumber + 1 phase = .exercising(setNumber: nextSetNumber) startHapticTimer() } private func completeSet() { stopTimers() if case .exercising(let setNumber) = phase { // Start rest timer phase = .resting(setNumber: setNumber, elapsedSeconds: 0) startRestTimer() startHapticTimer() // Play completion haptic HapticFeedback.success() } } private func cancelSet() { // Just go back to the previous state stopTimers() phase = .notStarted } private func completeExercise() { stopTimers() // Update workout log log.completed = true log.status = .completed try? modelContext.save() // Show completion screen phase = .completed // Play completion haptic HapticFeedback.success() } // MARK: - Timer Management private func startHapticTimer() { hapticSeconds = 0 hapticTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in hapticSeconds += 1 // Provide haptic feedback based on time intervals if hapticSeconds % 60 == 0 { // Triple tap every 60 seconds HapticFeedback.tripleTap() } else if hapticSeconds % 30 == 0 { // Double tap every 30 seconds HapticFeedback.doubleTap() } else if hapticSeconds % 10 == 0 { // Light tap every 10 seconds HapticFeedback.click() } } } private func startRestTimer() { restSeconds = 0 restTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in restSeconds += 1 if case .resting(let setNumber, _) = phase { phase = .resting(setNumber: setNumber, elapsedSeconds: restSeconds) } } } private func stopTimers() { hapticTimer?.invalidate() hapticTimer = nil restTimer?.invalidate() restTimer = nil } // MARK: - Helper Functions private func formatSeconds(_ seconds: Int) -> String { let minutes = seconds / 60 let remainingSeconds = seconds % 60 return String(format: "%d:%02d", minutes, remainingSeconds) } } //#Preview { // let config = ModelConfiguration(isStoredInMemoryOnly: true) // let container = try! ModelContainer(for: SchemaV1.models, configurations: config) // // // Create sample data // let exercise = Exercise(name: "Bench Press", sets: 3, reps: 8, weight: 60.0) // let workout = Workout(name: "Chest Day", date: Date()) // let log = WorkoutLog(exercise: exercise, workout: workout) // // NavigationStack { // ExerciseProgressView(log: log) // .modelContainer(container) // } //}