wip
This commit is contained in:
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user