This commit is contained in:
2025-08-08 21:09:11 -04:00
parent 2f044c3d9c
commit 7bcc5d656c
38 changed files with 776 additions and 159 deletions

View File

@ -28,7 +28,7 @@ struct WorkoutCardView: View {
.font(.headline)
.foregroundStyle(.white)
Text(workout.statusName)
Text("\(workout.statusName)~")
.font(.caption)
.foregroundStyle(Color.accentColor)
}

View File

@ -8,17 +8,24 @@
//
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
NavigationLink {
ExerciseProgressControlView(log: log)
Button {
handleExerciseTap(log)
} label: {
WorkoutLogCardView(log: log)
}
@ -46,5 +53,88 @@ struct WorkoutDetailView: View {
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
}
}

View File

@ -18,7 +18,7 @@ struct WorkoutLogCardView: View {
.font(.headline)
.lineLimit(1)
Text(log.status?.name ?? "Not Started")
Text(getStatusText(for: log))
.font(.caption)
.foregroundStyle(Color.accentColor)
@ -31,4 +31,41 @@ struct WorkoutLogCardView: View {
}
}
}
private func getStatusText(for log: WorkoutLog) -> String {
guard let status = log.status else {
return "Not Started"
}
if status == .inProgress, let currentStateIndex = log.currentStateIndex {
let currentSet = getCurrentSetNumber(stateIndex: currentStateIndex, totalSets: log.sets)
if currentSet > 0 {
return "In Progress, Set #\(currentSet)"
}
}
return status.name
}
private func getCurrentSetNumber(stateIndex: Int, totalSets: Int) -> Int {
// Exercise states are structured as: intro(0) set1(1) rest1(2) set2(3) rest2(4) ... done
// For each set number n, set state index = 2n-1, rest state index = 2n
if stateIndex <= 0 {
return 0 // intro or invalid
}
// Check if we're in a rest state (even indices > 0)
let isRestState = stateIndex > 0 && stateIndex % 2 == 0
if isRestState {
// During rest, show the next set number
let nextSetNumber = (stateIndex / 2) + 1
return min(nextSetNumber, totalSets)
} else {
// During set, show current set number
let currentSetNumber = (stateIndex + 1) / 2
return min(currentSetNumber, totalSets)
}
}
}