import SwiftUI import SwiftData struct ActiveWorkoutSession: View { @Environment(\.modelContext) private var modelContext @Default(\.isWorkingOut) var isWorkingOut @State var isTimerRunning: Bool = true @Query(sort: \WorkoutSession.name) var workoutSessions: [WorkoutSession] @State var activeWorkoutSession: WorkoutSession? @Default(\.activeWorkoutSessionId) var activeWorkoutSessionId @Query(sort: \Workout.name) var workouts: [Workout] @State var activeWorkout: Workout? @Default(\.activeWorkoutId) var activeWorkoutId var body: some View { VStack { List { Section(header: Text("Workout"), footer: Text(activeWorkoutSession?.creationDate.ISO8601Format() ?? "Unknown Date")) { NavigationLink(destination: { ItemPicker(selectedItem: $activeWorkout, items: workouts) }) { Text(activeWorkout?.name ?? "Select Workout") } .onChange(of: activeWorkout) { _, newWorkout in if let newWorkout { activeWorkoutId = newWorkout.id.uuidString activeWorkoutSession?.workout = newWorkout } } } if let activeWorkout { Section(header: Text("Exercises")) { ForEach(getActiveWorkoutItems(activeWorkout: activeWorkout)) { workoutItem in ActiveWorkoutSessionListItem(workoutItem: workoutItem) } } } else { ContentUnavailableView { Label("Select a Workout", systemImage: "arrow.up") } } } // MARK: Workout Controls if (isWorkingOut) { if activeWorkoutSession != nil { ActiveWorkoutSessionControls( session: Binding( get: { self.activeWorkoutSession! }, set: { self.activeWorkoutSession = $0 } )) } } } .navigationTitle("Session") .toolbar { if (isWorkingOut) { Button(action: { isWorkingOut = false activeWorkoutSession?.stop() }) { HStack { Image(systemName: "stop.fill") Text("Stop") } } .bold() .fontDesign(.rounded) .tint(.red) } else { Button(action: { isWorkingOut = true if let activeWorkout { activeWorkoutSession?.start(with: activeWorkout) } }) { HStack { Image(systemName: "play.fill") Text("Start") } } .bold() .fontDesign(.rounded) .tint(.green) } } .onAppear { if let activeWorkoutSession = getItem(from: workoutSessions, by: activeWorkoutSessionId) { self.activeWorkoutSession = activeWorkoutSession if let workout = getItem(from: workouts, by: activeWorkoutId) { self.activeWorkout = workout } } else { createNewWorkoutSession() } } } private func createNewWorkoutSession() { let newWorkoutSession = WorkoutSession() activeWorkoutSessionId = newWorkoutSession.id.uuidString if let selectedWorkout = getItem(from: workouts, by: activeWorkoutId) { newWorkoutSession.workout = selectedWorkout } self.activeWorkoutSession = newWorkoutSession } private func getActiveWorkoutItems(activeWorkout: Workout?) -> [WorkoutItem] { guard let activeWorkout else { return [] } return activeWorkout.getWorkoutItems() } // TODO: Put this somewhere general private func getItem(from array: [Item], by id: String) -> Item? { let filteredItems = array.filter { $0.id == UUID(uuidString: id) } return filteredItems.count == 1 ? filteredItems.first : nil } } #Preview("RR Selected") { @Previewable @State var activeWorkout = Workout.sampleData.first! NavigationStack { ActiveWorkoutSession(activeWorkout: activeWorkout) } .onAppear { Defaults.shared.isWorkingOut = false } .modelContainer(SampleData.shared.modelContainer) } #Preview("No Workout Selected") { NavigationStack { ActiveWorkoutSession() } .onAppear { Defaults.shared.isWorkingOut = false } .modelContainer(SampleData.shared.modelContainer) } #Preview("No Workout Data available") { NavigationStack { ActiveWorkoutSession() } }