This commit is contained in:
2025-07-20 20:20:39 -04:00
parent a0c8b21bf4
commit d2b8625f2e
2 changed files with 103 additions and 37 deletions

View File

@ -11,12 +11,15 @@ import SwiftUI
import SwiftData
enum ExerciseState: Identifiable {
case detail
case set(number: Int)
case rest(afterSet: Int)
case done
var id: String {
switch self {
case .detail:
return "detail"
case .set(let number):
return "set_\(number)"
case .rest(let afterSet):
@ -46,6 +49,13 @@ enum ExerciseState: Identifiable {
}
return false
}
var isDetail: Bool {
if case .detail = self {
return true
}
return false
}
}
struct ExerciseProgressControlView: View {
@ -62,14 +72,19 @@ struct ExerciseProgressControlView: View {
var body: some View {
TabView(selection: $currentStateIndex) {
ForEach(Array(exerciseStates.enumerated()), id: \.element.id) { index, state in
ExerciseStateView(
state: state,
elapsedSeconds: elapsedSeconds,
onComplete: {
moveToNextState()
}
)
.tag(index)
if state.isDetail {
ExerciseDetailView(log: log, onStart: { moveToNextState() })
.tag(index)
} else {
ExerciseStateView(
state: state,
elapsedSeconds: elapsedSeconds,
onComplete: {
moveToNextState()
}
)
.tag(index)
}
}
}
.tabViewStyle(.page(indexDisplayMode: .never))
@ -91,17 +106,20 @@ struct ExerciseProgressControlView: View {
private func setupExerciseStates() {
var states: [ExerciseState] = []
// Create states for each set and rest period
for setNumber in 1...log.sets {
states.append(.set(number: setNumber))
// Add the detail view as the first state
states.append(.detail)
// Create alternating set and rest states based on the log's set count
for i in 1...log.sets {
states.append(.set(number: i))
// Add rest period after each set except the last one
if setNumber < log.sets {
states.append(.rest(afterSet: setNumber))
// Add rest after each set except the last one
if i < log.sets {
states.append(.rest(afterSet: i))
}
}
// Add done state at the end
// Add the final DONE state
states.append(.done)
exerciseStates = states
@ -219,30 +237,32 @@ struct ExerciseStateView: View {
return "Resting"
case .done:
return "Exercise Complete"
case .detail:
return "Swipe to Start"
}
}
private var buttonTitle: String {
switch state {
case .set:
return "Complete Set"
case .rest:
return "Start Next Set"
case .done:
return "DONE"
}
}
// private var buttonTitle: String {
// switch state {
// case .set:
// return "Complete Set"
// case .rest:
// return "Start Next Set"
// case .done:
// return "DONE"
// }
// }
private var buttonColor: Color {
switch state {
case .set:
return .accentColor
case .rest:
return .orange
case .done:
return .green
}
}
// private var buttonColor: Color {
// switch state {
// case .set:
// return .accentColor
// case .rest:
// return .orange
// case .done:
// return .green
// }
// }
private var timeFormatted: String {
let minutes = elapsedSeconds / 60
@ -251,7 +271,53 @@ struct ExerciseStateView: View {
}
}
// Extension to safely access array elements
// Detail view shown as the first item in the exercise progress carousel
struct ExerciseDetailView: View {
let log: WorkoutLog
let onStart: () -> Void
var body: some View {
VStack(alignment: .center, spacing: 16) {
Text(log.exerciseName)
.font(.title)
.lineLimit(1)
.minimumScaleFactor(0.5)
.layoutPriority(1)
HStack(alignment: .bottom) {
Text("\(log.weight)")
Text("lbs")
.fontWeight(.light)
.padding([.trailing], 10)
Text("\(log.sets)")
Text("×")
.fontWeight(.light)
Text("\(log.reps)")
}
.font(.title3)
.lineLimit(1)
.minimumScaleFactor(0.5)
.layoutPriority(1)
Text(log.status?.name ?? "Not Started")
.foregroundStyle(Color.accentColor)
// Spacer()
//
// Button(action: onStart) {
// Text("Start Exercise")
// .font(.headline)
// .frame(maxWidth: .infinity)
// }
// .buttonStyle(.borderedProminent)
// .tint(.accentColor)
}
.padding()
}
}
// Helper extension to safely access array elements
extension Array {
subscript(safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil