// // ExerciseView.swift // Workouts // // Created by rzen on 7/18/25 at 5:44 PM. // // Copyright 2025 Rouslan Zenetl. All Rights Reserved. // import SwiftUI import CoreData import Charts struct ExerciseView: View { @Environment(\.managedObjectContext) private var viewContext @Environment(\.dismiss) private var dismiss @ObservedObject var workoutLog: WorkoutLog var allLogs: [WorkoutLog] var currentIndex: Int = 0 @State private var progress: Int = 0 @State private var navigateTo: WorkoutLog? = nil let notStartedColor = Color.white let completedColor = Color.green var body: some View { Form { Section(header: Text("Navigation")) { HStack { Button(action: navigateToPrevious) { HStack { Image(systemName: "chevron.left") Text("Previous") } } .disabled(currentIndex <= 0) Spacer() Text("\(currentIndex + 1) of \(allLogs.count)") .foregroundColor(.secondary) Spacer() Button(action: navigateToNext) { HStack { Text("Next") Image(systemName: "chevron.right") } } .disabled(currentIndex >= allLogs.count - 1) } .padding(.vertical, 8) } Section(header: Text("Progress")) { LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: Int(workoutLog.sets)), spacing: 2) { ForEach(1...Int(workoutLog.sets), id: \.self) { index in ZStack { let completed = index <= progress let color = completed ? completedColor : notStartedColor RoundedRectangle(cornerRadius: 8) .fill( LinearGradient( gradient: Gradient(colors: [color, color.darker(by: 0.2)]), startPoint: .topLeading, endPoint: .bottomTrailing ) ) .aspectRatio(0.618, contentMode: .fit) .shadow(radius: 2) Text("\(index)") .foregroundColor(.primary) .colorInvert() } .onTapGesture { if progress == index { progress = 0 } else { progress = index } updateLogStatus() } } } } Section(header: Text("Plan")) { Stepper("\(workoutLog.sets) sets", value: Binding( get: { Int(workoutLog.sets) }, set: { workoutLog.sets = Int32($0) } ), in: 1...10) .font(.title) Stepper("\(workoutLog.reps) reps", value: Binding( get: { Int(workoutLog.reps) }, set: { workoutLog.reps = Int32($0) } ), in: 1...25) .font(.title) HStack { Text("\(workoutLog.weight) lbs") VStack(alignment: .trailing) { Stepper("", value: Binding( get: { Int(workoutLog.weight) }, set: { workoutLog.weight = Int32($0) } ), in: 1...500) Stepper("", value: Binding( get: { Int(workoutLog.weight) }, set: { workoutLog.weight = Int32($0) } ), in: 1...500, step: 5) } } .font(.title) } Section(header: Text("Progress Tracking")) { WeightProgressionChartView(exerciseName: workoutLog.exerciseName) } } .navigationTitle(workoutLog.exerciseName) .navigationDestination(item: $navigateTo) { nextLog in ExerciseView( workoutLog: nextLog, allLogs: allLogs, currentIndex: allLogs.firstIndex(where: { $0.objectID == nextLog.objectID }) ?? 0 ) } .onAppear { progress = Int(workoutLog.currentStateIndex) } .onDisappear { saveChanges() } } private func updateLogStatus() { workoutLog.currentStateIndex = Int32(progress) if progress >= Int(workoutLog.sets) { workoutLog.status = .completed } else if progress > 0 { workoutLog.status = .inProgress } else { workoutLog.status = .notStarted } saveChanges() } private func saveChanges() { try? viewContext.save() } private func navigateToPrevious() { guard currentIndex > 0 else { return } let previousIndex = currentIndex - 1 navigateTo = allLogs[previousIndex] } private func navigateToNext() { guard currentIndex < allLogs.count - 1 else { return } let nextIndex = currentIndex + 1 navigateTo = allLogs[nextIndex] } }