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

@ -85,7 +85,7 @@ struct WorkoutDetailView: View {
List { List {
ForEach(logs) { log in ForEach(logs) { log in
NavigationLink { NavigationLink {
WorkoutLogDetailView(log: log) ExerciseProgressControlView(log: log)
} label: { } label: {
WorkoutLogCardView(log: log) WorkoutLogCardView(log: log)
} }

View File

@ -11,12 +11,15 @@ import SwiftUI
import SwiftData import SwiftData
enum ExerciseState: Identifiable { enum ExerciseState: Identifiable {
case detail
case set(number: Int) case set(number: Int)
case rest(afterSet: Int) case rest(afterSet: Int)
case done case done
var id: String { var id: String {
switch self { switch self {
case .detail:
return "detail"
case .set(let number): case .set(let number):
return "set_\(number)" return "set_\(number)"
case .rest(let afterSet): case .rest(let afterSet):
@ -46,6 +49,13 @@ enum ExerciseState: Identifiable {
} }
return false return false
} }
var isDetail: Bool {
if case .detail = self {
return true
}
return false
}
} }
struct ExerciseProgressControlView: View { struct ExerciseProgressControlView: View {
@ -62,6 +72,10 @@ struct ExerciseProgressControlView: View {
var body: some View { var body: some View {
TabView(selection: $currentStateIndex) { TabView(selection: $currentStateIndex) {
ForEach(Array(exerciseStates.enumerated()), id: \.element.id) { index, state in ForEach(Array(exerciseStates.enumerated()), id: \.element.id) { index, state in
if state.isDetail {
ExerciseDetailView(log: log, onStart: { moveToNextState() })
.tag(index)
} else {
ExerciseStateView( ExerciseStateView(
state: state, state: state,
elapsedSeconds: elapsedSeconds, elapsedSeconds: elapsedSeconds,
@ -72,6 +86,7 @@ struct ExerciseProgressControlView: View {
.tag(index) .tag(index)
} }
} }
}
.tabViewStyle(.page(indexDisplayMode: .never)) .tabViewStyle(.page(indexDisplayMode: .never))
.onChange(of: currentStateIndex) { oldValue, newValue in .onChange(of: currentStateIndex) { oldValue, newValue in
if oldValue != newValue { if oldValue != newValue {
@ -91,17 +106,20 @@ struct ExerciseProgressControlView: View {
private func setupExerciseStates() { private func setupExerciseStates() {
var states: [ExerciseState] = [] var states: [ExerciseState] = []
// Create states for each set and rest period // Add the detail view as the first state
for setNumber in 1...log.sets { states.append(.detail)
states.append(.set(number: setNumber))
// Add rest period after each set except the last one // Create alternating set and rest states based on the log's set count
if setNumber < log.sets { for i in 1...log.sets {
states.append(.rest(afterSet: setNumber)) states.append(.set(number: i))
// 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) states.append(.done)
exerciseStates = states exerciseStates = states
@ -219,30 +237,32 @@ struct ExerciseStateView: View {
return "Resting" return "Resting"
case .done: case .done:
return "Exercise Complete" return "Exercise Complete"
case .detail:
return "Swipe to Start"
} }
} }
private var buttonTitle: String { // private var buttonTitle: String {
switch state { // switch state {
case .set: // case .set:
return "Complete Set" // return "Complete Set"
case .rest: // case .rest:
return "Start Next Set" // return "Start Next Set"
case .done: // case .done:
return "DONE" // return "DONE"
} // }
} // }
private var buttonColor: Color { // private var buttonColor: Color {
switch state { // switch state {
case .set: // case .set:
return .accentColor // return .accentColor
case .rest: // case .rest:
return .orange // return .orange
case .done: // case .done:
return .green // return .green
} // }
} // }
private var timeFormatted: String { private var timeFormatted: String {
let minutes = elapsedSeconds / 60 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 { extension Array {
subscript(safe index: Index) -> Element? { subscript(safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil return indices.contains(index) ? self[index] : nil