diff --git a/WorkoutsPlus/Exercise/Exercise.swift b/WorkoutsPlus/Exercise/Exercise.swift index 5c3cdad..b26152e 100644 --- a/WorkoutsPlus/Exercise/Exercise.swift +++ b/WorkoutsPlus/Exercise/Exercise.swift @@ -10,7 +10,7 @@ import SwiftData @Model final class Exercise { - var name: String + @Attribute(.unique) var name: String static var systemImage = "figure.run" var timestamp: Date @@ -20,11 +20,13 @@ final class Exercise { self.timestamp = timestamp } - static let sampleData = [ - Exercise("Pull-up"), - Exercise("Push-up"), - Exercise("Dips"), - Exercise("Rows"), - Exercise("Split Squat") + static let sampleData: [Exercise] = [ + Exercise("Warm-up"), Exercise("Pull-up Progression"), Exercise("Squat Progression"), + Exercise("Dip Progression"), Exercise("Hinge Progression"), Exercise("Row Progression"), + Exercise("Push-up Progression"), Exercise("Core Triplet"), Exercise("Push"), Exercise("Pull"), + Exercise("Legs"), Exercise("Core"), Exercise("Dips"), Exercise("Chin-ups"), + Exercise("Push-ups"), Exercise("Inverted Rows"), Exercise("Hanging Knee Raises"), + Exercise("Pistol Squats"), Exercise("Hanging Leg Curls"), Exercise("Sissy Squats"), + Exercise("400 m schnell"), Exercise("200 m langsam") ] } diff --git a/WorkoutsPlus/Exercise/ExerciseLibrary.swift b/WorkoutsPlus/Exercise/ExerciseLibrary.swift index d8627d5..1360765 100644 --- a/WorkoutsPlus/Exercise/ExerciseLibrary.swift +++ b/WorkoutsPlus/Exercise/ExerciseLibrary.swift @@ -14,6 +14,8 @@ struct ExerciseLibrary: View { @State private var newExercise: Exercise? + // TODO: Add search bar to the top + var body: some View { NavigationSplitView { Group { @@ -50,6 +52,7 @@ struct ExerciseLibrary: View { AddExercise(exercise: exercise) } // TODO: It's possible to add a boolean here ("Terms accepted y/n"). Maybe add this for empty string + .presentationDetents([.medium]) .interactiveDismissDisabled() } } detail: { diff --git a/WorkoutsPlus/SampleData.swift b/WorkoutsPlus/SampleData.swift index 4d4b106..ecd43d0 100644 --- a/WorkoutsPlus/SampleData.swift +++ b/WorkoutsPlus/SampleData.swift @@ -31,11 +31,19 @@ class SampleData { } func insertSampleData() { + // Erstellt ein Dictionary, um Übungen nach Namen nachzuschlagen + var exercisesDict = [String: Exercise]() + + // Alle Übungen in der Datenbank speichern und im Dictionary ablegen for exercise in Exercise.sampleData { - context.insert(exercise) + if exercisesDict[exercise.name] == nil { + context.insert(exercise) + exercisesDict[exercise.name] = exercise + } } - for workout in Workout.sampleData { + // Workouts erstellen und dabei vorhandene Übungen referenzieren + for workout in Workout.sampleData(using: exercisesDict) { context.insert(workout) } diff --git a/WorkoutsPlus/Workout/AddExerciseToWorkout.swift b/WorkoutsPlus/Workout/AddExerciseToWorkout.swift new file mode 100644 index 0000000..153aab1 --- /dev/null +++ b/WorkoutsPlus/Workout/AddExerciseToWorkout.swift @@ -0,0 +1,84 @@ +// +// AddExerciseToWorkout.swift +// WorkoutsPlus +// +// Created by Felix Förtsch on 22.08.24. +// + +import SwiftUI +import SwiftData + +struct AddExerciseToWorkout: View { + @Environment(\.modelContext) private var modelContext + @Query(sort: \Exercise.name) private var exercises: [Exercise] + + @Bindable var workout: Workout + + var selectedExercises: [Exercise] = [Exercise("Selected")] + + var body: some View { + Group { + if !exercises.isEmpty { + List { + Section(header: Text("Utility")) { + // TODO: Loop, Warm-up, Cool-down are not unique yet. They are special utility types + AddExerciseToWorkoutListItem(Exercise("Loop"), workout) + AddExerciseToWorkoutListItem(Exercise("Warm-up"),workout) + AddExerciseToWorkoutListItem(Exercise("Cool-down"),workout) + } + Section(header: Text("Excersises")) { + ForEach(exercises) { exercise in + AddExerciseToWorkoutListItem(exercise, workout) + } + } + } + } else { + ContentUnavailableView { + // TODO: Add Button that allows adding an exercise + Label("No Exercises", systemImage: Exercise.systemImage) + } + } + } + } +} + +struct AddExerciseToWorkoutListItem: View { + var exercise: Exercise + var workout: Workout + + init(_ exercise: Exercise, _ workout: Workout) { + self.exercise = exercise + self.workout = workout + } + + var body: some View { + Button(action: { + workout.addExercise(exercise) + }) { + HStack { + Text(String(workout.exercises.filter { $0 == exercise }.count)) + .font(.system(size: 14, weight: .bold)) + .foregroundColor(.white) + .frame(width: 20, height: 10) + .padding(8) + .background(Color.blue) + .clipShape(RoundedRectangle(cornerRadius: 8)) + Text(exercise.name) + .foregroundColor(.black) + Spacer() + Image(systemName: "plus.circle.fill") + .foregroundColor(.green) + } + } + } +} + +#Preview("With Sample Data") { + AddExerciseToWorkout(workout: Workout(name: "New Workout")) + .modelContainer(SampleData.shared.modelContainer) +} + +#Preview("Empty Database") { + AddExerciseToWorkout(workout: Workout(name: "New Workout")) + .modelContainer(for: Exercise.self, inMemory: true) +} diff --git a/WorkoutsPlus/Workout/Workout.swift b/WorkoutsPlus/Workout/Workout.swift index 5e2f763..3530e77 100644 --- a/WorkoutsPlus/Workout/Workout.swift +++ b/WorkoutsPlus/Workout/Workout.swift @@ -37,27 +37,32 @@ final class Workout { exercises.append(exercise) } - static let sampleData = [ - Workout(name: "RR", exercises: [ - Exercise("Warm-up"), - Exercise("Pull-up Progression"), Exercise("Squat Progression"), - Exercise("Dip Progression"), Exercise("Hinge Progression"), - Exercise("Row Progression"), Exercise("Push-up Progression"), - Exercise("Core Trilet")]), - Workout(name: "Minimalist", exercises:[ - Exercise("Push"), Exercise("Pull"), - Exercise("Legs"), Exercise("Core")]), - Workout(name: "Rings", exercises: [ - Exercise("Dips"), Exercise("Chin-ups"), - Exercise("Push-ups"), Exercise("Inverted Rows"), - Exercise("Hanging Knee Raises"), Exercise("Pistol Squats"), Exercise("Hanging Leg Curls"), - Exercise("Sissy Squats")]), - Workout(name: "Intervalltraining", exercises: [ - Exercise("400 m schnell"), Exercise("200 m langsam"), - Exercise("400 m schnell"), Exercise("200 m langsam"), - Exercise("400 m schnell"), Exercise("200 m langsam"), - Exercise("400 m schnell"), Exercise("200 m langsam"), - Exercise("400 m schnell"), Exercise("200 m langsam"), - Exercise("400 m schnell"), Exercise("200 m langsam")]) - ] + static func sampleData(using exercisesDict: [String: Exercise]) -> [Workout] { + return [ + Workout(name: "RR", exercises: [ + exercisesDict["Warm-up"]!, exercisesDict["Pull-up Progression"]!, + exercisesDict["Squat Progression"]!, exercisesDict["Dip Progression"]!, + exercisesDict["Hinge Progression"]!, exercisesDict["Row Progression"]!, + exercisesDict["Push-up Progression"]!, exercisesDict["Core Triplet"]! + ]), + Workout(name: "Minimalist", exercises: [ + exercisesDict["Push"]!, exercisesDict["Pull"]!, + exercisesDict["Legs"]!, exercisesDict["Core"]! + ]), + Workout(name: "Rings", exercises: [ + exercisesDict["Dips"]!, exercisesDict["Chin-ups"]!, + exercisesDict["Push-ups"]!, exercisesDict["Inverted Rows"]!, + exercisesDict["Hanging Knee Raises"]!, exercisesDict["Pistol Squats"]!, + exercisesDict["Hanging Leg Curls"]!, exercisesDict["Sissy Squats"]! + ]), + Workout(name: "Intervalltraining", exercises: [ + exercisesDict["400 m schnell"]!, exercisesDict["200 m langsam"]!, + exercisesDict["400 m schnell"]!, exercisesDict["200 m langsam"]!, + exercisesDict["400 m schnell"]!, exercisesDict["200 m langsam"]!, + exercisesDict["400 m schnell"]!, exercisesDict["200 m langsam"]!, + exercisesDict["400 m schnell"]!, exercisesDict["200 m langsam"]!, + exercisesDict["400 m schnell"]!, exercisesDict["200 m langsam"]! + ]) + ] + } } diff --git a/WorkoutsPlus/Workout/WorkoutDetail.swift b/WorkoutsPlus/Workout/WorkoutDetail.swift index 2462298..f563a83 100644 --- a/WorkoutsPlus/Workout/WorkoutDetail.swift +++ b/WorkoutsPlus/Workout/WorkoutDetail.swift @@ -13,6 +13,7 @@ struct WorkoutDetail: View { @Environment(\.modelContext) private var modelContext @Bindable var workout: Workout + @State private var isPresenting = false var body: some View { @@ -26,6 +27,9 @@ struct WorkoutDetail: View { Text(exercise.name) } } + Button(action: addExerciseToWorkout) { + Text("Add") + } } } .navigationBarTitle("Edit \(workout.name)") @@ -36,6 +40,19 @@ struct WorkoutDetail: View { } } } + .sheet(isPresented: $isPresenting) { + NavigationStack { + AddExerciseToWorkout(workout: workout) + } + .presentationDetents([.medium, .large]) + .presentationDragIndicator(.visible) + } + } + + private func addExerciseToWorkout() { + withAnimation { + isPresenting = true + } } private func saveWorkout() { @@ -51,7 +68,7 @@ struct WorkoutDetail: View { #Preview { NavigationStack { - WorkoutDetail(workout: Workout.sampleData[0]) + WorkoutDetail(workout: Workout(name: "RR")) .modelContainer(SampleData.shared.modelContainer) } } diff --git a/WorkoutsPlus/Workout/WorkoutLibrary.swift b/WorkoutsPlus/Workout/WorkoutLibrary.swift index f6eb98b..efa0238 100644 --- a/WorkoutsPlus/Workout/WorkoutLibrary.swift +++ b/WorkoutsPlus/Workout/WorkoutLibrary.swift @@ -34,7 +34,7 @@ struct WorkoutLibrary: View { } } } - .navigationBarTitle("Workouts") + .navigationBarTitle("Workout Templates") .toolbar { ToolbarItem(placement: .topBarLeading) { EditButton() @@ -49,6 +49,7 @@ struct WorkoutLibrary: View { NavigationStack { AddWorkout(workout: workout) } + .presentationDetents([.medium]) .interactiveDismissDisabled() } } detail: {