diff --git a/WorkoutsPlus/DebugExerciseList.swift b/WorkoutsPlus/DebugExerciseList.swift index 6db0f8d..c0f1674 100644 --- a/WorkoutsPlus/DebugExerciseList.swift +++ b/WorkoutsPlus/DebugExerciseList.swift @@ -9,7 +9,7 @@ import SwiftUI import SwiftData struct DebugExerciseList: View { - @Query(sort: \Exercise.name) private var exercises: [Exercise] + @Query(sort: \WorkoutItem.name) private var exercises: [WorkoutItem] var body: some View { List { diff --git a/WorkoutsPlus/Exercise/AddExercise.swift b/WorkoutsPlus/Exercise/AddExercise.swift index 57c4dee..bc1e795 100644 --- a/WorkoutsPlus/Exercise/AddExercise.swift +++ b/WorkoutsPlus/Exercise/AddExercise.swift @@ -11,16 +11,16 @@ struct AddExercise: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss - @Bindable var exerciseTemplate: ExerciseTemplate + @Bindable var exercise: Exercise var body : some View { Form { - TextField("Workout Name", text: $exerciseTemplate.name) + TextField("Workout Name", text: $exercise.name) } .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { - modelContext.delete(exerciseTemplate) + modelContext.delete(exercise) dismiss() } } @@ -36,6 +36,6 @@ struct AddExercise: View { #Preview { Color.clear .sheet(isPresented: .constant(true)) { - AddExercise(exerciseTemplate: ExerciseTemplate("")) + AddExercise(exercise: Exercise("")) } } diff --git a/WorkoutsPlus/Exercise/Exercise.swift b/WorkoutsPlus/Exercise/Exercise.swift index 08a123e..ac5767a 100644 --- a/WorkoutsPlus/Exercise/Exercise.swift +++ b/WorkoutsPlus/Exercise/Exercise.swift @@ -2,48 +2,33 @@ // Exercise.swift // WorkoutsPlus // -// Created by Felix Förtsch on 10.08.24. +// Created by Felix Förtsch on 25.08.24. // import Foundation import SwiftData @Model -final class Exercise: Identifiable { - var id = UUID() - var name: String +final class Exercise { + static var systemImage = "figure.run" + @Attribute(.unique) var name: String + var metric: String = "reps" + // var exerciseDescription: ExerciseDescription? - var workout: Workout? - var position: Int = 0 + var timestamp: Date = Date.now - var exerciseTemplate: ExerciseTemplate? { - didSet { - self.name = exerciseTemplate?.name ?? "self.name" - } - } - var reps: Int = 0 - - init(_ reps: Int, _ exercise: String) { - self.name = exercise - self.reps = reps - self.exerciseTemplate = ExerciseTemplate(exercise) + init(_ name: String = "") { + self.name = name } - // 8x Dips - init(from exerciseTemplate: ExerciseTemplate) { - self.name = exerciseTemplate.name - self.exerciseTemplate = exerciseTemplate - } -} - -extension Exercise { - static let sampleData: [Exercise] = { - var exercises = [Exercise]() - - for exerciseTemplate in ExerciseTemplate.sampleData { - exercises.append(Exercise(from: exerciseTemplate)) - } - - return exercises - }() + static let sampleData: [Exercise] = [ + 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") + ] } diff --git a/WorkoutsPlus/Exercise/ExerciseDetail.swift b/WorkoutsPlus/Exercise/ExerciseDetail.swift index 182b131..6e04abf 100644 --- a/WorkoutsPlus/Exercise/ExerciseDetail.swift +++ b/WorkoutsPlus/Exercise/ExerciseDetail.swift @@ -11,12 +11,12 @@ struct ExerciseDetail: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var modelContext - @Bindable var exerciseTemplate: ExerciseTemplate + @Bindable var exercise: Exercise var body: some View { Form { - TextField("Exercise Name", text: $exerciseTemplate.name) + TextField("Exercise Name", text: $exercise.name) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Save") { @@ -41,5 +41,5 @@ struct ExerciseDetail: View { } #Preview { - ExerciseDetail(exerciseTemplate: ExerciseTemplate.sampleData.first!) + ExerciseDetail(exercise: Exercise.sampleData.first!) } diff --git a/WorkoutsPlus/Exercise/ExerciseLibrary.swift b/WorkoutsPlus/Exercise/ExerciseLibrary.swift index 336804f..d4c039a 100644 --- a/WorkoutsPlus/Exercise/ExerciseLibrary.swift +++ b/WorkoutsPlus/Exercise/ExerciseLibrary.swift @@ -10,19 +10,19 @@ import SwiftData struct ExerciseLibrary: View { @Environment(\.modelContext) private var modelContext - @Query(sort: \ExerciseTemplate.name) private var exerciseTemplates: [ExerciseTemplate] + @Query(sort: \Exercise.name) private var exercises: [Exercise] - @State private var newExerciseTemplate: ExerciseTemplate = ExerciseTemplate("") + @State private var newExercise: Exercise = Exercise("") @State private var newExerciseName: String = "" - @State private var isAddingExerciseTemplate: Bool = false + @State private var isAddingExercise: Bool = false @FocusState private var isInputFieldFocused: Bool @State private var searchText: String = "" - var filteredItems: [ExerciseTemplate] { + var filteredItems: [Exercise] { if searchText.isEmpty { - return exerciseTemplates + return exercises } else { - return exerciseTemplates.filter { $0.name.localizedCaseInsensitiveContains(searchText) } + return exercises.filter { $0.name.localizedCaseInsensitiveContains(searchText) } } } @@ -32,24 +32,24 @@ struct ExerciseLibrary: View { NavigationView { Group { List { - ForEach(filteredItems) { exerciseTemplate in + ForEach(filteredItems) { exercise in NavigationLink { - ExerciseDetail(exerciseTemplate: exerciseTemplate) + ExerciseDetail(exercise: exercise) } label: { - Text(exerciseTemplate.name) + Text(exercise.name) } } .onDelete(perform: deleteExercise) - if isAddingExerciseTemplate { + if isAddingExercise { TextField("New Exercise", text: $newExerciseName, onCommit: { - newExerciseTemplate.name = newExerciseName - saveExercise(exerciseTemplate: newExerciseTemplate) - isAddingExerciseTemplate = false + newExercise.name = newExerciseName + save(exercise: newExercise) + isAddingExercise = false }) .textInputAutocapitalization(.words) .focused($isInputFieldFocused) } - AddItemButton(label: "Exercise", action: addExerciseTemplate) + AddItemButton(label: "Exercise", action: addExercise) } .searchable(text: $searchText) } @@ -62,18 +62,18 @@ struct ExerciseLibrary: View { } } - private func addExerciseTemplate() { + private func addExercise() { withAnimation { - newExerciseTemplate = ExerciseTemplate("") + newExercise = Exercise("") newExerciseName = "" - isAddingExerciseTemplate = true + isAddingExercise = true isInputFieldFocused = true } } - private func saveExercise(exerciseTemplate: ExerciseTemplate) { - if !exerciseTemplate.name.isEmpty { - modelContext.insert(exerciseTemplate) + private func save(exercise: Exercise) { + if !exercise.name.isEmpty { + modelContext.insert(exercise) try? modelContext.save() } } @@ -81,7 +81,7 @@ struct ExerciseLibrary: View { private func deleteExercise(offsets: IndexSet) { withAnimation { for index in offsets { - modelContext.delete(exerciseTemplates[index]) + modelContext.delete(exercises[index]) } try? modelContext.save() } @@ -95,6 +95,6 @@ struct ExerciseLibrary: View { #Preview("Empty Database") { ExerciseLibrary() - .modelContainer(for: Exercise.self, inMemory: true) + .modelContainer(for: WorkoutItem.self, inMemory: true) } diff --git a/WorkoutsPlus/Exercise/ExerciseTemplate.swift b/WorkoutsPlus/Exercise/ExerciseTemplate.swift deleted file mode 100644 index 93932ab..0000000 --- a/WorkoutsPlus/Exercise/ExerciseTemplate.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// ExerciseTemplate.swift -// WorkoutsPlus -// -// Created by Felix Förtsch on 25.08.24. -// - -import Foundation -import SwiftData - -@Model -final class ExerciseTemplate { - static var systemImage = "figure.run" - @Attribute(.unique) var name: String - var metric: String = "reps" - // var exerciseDescription: ExerciseDescription? - - var timestamp: Date = Date.now - - init(_ name: String = "") { - self.name = name - } - - static let sampleData: [ExerciseTemplate] = [ - ExerciseTemplate("Dips"), - ExerciseTemplate("Chin-ups"), - ExerciseTemplate("Push-ups"), - ExerciseTemplate("Inverted Rows"), - ExerciseTemplate("Hanging Knee Raises"), - ExerciseTemplate("Pistol Squats"), - ExerciseTemplate("Hanging Leg Curls"), - ExerciseTemplate("Sissy Squats") - ] -} diff --git a/WorkoutsPlus/SampleData.swift b/WorkoutsPlus/SampleData.swift index ee4e060..ee987c8 100644 --- a/WorkoutsPlus/SampleData.swift +++ b/WorkoutsPlus/SampleData.swift @@ -19,7 +19,7 @@ class SampleData { } private init() { - let schema = Schema([Exercise.self, ExerciseTemplate.self, Workout.self]) + let schema = Schema([WorkoutItem.self, Exercise.self, Workout.self]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) do { @@ -31,14 +31,14 @@ class SampleData { } func insertSampleData() { - for exerciseTemplate in ExerciseTemplate.sampleData { - context.insert(exerciseTemplate) - } - for exercise in Exercise.sampleData { context.insert(exercise) } + for workoutItem in WorkoutItem.sampleData { + context.insert(workoutItem) + } + for workout in Workout.sampleData { context.insert(workout) } diff --git a/WorkoutsPlus/Workout/AddExerciseToWorkout.swift b/WorkoutsPlus/Workout/AddExerciseToWorkout.swift index e1417a3..dadcb3c 100644 --- a/WorkoutsPlus/Workout/AddExerciseToWorkout.swift +++ b/WorkoutsPlus/Workout/AddExerciseToWorkout.swift @@ -10,24 +10,24 @@ import SwiftData struct AddExerciseToWorkout: View { @Environment(\.modelContext) private var modelContext - @Query(sort: \ExerciseTemplate.name) private var exerciseTemplates: [ExerciseTemplate] + @Query(sort: \Exercise.name) private var exercises: [Exercise] @Bindable var workout: Workout var body: some View { Group { - if !exerciseTemplates.isEmpty { + if !exercises.isEmpty { List { Section(header: Text("Excersises")) { - ForEach(exerciseTemplates) { exerciseTemplate in - AddExerciseToWorkoutListItem(exerciseTemplate, workout) + ForEach(exercises) { exercise in + AddExerciseToWorkoutListItem(exercise, workout) } } } } else { ContentUnavailableView { // TODO: Add Button that allows adding an exercise - Label("No Exercises", systemImage: ExerciseTemplate.systemImage) + Label("No Exercises", systemImage: Exercise.systemImage) } } } @@ -37,20 +37,20 @@ struct AddExerciseToWorkout: View { struct AddExerciseToWorkoutListItem: View { @Environment(\.modelContext) private var modelContext - var exerciseTemplate: ExerciseTemplate + var exercise: Exercise var workout: Workout - init(_ exerciseTemplate: ExerciseTemplate, _ workout: Workout) { - self.exerciseTemplate = exerciseTemplate + init(_ exercise: Exercise, _ workout: Workout) { + self.exercise = exercise self.workout = workout } var body: some View { Button(action: { - workout.addExercise(from: exerciseTemplate) + workout.addExercise(exercise) }) { HStack { - Text(exerciseTemplate.name) + Text(exercise.name) .foregroundStyle(.black) Spacer() Image(systemName: "plus.circle.fill") @@ -67,5 +67,5 @@ struct AddExerciseToWorkoutListItem: View { #Preview("Empty Database") { AddExerciseToWorkout(workout: Workout.sampleData.first!) - .modelContainer(for: ExerciseTemplate.self, inMemory: true) + .modelContainer(for: Exercise.self, inMemory: true) } diff --git a/WorkoutsPlus/Workout/Workout.swift b/WorkoutsPlus/Workout/Workout.swift index 2130b0c..a4d0947 100644 --- a/WorkoutsPlus/Workout/Workout.swift +++ b/WorkoutsPlus/Workout/Workout.swift @@ -17,23 +17,23 @@ final class Workout: Identifiable { // Other properties and methods var timestamp: Date = Date.now - @Relationship(deleteRule: .cascade) var exercises: [Exercise] = [] + @Relationship(deleteRule: .cascade) var exercises: [WorkoutItem] = [] init(name: String) { self.name = name } - func addExercise(from exerciseTemplate: ExerciseTemplate) { - self.exercises.append(Exercise(from: exerciseTemplate)) - updateExercisePositions() - } - func addExercise(_ exercise: Exercise) { - self.exercises.append(exercise) + self.exercises.append(WorkoutItem(from: exercise)) updateExercisePositions() } - func addExercise(_ exercises: [Exercise]) { +// func addExercise(_ exercise: WorkoutItem) { +// self.exercises.append(exercise) +// updateExercisePositions() +// } + + func addExercise(_ exercises: [WorkoutItem]) { for exercise in exercises { self.exercises.append(exercise) } @@ -54,13 +54,13 @@ final class Workout: Identifiable { } extension Workout { - private convenience init(name: String, exercises: [Exercise]) { + private convenience init(name: String, exercises: [WorkoutItem]) { self.init(name: name) self.exercises = exercises } static let sampleData: [Workout] = [ - Workout(name: "Recommended Routine", exercises: Exercise.sampleData), - Workout(name: "Marathon Plan", exercises: Exercise.sampleData) + Workout(name: "Recommended Routine", exercises: WorkoutItem.sampleData), + Workout(name: "Marathon Plan", exercises: WorkoutItem.sampleData) ] } diff --git a/WorkoutsPlus/Workout/WorkoutDetail.swift b/WorkoutsPlus/Workout/WorkoutDetail.swift index 2d46fb0..f005187 100644 --- a/WorkoutsPlus/Workout/WorkoutDetail.swift +++ b/WorkoutsPlus/Workout/WorkoutDetail.swift @@ -82,9 +82,9 @@ struct WorkoutDetail: View { struct ExerciseListItem: View { var workout: Workout - @State var exercise: Exercise + @State var exercise: WorkoutItem - init(_ workout: Workout, _ exercise: Exercise ) { + init(_ workout: Workout, _ exercise: WorkoutItem ) { self.workout = workout self.exercise = exercise } diff --git a/WorkoutsPlus/Workout/WorkoutItem.swift b/WorkoutsPlus/Workout/WorkoutItem.swift new file mode 100644 index 0000000..3ed6065 --- /dev/null +++ b/WorkoutsPlus/Workout/WorkoutItem.swift @@ -0,0 +1,66 @@ +// +// Exercise.swift +// WorkoutsPlus +// +// Created by Felix Förtsch on 10.08.24. +// + +import Foundation +import SwiftData + +@Model +final class WorkoutItem: Identifiable { + var id = UUID() + var name: String + var workoutItemType: WorkoutItemType + + var workout: Workout? + var children: [WorkoutItem] = [] + var position: Int = 0 + + var exercise: Exercise? { + didSet { + self.name = exercise?.name ?? "self.name" + } + } + var reps: Int = 0 + + init(_ reps: Int, _ exercise: String) { + self.workoutItemType = .exercise + + self.name = exercise + self.reps = reps + self.exercise = Exercise(exercise) + } + + init(from exercise: Exercise) { + self.workoutItemType = .exercise + + self.name = exercise.name + self.exercise = exercise + } + + func addChild(_ child: WorkoutItem) { + self.children.append(child) + } +} + +extension WorkoutItem { + enum WorkoutItemType: Codable { + case set + case workout + case exercise + } +} + +extension WorkoutItem { + static let sampleData: [WorkoutItem] = { + var exercises = [WorkoutItem]() + + for exercise in Exercise.sampleData { + exercises.append(WorkoutItem(from: exercise)) + } + + return exercises + }() +} diff --git a/WorkoutsPlus/Workout/WorkoutLibrary.swift b/WorkoutsPlus/Workout/WorkoutLibrary.swift index ed963fb..88d2a18 100644 --- a/WorkoutsPlus/Workout/WorkoutLibrary.swift +++ b/WorkoutsPlus/Workout/WorkoutLibrary.swift @@ -41,23 +41,13 @@ struct WorkoutLibrary: View { if isAddingWorkout { // TODO: On tap-out of the text field, it should lose focus TextField("New Workout", text: $newWorkoutName, onCommit: { - saveWorkout(workout: newWorkout) + save(workout: newWorkout) }) .textInputAutocapitalization(.words) .focused($isInputFieldFocused) } - Button(action: { - if isAddingWorkout { - saveWorkout(workout: newWorkout) - } - addWorkout() - }) { - HStack { - Image(systemName: "plus.circle.fill") - .foregroundStyle(.green) - Text("Add Workout") - } - } + // TODO: When pressing the button again, it should check if something is being added already and if yes, save it. + AddItemButton(label: "Workout", action: addWorkout) } .searchable(text: $searchText) } @@ -80,7 +70,7 @@ struct WorkoutLibrary: View { } // TODO: Brauchen wir das? - private func saveWorkout(workout: Workout) { + private func save(workout: Workout) { withAnimation { newWorkout.name = newWorkoutName if !workout.name.isEmpty { diff --git a/WorkoutsPlus/WorkoutsPlusApp.swift b/WorkoutsPlus/WorkoutsPlusApp.swift index b30556a..d1f9426 100644 --- a/WorkoutsPlus/WorkoutsPlusApp.swift +++ b/WorkoutsPlus/WorkoutsPlusApp.swift @@ -12,8 +12,8 @@ import SwiftData struct WorkoutsPlusApp: App { var sharedModelContainer: ModelContainer = { let schema = Schema([ + WorkoutItem.self, Exercise.self, - ExerciseTemplate.self, Workout.self ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)