From 370e070fcd4b3b6745e220c4e7d4ffbcab4727be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Tue, 12 Nov 2024 14:47:59 +0100 Subject: [PATCH] clean up ActiveWorkoutSession --- WorkoutsPlus/Components/ValueKeyboard.swift | 1 - WorkoutsPlus/ContentView.swift | 2 +- .../Features/Exercise/AddExercise.swift | 92 ++++++++++++++ WorkoutsPlus/Features/Exercise/Exercise.swift | 49 +++----- .../Features/Exercise/ExerciseDetail.swift | 56 +++++++-- .../Features/Exercise/ExerciseEditor.swift | 117 ------------------ .../Features/Exercise/ExerciseLibrary.swift | 14 +-- .../Features/Exercise/ExerciseType.swift | 29 +++++ .../Features/Exercise/ExerciseUnit.swift | 19 +-- .../Features/Workout/WorkoutItem.swift | 7 +- .../Features/Workout/WorkoutListItem.swift | 4 +- .../Features/WorkoutLog/WorkoutLogItem.swift | 19 +++ .../WorkoutLogs.swift} | 6 +- .../WorkoutSession/ActiveWorkoutSession.swift | 22 ++-- .../ActiveWorkoutSessionControls.swift | 11 +- .../ActiveWorkoutSessionListItem.swift | 23 ++-- .../WorkoutSession/WorkoutSession.swift | 33 ++--- .../WorkoutSession/WorkoutSessionItem.swift | 7 +- WorkoutsPlus/WorkoutsPlusApp.swift | 1 + WorkoutsPlus/er-diagram.md | 7 +- 20 files changed, 281 insertions(+), 238 deletions(-) create mode 100644 WorkoutsPlus/Features/Exercise/AddExercise.swift delete mode 100644 WorkoutsPlus/Features/Exercise/ExerciseEditor.swift create mode 100644 WorkoutsPlus/Features/Exercise/ExerciseType.swift create mode 100644 WorkoutsPlus/Features/WorkoutLog/WorkoutLogItem.swift rename WorkoutsPlus/Features/{Home/WorkoutLog.swift => WorkoutLog/WorkoutLogs.swift} (97%) diff --git a/WorkoutsPlus/Components/ValueKeyboard.swift b/WorkoutsPlus/Components/ValueKeyboard.swift index 71d9ed1..daabfa6 100644 --- a/WorkoutsPlus/Components/ValueKeyboard.swift +++ b/WorkoutsPlus/Components/ValueKeyboard.swift @@ -142,7 +142,6 @@ struct ValueKeyboard: View { @Previewable @State var isPresented: Bool = true let value = 0 - let unit = ExerciseMetric.allCases VStack { // ValueKeyboard(isPresented: $isPresented, value: value, unit: unit) diff --git a/WorkoutsPlus/ContentView.swift b/WorkoutsPlus/ContentView.swift index c7f1fb6..42b54f4 100644 --- a/WorkoutsPlus/ContentView.swift +++ b/WorkoutsPlus/ContentView.swift @@ -136,7 +136,7 @@ struct ContentView: View { case .workoutLibrary: WorkoutLibrary(activeWorkoutSession: $activeWorkoutSession) case .workoutLog: - WorkoutLog() + WorkoutLogs() case .exerciseLibrary: ExerciseLibrary() case .settings: diff --git a/WorkoutsPlus/Features/Exercise/AddExercise.swift b/WorkoutsPlus/Features/Exercise/AddExercise.swift new file mode 100644 index 0000000..15772d5 --- /dev/null +++ b/WorkoutsPlus/Features/Exercise/AddExercise.swift @@ -0,0 +1,92 @@ +// +// AddExercise.swift +// WorkoutsPlus +// +// Created by Felix Förtsch on 21.09.24. +// + +import SwiftUI +import SwiftData + +struct AddExercise: View { + @Environment(\.modelContext) private var modelContext + @Environment(\.dismiss) private var dismiss + var isPresentedAsSheet: Bool = false + + @State var exercise: Exercise = Exercise("") + + @State private var name: String = "" + @State private var description: String = "" + @State private var type = ExerciseType("") + @State private var unit = ExerciseUnit("", symbol: "") + + @State private var isPartOfProgression: Bool = false + + @Query(sort: \ExerciseType.name) private var exerciseTypes: [ExerciseType] + @Query(sort: \ExerciseUnit.name) private var exerciseUnits: [ExerciseUnit] + + var body: some View { + NavigationStack { + VStack { + Form { + Section { + TextField("Exercise Name", text: $name) + // TODO: Add Autocomplete + TextEditorWithPlaceholder(text: $description, placeholder: "Description (optional)") + } + Section(footer: Text(""" + Examples: + • Pull-up → None + • Weighted Pull-up → Weight + • Sprint → Time or Distance + """)) { + Picker("Exercise Type", selection: $type) { + ForEach(exerciseTypes, id: \.self) { type in + Text("\(type.name)").tag(type as ExerciseType?) + } + } + .pickerStyle(NavigationLinkPickerStyle()) + Picker("Exercise Unit", selection: $unit) { + ForEach(exerciseUnits, id: \.self) { unit in + Text("\(unit.name) (\(unit.symbol))").tag(unit as ExerciseUnit?) + } + } + .pickerStyle(NavigationLinkPickerStyle()) + } + } + .navigationTitle("Add New Exercise") + .toolbar { + if isPresentedAsSheet { + ToolbarItem(placement: .cancellationAction) { + Button("Cancel", role: .cancel) { + dismiss() + } + } + } + ToolbarItem(placement: .confirmationAction) { + Button("Save") { + withAnimation { + save() + dismiss() + } + } + } + } + } + } + } + + private func save() { + let exerciseToSave = Exercise(name) + modelContext.insert(exerciseToSave) + + exerciseToSave.name = name + exerciseToSave.exerciseDescription = description + exerciseToSave.type = type + exerciseToSave.isPartOfProgression = isPartOfProgression + } +} + +#Preview { + AddExercise() +} diff --git a/WorkoutsPlus/Features/Exercise/Exercise.swift b/WorkoutsPlus/Features/Exercise/Exercise.swift index 4a038ba..09b89a0 100644 --- a/WorkoutsPlus/Features/Exercise/Exercise.swift +++ b/WorkoutsPlus/Features/Exercise/Exercise.swift @@ -26,53 +26,42 @@ final class Exercise: Nameable { @Attribute(.unique) var name: String var exerciseDescription = "" - var metric = ExerciseMetric.none - var unit: ExerciseUnit + var type: ExerciseType? + var unit: ExerciseUnit? var isPartOfProgression = false var equipment: [Equipment] = [] - init(_ name: String, _ metric: ExerciseMetric = .none) { + init(_ name: String) { self.name = name - self.metric = metric - self.unit = ExerciseUnit(name: "Meters", symbol: "m") } } -enum ExerciseMetric: String, Codable, CaseIterable, Identifiable { - case none = "" - case distance = "Distance" - case time = "Time" - case weight = "Weight" - - var id: Self { self } -} - extension Exercise { static let sampleDataRecommendedRoutine: [Exercise] = [ Exercise("Shoulder Band Warm-up"), Exercise("Squat Sky Reaches"), - Exercise("GMB Wrist Prep", .time), + Exercise("GMB Wrist Prep"), Exercise("Dead Bugs"), - Exercise("Pull-up Progression", .weight), - Exercise("Dip Progression", .weight), - Exercise("Squat Progression", .weight), - Exercise("Hinge Progression", .weight), - Exercise("Row Progression", .weight), - Exercise("Push-up Progression", .weight), - Exercise("Handstand Practice", .time), - Exercise("Support Practice", .time) + Exercise("Pull-up Progression"), + Exercise("Dip Progression"), + Exercise("Squat Progression"), + Exercise("Hinge Progression"), + Exercise("Row Progression"), + Exercise("Push-up Progression"), + Exercise("Handstand Practice"), + Exercise("Support Practice") ] static let sampleDataRings: [Exercise] = [ - Exercise("Dips", .weight), - Exercise("Chin-ups", .weight), - Exercise("Push-ups", .weight), - Exercise("Inverted Rows", .weight), - Exercise("Hanging Knee Raises", .weight), - Exercise("Pistol Squats", .weight), - Exercise("Hanging Leg Curls", .weight), + 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/Features/Exercise/ExerciseDetail.swift b/WorkoutsPlus/Features/Exercise/ExerciseDetail.swift index a46dec6..89ea371 100644 --- a/WorkoutsPlus/Features/Exercise/ExerciseDetail.swift +++ b/WorkoutsPlus/Features/Exercise/ExerciseDetail.swift @@ -6,26 +6,64 @@ // import SwiftUI +import SwiftData struct ExerciseDetail: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var modelContext @State var exercise: Exercise + @State private var description: String = "" + @State private var isPartOfProgression: Bool = false + + @State private var type: ExerciseType? + @State private var unit: ExerciseUnit? + + @Query(sort: \ExerciseType.name) private var exerciseTypes: [ExerciseType] + @Query(sort: \ExerciseUnit.name) private var exerciseUnits: [ExerciseUnit] var body: some View { Form { - TextField("Exercise Name", text: $exercise.name) - .toolbar { - ToolbarItem(placement: .topBarTrailing) { - Button("Save") { - saveItem() - dismiss() - } + Section { + TextField("Exercise Name", text: $exercise.name) + TextEditorWithPlaceholder(text: $description, placeholder: "Description (optional)") + } + Section(footer: Text(""" + Examples: + • Pull-up → None + • Weighted Pull-up → Weight + • Sprint → Time or Distance + """)) { + Picker("Exercise Type", selection: $type) { + ForEach(exerciseTypes, id: \.self) { type in + Text("\(type.name)").tag(type as ExerciseType?) } } + .pickerStyle(NavigationLinkPickerStyle()) + Picker("Exercise Unit", selection: $unit) { + ForEach(exerciseUnits, id: \.self) { unit in + Text("\(unit.name) (\(unit.symbol))").tag(unit as ExerciseUnit?) + } + } + .pickerStyle(NavigationLinkPickerStyle()) + } + Section(footer: Text("Feature coming soon.")) { + Toggle(isOn: $isPartOfProgression) { + Text("Exercise is Part of a Progression") + .foregroundStyle(.gray) + } + .disabled(true) + } + } + .navigationTitle("Edit Exercise") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button("Save") { + saveItem() + dismiss() + } + } } - .navigationTitle("Exercise Details") } private func saveItem() { @@ -41,6 +79,6 @@ struct ExerciseDetail: View { #Preview { NavigationStack { - ExerciseDetail(exercise: Exercise.sampleDataRecommendedRoutine.first!) + ExerciseDetail(exercise: Exercise("Squat Sky Reaches")) } } diff --git a/WorkoutsPlus/Features/Exercise/ExerciseEditor.swift b/WorkoutsPlus/Features/Exercise/ExerciseEditor.swift deleted file mode 100644 index d599fb6..0000000 --- a/WorkoutsPlus/Features/Exercise/ExerciseEditor.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// AddExercise.swift -// WorkoutsPlus -// -// Created by Felix Förtsch on 21.09.24. -// - -import SwiftUI -import SwiftData - -struct ExerciseEditor: View { - @Environment(\.modelContext) private var modelContext - @Environment(\.dismiss) private var dismiss - var isPresentedAsSheet: Bool = false - - @State var exercise: Exercise? - - @State private var name: String = "" - @State private var description: String = "" - @State private var metric = ExerciseMetric.none - @State private var unit = ExerciseUnit(name: "", symbol: "") - - @State private var isPartOfProgression: Bool = false - - let exerciseUnits = ExerciseUnit.getUnits - - var body: some View { - NavigationStack { - VStack { - ScrollViewReader { proxy in - VStack { - Form { - Section { - TextField("Exercise Name", text: $name) - // TODO: Add Autocomplete - TextEditorWithPlaceholder(text: $description, placeholder: "Description (optional)") - } - Section(footer: Text(""" - Examples: - • Pull-up → None - • Weighted Pull-up → Weight - • Sprint → Time or Distance - """)) { - Picker("Exercise Metric", selection: $metric) { - ForEach(ExerciseMetric.allCases) { metric in - Text(metric.rawValue.isEmpty ? "None" : metric.rawValue) - .tag(metric) - } - } - .pickerStyle(SegmentedPickerStyle()) - Picker("Select Exercise Unit", selection: $unit) { - ForEach(exerciseUnits, id: \.self) { unit in - Text("\(unit.name) (\(unit.symbol))").tag(unit as ExerciseUnit?) - } - } - .pickerStyle(NavigationLinkPickerStyle()) - } - Section(footer: Text("Feature coming soon.")) { - Toggle(isOn: $isPartOfProgression) { - Text("Exercise is Part of a Progression") - .foregroundStyle(.gray) - } - .disabled(true) - } - } - .navigationTitle("Edit") - .toolbar { - if isPresentedAsSheet { - ToolbarItem(placement: .cancellationAction) { - Button("Cancel", role: .cancel) { - dismiss() - } - } - } - ToolbarItem(placement: .confirmationAction) { - Button("Save") { - withAnimation { - save() - dismiss() - } - } - } - } - } - .onAppear { - if let exercise { - self.name = exercise.name - self.description = exercise.exerciseDescription - self.metric = exercise.metric - self.isPartOfProgression = exercise.isPartOfProgression - } - } - } - } - } - } - - private func save() { - let exerciseToSave: Exercise - - if let exercise = exercise { - exerciseToSave = exercise - } else { - exerciseToSave = Exercise(name) - modelContext.insert(exerciseToSave) - } - - exerciseToSave.name = name - exerciseToSave.exerciseDescription = description - exerciseToSave.metric = metric - exerciseToSave.isPartOfProgression = isPartOfProgression - } -} - -#Preview { - ExerciseEditor() -} diff --git a/WorkoutsPlus/Features/Exercise/ExerciseLibrary.swift b/WorkoutsPlus/Features/Exercise/ExerciseLibrary.swift index 07566a5..76b8d8c 100644 --- a/WorkoutsPlus/Features/Exercise/ExerciseLibrary.swift +++ b/WorkoutsPlus/Features/Exercise/ExerciseLibrary.swift @@ -31,17 +31,7 @@ struct ExerciseLibrary: View { List { Section { ForEach(filteredItems) { exercise in - NavigationLink { - ExerciseEditor(exercise: exercise) - } label: { - HStack { - Text(exercise.name) - Spacer() -// Text(exercise.metric.rawValue) -// .font(.footnote) -// .foregroundStyle(.gray) - } - } + NavigationLink(destination: ExerciseDetail(exercise: exercise), label: {Text(exercise.name)}) } .onDelete(perform: deleteExercise) if filteredItems.isEmpty { @@ -66,7 +56,7 @@ struct ExerciseLibrary: View { } } .sheet(isPresented: $isAddingExercise) { - ExerciseEditor(isPresentedAsSheet: true) + AddExercise(isPresentedAsSheet: true) } } diff --git a/WorkoutsPlus/Features/Exercise/ExerciseType.swift b/WorkoutsPlus/Features/Exercise/ExerciseType.swift new file mode 100644 index 0000000..d3d08fc --- /dev/null +++ b/WorkoutsPlus/Features/Exercise/ExerciseType.swift @@ -0,0 +1,29 @@ +// +// ExerciseType.swift +// WorkoutsPlus +// +// Created by Felix Förtsch on 09.11.24. +// + +import Foundation +import SwiftData + +@Model +final class ExerciseType: Identifiable { + @Attribute(.unique) var name: String + + @Relationship(deleteRule: .nullify, inverse: \Exercise.type) + var exercises = [Exercise]() + + init(_ name: String) { + self.name = name + } +} + +extension ExerciseType { + static let getTypes = [ + ExerciseType("Kilograms"), + ExerciseType("Kilometers"), + ExerciseType("Meters"), + ] +} diff --git a/WorkoutsPlus/Features/Exercise/ExerciseUnit.swift b/WorkoutsPlus/Features/Exercise/ExerciseUnit.swift index 04df016..c964e14 100644 --- a/WorkoutsPlus/Features/Exercise/ExerciseUnit.swift +++ b/WorkoutsPlus/Features/Exercise/ExerciseUnit.swift @@ -9,20 +9,23 @@ import Foundation import SwiftData @Model -final class ExerciseUnit: Unit { - var name: String - var symbol: String +final class ExerciseUnit: Unit, Identifiable { + @Attribute(.unique) var name: String + @Attribute(.unique) var symbol: String - init(name: String, symbol: String) { + @Relationship(deleteRule: .cascade, inverse: \Exercise.unit) + var exercises = [Exercise]() + + init(_ name: String, symbol: String) { self.name = name self.symbol = symbol } } -extension ExerciseUnit: Identifiable { +extension ExerciseUnit { static let getUnits = [ - ExerciseUnit(name: "Kilograms", symbol: "kg"), - ExerciseUnit(name: "Kilometers", symbol: "km"), - ExerciseUnit(name: "Meters", symbol: "m"), + ExerciseUnit("Kilograms", symbol: "kg"), + ExerciseUnit("Kilometers", symbol: "km"), + ExerciseUnit("Meters", symbol: "m"), ] } diff --git a/WorkoutsPlus/Features/Workout/WorkoutItem.swift b/WorkoutsPlus/Features/Workout/WorkoutItem.swift index c3153a2..da02d2c 100644 --- a/WorkoutsPlus/Features/Workout/WorkoutItem.swift +++ b/WorkoutsPlus/Features/Workout/WorkoutItem.swift @@ -45,8 +45,9 @@ final class WorkoutItem: Nameable, Positionable { var exercise: Exercise // Do Push-up | Run Marathon var plannedReps: Int // 8 times | 1 time var plannedValue: Double // With 10 | 42,187 - var unit: ExerciseUnit - var metric: ExerciseMetric? // kg (weight) | km (distance) + + var unit: ExerciseUnit? + var type: ExerciseType? enum WorkoutItemType: Codable { case exercise @@ -64,8 +65,6 @@ final class WorkoutItem: Nameable, Positionable { self.plannedReps = 1 // 0 self.plannedValue = 0 - // kg - self.unit = exercise.unit } // init(set: [WorkoutItem] = []) { diff --git a/WorkoutsPlus/Features/Workout/WorkoutListItem.swift b/WorkoutsPlus/Features/Workout/WorkoutListItem.swift index cc9e499..e2a0ddc 100644 --- a/WorkoutsPlus/Features/Workout/WorkoutListItem.swift +++ b/WorkoutsPlus/Features/Workout/WorkoutListItem.swift @@ -44,7 +44,7 @@ struct WorkoutListItem: View { WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Push-ups"))) // WorkoutListItem(Workout(name: "RR"), WorkoutItem(rest: 15)) WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Push-ups"))) - WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Sprint", .distance))) - WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Run", .time))) + WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Sprint"))) + WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Run"))) } } diff --git a/WorkoutsPlus/Features/WorkoutLog/WorkoutLogItem.swift b/WorkoutsPlus/Features/WorkoutLog/WorkoutLogItem.swift new file mode 100644 index 0000000..40b69d3 --- /dev/null +++ b/WorkoutsPlus/Features/WorkoutLog/WorkoutLogItem.swift @@ -0,0 +1,19 @@ +// +// WorkoutLogItem.swift +// WorkoutsPlus +// +// Created by Felix Förtsch on 05.11.24. +// + +import Foundation +import SwiftData + +@Model +class WorkoutLogItem { + var date = Date.now + var workoutSession: WorkoutSession + + init(log session: WorkoutSession) { + workoutSession = session + } +} diff --git a/WorkoutsPlus/Features/Home/WorkoutLog.swift b/WorkoutsPlus/Features/WorkoutLog/WorkoutLogs.swift similarity index 97% rename from WorkoutsPlus/Features/Home/WorkoutLog.swift rename to WorkoutsPlus/Features/WorkoutLog/WorkoutLogs.swift index 921c804..d7513d6 100644 --- a/WorkoutsPlus/Features/Home/WorkoutLog.swift +++ b/WorkoutsPlus/Features/WorkoutLog/WorkoutLogs.swift @@ -8,7 +8,7 @@ import SwiftUI import SwiftData -struct WorkoutLog: View { +struct WorkoutLogs: View { @Environment(\.modelContext) private var modelContext @Query(sort: \WorkoutSession.name) private var workoutSessions: [WorkoutSession] @@ -97,7 +97,7 @@ struct WorkoutLog: View { #Preview("Active WorkoutSession") { NavigationStack { - WorkoutLog() + WorkoutLogs() .onAppear { Defaults.shared.isWorkingOut = true } @@ -105,5 +105,5 @@ struct WorkoutLog: View { } #Preview("No Active WorkoutSession") { - WorkoutLog() + WorkoutLogs() } diff --git a/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSession.swift b/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSession.swift index 133203c..4c6ef1c 100644 --- a/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSession.swift +++ b/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSession.swift @@ -4,6 +4,7 @@ // // Created by Felix Förtsch on 12.09.24. // + import SwiftUI import SwiftData @@ -15,22 +16,21 @@ struct ActiveWorkoutSession: View { var body: some View { VStack { - VStack { - Text(activeWorkoutSession.name) - SimpleStopWatch( - startDate: activeWorkoutSession.startDate, - duration: $activeWorkoutSession.workoutDuration) - .font(.system(.largeTitle, design: .monospaced)) - .fontWeight(.bold) - } List { - Section(header: Text("Exercises")) { - ForEach(activeWorkoutSession.workoutSessionItems) { workoutItem in - ActiveWorkoutSessionListItem(workoutItem: workoutItem) + Section { + ForEach(activeWorkoutSession.workoutSessionItems.reversed()) { workoutSessionItem in + ActiveWorkoutSessionListItem(workoutSessionItem: workoutSessionItem) } } + }.listStyle(.plain) + + VStack { + Text(activeWorkoutSession.name) + ActiveWorkoutSessionControls(session: $activeWorkoutSession) } + .frame(height: 200) } + .background(.bar) // .navigationTitle(activeWorkoutSession.name) // .navigationBarTitleDisplayMode(.inline) .toolbar { diff --git a/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionControls.swift b/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionControls.swift index e958640..7c76e80 100644 --- a/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionControls.swift +++ b/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionControls.swift @@ -13,8 +13,13 @@ struct ActiveWorkoutSessionControls: View { var body: some View { VStack { + SimpleStopWatch( + startDate: session.startDate, + duration: $session.workoutDuration) + .font(.system(.largeTitle, design: .monospaced)) + .fontWeight(.bold) HStack { - Text(session.getCurrentTodo()) + Text(session.getCurrentExerciseName()) .font(.system(size: 24, weight: .bold, design: .rounded)) } ProgressView("", @@ -32,7 +37,7 @@ struct ActiveWorkoutSessionControls: View { } .buttonStyle(.borderedProminent) .fontWeight(.bold) - .tint(.primary) + .tint(.accentColor) Button(action: { // TODO: Implement proper Pausing session.isPaused = true @@ -56,7 +61,7 @@ struct ActiveWorkoutSessionControls: View { } .buttonStyle(.borderedProminent) .fontWeight(.bold) - .tint(.primary) + .tint(.accentColor) } } } diff --git a/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionListItem.swift b/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionListItem.swift index 55a56e4..616ca7d 100644 --- a/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionListItem.swift +++ b/WorkoutsPlus/Features/WorkoutSession/ActiveWorkoutSessionListItem.swift @@ -8,18 +8,15 @@ import SwiftUI struct ActiveWorkoutSessionListItem: View { - var workoutItem: WorkoutSessionItem + var workoutSessionItem: WorkoutSessionItem var body: some View { VStack(alignment: .leading) { HStack { - Text(String(workoutItem.plannedReps) + "x") - Text(String(workoutItem.plannedValue)) - Text(String(workoutItem.unit.symbol)) - if let metric = workoutItem.metric { - Text(metric.rawValue) - } - Text(workoutItem.name) + Text(String(workoutSessionItem.plannedReps) + "x") + Text(String(workoutSessionItem.plannedValue)) + + Text(workoutSessionItem.name) .fontWeight(.bold) Spacer() Button(action: { @@ -32,7 +29,7 @@ struct ActiveWorkoutSessionListItem: View { HStack { Text("Planned: ") - if let actualRepsDone = workoutItem.actualReps { + if let actualRepsDone = workoutSessionItem.actualReps { Text("Actual: ") Text(String(actualRepsDone)) } else { @@ -41,6 +38,11 @@ struct ActiveWorkoutSessionListItem: View { } } } + .listRowBackground( + workoutSessionItem.isCompleted() + ? Color.gray.opacity(0.2) + : nil + ) } } @@ -48,7 +50,8 @@ struct ActiveWorkoutSessionListItem: View { @Previewable @State var workoutSession = WorkoutSession(start: Workout.sampleData.first!) List { ForEach(WorkoutItem.sampleDataRecommendedRoutine) { item in - ActiveWorkoutSessionListItem(workoutItem: WorkoutSessionItem(workoutSession: workoutSession, planned: item)) + ActiveWorkoutSessionListItem(workoutSessionItem: WorkoutSessionItem(workoutSession: workoutSession, planned: item)) } + .listStyle(.plain) } } diff --git a/WorkoutsPlus/Features/WorkoutSession/WorkoutSession.swift b/WorkoutsPlus/Features/WorkoutSession/WorkoutSession.swift index 2f28dae..a6b23a9 100644 --- a/WorkoutsPlus/Features/WorkoutSession/WorkoutSession.swift +++ b/WorkoutsPlus/Features/WorkoutSession/WorkoutSession.swift @@ -23,11 +23,7 @@ final class WorkoutSession: Nameable { } } - // State var isPaused = false - // var isCancelled: Bool - // var isDeleted: Bool - // var isSynced: Bool // My workout session started at: var startDate: Date = Date.now @@ -36,14 +32,12 @@ final class WorkoutSession: Nameable { // My workout session took me x seconds. var workoutDuration: TimeInterval = 0.0 var pauseDuration: TimeInterval = 0.0 - // My workout session is completed and moved to the workout log. - var isCompleted = false // Exercise Progress var currentExercise = 0 - func isActive() -> Bool { - return stopDate == nil + func isCompleted() -> Bool { + stopDate != nil } // MARK: -- Workout Controls @@ -56,20 +50,25 @@ final class WorkoutSession: Nameable { // } // Call stop() to terminate the workout. - func stop() { - isCompleted = true + func stop() -> WorkoutLogItem { stopDate = Date.now // duration = stopDate!.timeIntervalSince(startDate) + + return WorkoutLogItem(log: self) } func prevExercise() { + workoutSessionItems[currentExercise].startDate = Date.now if currentExercise > 0 { currentExercise -= 1 } } func nextExercise() { - + workoutSessionItems[currentExercise].stopDate = Date.now + if currentExercise < workoutSessionItems.count - 1 { + currentExercise += 1 + } } // MARK: -- Workout Information @@ -82,22 +81,14 @@ final class WorkoutSession: Nameable { } func getTotalExerciseCount() -> Double { - return 100.0 + return Double(workoutSessionItems.count) } func getCurrentExerciseIndex() -> Double { return Double(currentExercise) } - func getCurrentTodo() -> String { - return getCurrentExerciseMetric() + " " + getCurrentExerciseName() - } - func getCurrentExerciseName() -> String { - return "Hello" - } - - func getCurrentExerciseMetric() -> String { - return "Hello" + return workoutSessionItems[currentExercise].name } } diff --git a/WorkoutsPlus/Features/WorkoutSession/WorkoutSessionItem.swift b/WorkoutsPlus/Features/WorkoutSession/WorkoutSessionItem.swift index bc98bd8..7390928 100644 --- a/WorkoutsPlus/Features/WorkoutSession/WorkoutSessionItem.swift +++ b/WorkoutsPlus/Features/WorkoutSession/WorkoutSessionItem.swift @@ -18,14 +18,15 @@ final class WorkoutSessionItem: Nameable, Positionable { var plannedReps: Int // 8 times | 1 time var plannedValue: Double // With 10 | 42,187 - var unit: ExerciseUnit - var metric: ExerciseMetric? // kg (weight) | km (distance) + var unit: ExerciseUnit? + var metric: ExerciseType? // kg (weight) | km (distance) var actualReps: Int? var actualValue: Double? var startDate: Date? var stopDate: Date? + func isCompleted() -> Bool { stopDate != nil } init(workoutSession: WorkoutSession, planned: WorkoutItem) { self.workoutSession = workoutSession @@ -33,8 +34,6 @@ final class WorkoutSessionItem: Nameable, Positionable { self.position = planned.position self.plannedReps = planned.plannedReps self.plannedValue = planned.plannedValue - self.unit = planned.unit - self.metric = planned.metric } func start() { startDate = .now } diff --git a/WorkoutsPlus/WorkoutsPlusApp.swift b/WorkoutsPlus/WorkoutsPlusApp.swift index f22ba97..b12524a 100644 --- a/WorkoutsPlus/WorkoutsPlusApp.swift +++ b/WorkoutsPlus/WorkoutsPlusApp.swift @@ -33,6 +33,7 @@ extension WorkoutsPlusApp { static let swiftDataSchema = Schema([ Exercise.self, ExerciseUnit.self, + ExerciseType.self, Equipment.self, Workout.self, WorkoutItem.self, diff --git a/WorkoutsPlus/er-diagram.md b/WorkoutsPlus/er-diagram.md index e40a2d6..54cc142 100644 --- a/WorkoutsPlus/er-diagram.md +++ b/WorkoutsPlus/er-diagram.md @@ -5,6 +5,7 @@ erDiagram Workout 1 .. 0+ WorkoutItem : collects Workout 1 .. 0+ WorkoutSession : "starts" WorkoutItem 1 -- 1 WorkoutSessionItem : "provides data for" + WorkoutItem 1 -- 0+ WorkoutItem : "collects" WorkoutSession 1 -- 1+ WorkoutSessionItem : collects ContentView 1 -- 1 WorkoutSession : "holds onto" @@ -14,18 +15,20 @@ erDiagram } Workout { string name + WorkoutItem[] workoutItems } WorkoutSession { Workout workout time workoutSessionDuration } WorkoutItem { - Exercise exerciseData + Exercise exercise + WorkoutItem[] workoutItems int plannedReps double plannedValue } WorkoutSessionItem { - WorkoutItem exerciseData + WorkoutItem exercise int actualReps double actualValue }