Files
workouts/Workouts Watch App/Views/Workouts/WorkoutDetailView.swift
2025-08-08 21:09:11 -04:00

141 lines
4.6 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// WorkoutDetailView.swift
// Workouts
//
// Created by rzen on 7/22/25 at 9:54PM.
//
// Copyright 2025 Rouslan Zenetl. All Rights Reserved.
//
import SwiftUI
import SwiftData
struct WorkoutDetailView: View {
let workout: Workout
@Environment(\.modelContext) private var modelContext
@Environment(\.dismiss) private var dismiss
@State private var showingCompletedDialog = false
@State private var selectedLog: WorkoutLog? = nil
@State private var navigateToExercise = false
var body: some View {
VStack(alignment: .center, spacing: 8) {
if let logs = workout.logs?.sorted(by: { $0.order < $1.order }), !logs.isEmpty {
List {
ForEach(logs) { log in
Button {
handleExerciseTap(log)
} label: {
WorkoutLogCardView(log: log)
}
.listRowBackground(
RoundedRectangle(cornerRadius: 12)
.fill(Color.secondary.opacity(0.2))
.padding(
EdgeInsets(
top: 4,
leading: 8,
bottom: 4,
trailing: 8
)
)
)
}
}
.listStyle(.carousel)
} else {
Text("No exercises in this workout")
.font(.body)
.foregroundStyle(.secondary)
.padding()
Spacer()
}
}
.navigationDestination(isPresented: $navigateToExercise) {
if let selectedLog = selectedLog {
ExerciseProgressControlView(log: selectedLog)
}
}
.alert("Exercise Completed", isPresented: $showingCompletedDialog) {
Button("Cancel", role: .cancel) {
// Do nothing, just dismiss
}
Button("Restart") {
if let log = selectedLog {
restartExercise(log)
}
}
Button("One More Set") {
if let log = selectedLog {
addOneMoreSet(log)
}
}
} message: {
Text("This exercise is already completed. What would you like to do?")
}
}
private func handleExerciseTap(_ log: WorkoutLog) {
selectedLog = log
switch log.status {
case .notStarted:
// Start from beginning
log.currentStateIndex = 0
try? modelContext.save()
navigateToExercise = true
case .inProgress:
// If we're in a rest state, advance to the next set
if let currentStateIndex = log.currentStateIndex, isRestState(currentStateIndex) {
log.currentStateIndex = currentStateIndex + 1
try? modelContext.save()
}
// Continue from current (possibly updated) position
navigateToExercise = true
case .completed:
// Show dialog for completed exercise
showingCompletedDialog = true
default:
// Default to not started behavior
log.currentStateIndex = 0
try? modelContext.save()
navigateToExercise = true
}
}
private func restartExercise(_ log: WorkoutLog) {
log.status = .notStarted
log.currentStateIndex = 0
log.elapsedSeconds = 0
try? modelContext.save()
navigateToExercise = true
}
private func addOneMoreSet(_ log: WorkoutLog) {
// Increment total sets
log.sets += 1
// Calculate the state index for the additional set
// States: intro(0) set1(1) rest1(2) ... setN(2N-1) done(2N)
// For the additional set, we want to go to setN+1 which is at index 2N+1
let additionalSetStateIndex = (log.sets * 2) - 1
log.status = .inProgress
log.currentStateIndex = additionalSetStateIndex
log.elapsedSeconds = 0
try? modelContext.save()
navigateToExercise = true
}
private func isRestState(_ stateIndex: Int) -> Bool {
// Rest states are at even indices > 0
return stateIndex > 0 && stateIndex % 2 == 0
}
}