// // WorkoutDetail.swift // WorkoutsPlus // // Created by Felix Förtsch on 10.08.24. // import SwiftUI import SwiftData struct WorkoutDetail: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var modelContext @Default(\.isWorkingOut) var isWorkingOut @Binding var activeWorkoutSession: WorkoutSession? @State var workout: Workout @State private var isPresentingWorkoutItemLibrarySheet = false var numberFormatter: NumberFormatter { let f = NumberFormatter() f.numberStyle = .decimal f.maximumFractionDigits = 0 return f } @State var value: Decimal? = 60 @State var textFieldIsActive: Bool = false @State var defaultRestTime: Double = 45 @State private var selectedMinutes = 0 @State private var selectedSeconds = 0 var body: some View { List { Section( content: { NavigationLink(destination: WorkoutIconSelector(workout: workout)) { TextField("Workout Name", text: $workout.name) Image(systemName: workout.workoutIconSystemName) .scaledToFit() .foregroundStyle(workout.workoutIconColorName.color) } HStack { Text("Default Rest Time (min:s)") Spacer() // TODO: This is f-in horrible. But I need a break rn. NumbersOnlyTextField(value: $defaultRestTime) } }, header: { Text("Name & Icon") }, footer: { Text("Setting a Default Rest Time inserts the time between each exercise.") }) Section( header: Text("Exercises"), footer: Text("Drag and drop to re-arrange or swipe to delete exercises.")) { ForEach(workout.getWorkoutItems()) { workoutItem in WorkoutListItem(workout, workoutItem) } .onDelete(perform: deleteWorkoutItem) .onMove(perform: move) .environment(\.editMode, .constant(.active)) // Always active drag mode AddItemButton(label: "Exercise", action: presentWorkoutItemLibrarySheet) } } .navigationTitle("\(workout.name)") .toolbar { // TODO: Add proper Sharing for workouts. // ToolbarItem() { ShareLink(item: URL(filePath: "felixfoertsch.de")!) } 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 activeWorkoutSession = workout.start() }) { HStack { Image(systemName: "play.fill") Text("Start") } } .bold() .fontDesign(.rounded) .tint(.green) } } .sheet(isPresented: $isPresentingWorkoutItemLibrarySheet) { WorkoutItemLibrarySheet(workout: workout) } } private func presentWorkoutItemLibrarySheet() { withAnimation { isPresentingWorkoutItemLibrarySheet = true } } private func saveWorkout() { if modelContext.hasChanges { do { try modelContext.save() } catch { print("Failed to save workout: \(error.localizedDescription)") } } } private func deleteWorkoutItem(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(workout.getWorkoutItems()[index]) } try? modelContext.save() } } private func move(from source: IndexSet, to destination: Int) { workout.moveWorkoutItem(from: source, to: destination) } } #Preview { @Previewable @State var activeWorkoutSession: WorkoutSession? NavigationStack { WorkoutDetail(activeWorkoutSession: $activeWorkoutSession, workout: Workout.sampleData.first!) .modelContainer(SampleData.shared.modelContainer) } } #Preview("Debug") { @Previewable @State var activeWorkoutSession: WorkoutSession? TabView { WorkoutDetail(activeWorkoutSession: $activeWorkoutSession, workout: Workout.sampleData.first!) .tabItem { Image(systemName: "figure.run.square.stack") Text("Workouts") } DebugList() .tabItem { Image(systemName: "hammer") Text("Debug") } } .modelContainer(SampleData.shared.modelContainer) }