diff --git a/WorkoutsPlus/Models/Exercise.swift b/WorkoutsPlus/Models/Exercise.swift index e1b252a..bfb7ece 100644 --- a/WorkoutsPlus/Models/Exercise.swift +++ b/WorkoutsPlus/Models/Exercise.swift @@ -14,8 +14,9 @@ final class Exercise: Nameable { var id = UUID() @Attribute(.unique) var name: String - // var metric: String = "reps" + // var metric: String = "reps" // var exerciseDescription: ExerciseDescription? + // var focus: ExerciseFocus? // Strength, Flexibility, Speed, etc var timestamp: Date = Date.now diff --git a/WorkoutsPlus/Models/Workout.swift b/WorkoutsPlus/Models/Workout.swift index d7176d7..d198126 100644 --- a/WorkoutsPlus/Models/Workout.swift +++ b/WorkoutsPlus/Models/Workout.swift @@ -5,7 +5,7 @@ // Created by Felix Förtsch on 10.08.24. // -import Foundation +import SwiftUI import SwiftData @Model @@ -15,8 +15,12 @@ final class Workout: Nameable { var id = UUID() @Attribute(.unique) var name: String + // Icon + var workoutIconSystemName = "figure.run.square.stack" + var workoutIconColorName = ColorName.black + // Other properties and methods - var timestamp: Date = Date.now + var timestamp = Date.now @Relationship(deleteRule: .cascade) var workoutItems: [WorkoutItem] = [] @@ -46,7 +50,64 @@ final class Workout: Nameable { exercise.position = index } } - +} + +extension Workout { + // This enum maps the system colors to enable storing them with the SwiftData model data as String. + // See Workout.workoutIconColorName for a usage example. + // TODO: Use a Macro to reduce this horrible contraption to something maintainable. + enum ColorName: String, Codable { + case black + case blue + case cyan + case gray + case green + case indigo + case mint + case orange + case pink + case purple + case red + case white + case yellow + + var color: Color { + switch self { + case .black: return .black + case .blue: return .blue + case .cyan: return .cyan + case .gray: return .gray + case .green: return .green + case .indigo: return .indigo + case .mint: return .mint + case .orange: return .orange + case .pink: return .pink + case .purple: return .purple + case .red: return .red + case .white: return .white + case .yellow: return .yellow + } + } + + static func fromColor(_ color: Color) -> ColorName? { + switch color { + case .black: return .black + case .blue: return .blue + case .cyan: return .cyan + case .gray: return .gray + case .green: return .green + case .indigo: return .indigo + case .mint: return .mint + case .orange: return .orange + case .pink: return .pink + case .purple: return .purple + case .red: return .red + case .white: return .white + case .yellow: return .yellow + default: return nil + } + } + } } extension Workout { diff --git a/WorkoutsPlus/Models/WorkoutItem.swift b/WorkoutsPlus/Models/WorkoutItem.swift index 775e8c5..9a0aad3 100644 --- a/WorkoutsPlus/Models/WorkoutItem.swift +++ b/WorkoutsPlus/Models/WorkoutItem.swift @@ -22,6 +22,8 @@ final class WorkoutItem: Nameable, Positionable { // EXERCISE var exercise: Exercise? // TODO: Think about what's happening when an exercise (template) is deleted or changed + // If it is delete -> we just keep the WorkoutItem with the name :) + // The only relevant delete is delete Workout -> Delete Workoutitems // { didSet { self.name = exercise?.name ?? "self.name" } } init(_ reps: Int, _ exercise: String) { diff --git a/WorkoutsPlus/Workout/WorkoutDetail.swift b/WorkoutsPlus/Workout/WorkoutDetail.swift index e4ba050..f6168ca 100644 --- a/WorkoutsPlus/Workout/WorkoutDetail.swift +++ b/WorkoutsPlus/Workout/WorkoutDetail.swift @@ -18,8 +18,12 @@ struct WorkoutDetail: View { var body: some View { Form { - Section(header: Text("Workout Name")) { - TextField("Workout Name", text: $workout.name) + Section { + NavigationLink(destination: WorkoutIconSelector(workout: workout)) { + Image(systemName: workout.workoutIconSystemName) + .foregroundStyle(workout.workoutIconColorName.color) + TextField("Workout Name", text: $workout.name) + } } Section(header: Text("Exercises")) { List { diff --git a/WorkoutsPlus/Workout/WorkoutIconSelector.swift b/WorkoutsPlus/Workout/WorkoutIconSelector.swift index afc5c04..4726fdb 100644 --- a/WorkoutsPlus/Workout/WorkoutIconSelector.swift +++ b/WorkoutsPlus/Workout/WorkoutIconSelector.swift @@ -9,9 +9,8 @@ import SwiftUI struct WorkoutIconSelector: View { - @State private var selectedColor: Color = .black - @State private var selectedIcon: String? - + @State var workout: Workout + @State private var searchText: String = "" var filteredIcons: [String] { if searchText.isEmpty { @@ -22,18 +21,24 @@ struct WorkoutIconSelector: View { } var body: some View { + ScrollView { + Text(workout.name) + Text(workout.workoutIconSystemName) + Text(workout.workoutIconColorName.rawValue) + LazyVGrid(columns: [GridItem(.adaptive(minimum: 50))]) { ForEach(systemColors, id: \.self) { color in Button(action: { - selectedColor = color + workout.workoutIconColorName = Workout.ColorName.fromColor(color)! }) { Circle() .fill(color) .frame(width: 40, height: 40) .overlay( Circle() - .stroke(Color.white, lineWidth: selectedColor == color ? 4 : 0) + // TODO: change this from stroke to checkmark symbol in the circle + .stroke(Color.black, lineWidth: workout.workoutIconColorName.color == color ? 4 : 0) ) } } @@ -42,10 +47,10 @@ struct WorkoutIconSelector: View { LazyVGrid(columns: [GridItem(.adaptive(minimum: 50, maximum: 100))]) { ForEach(filteredIcons, id: \.self) { iconName in Button(action: { - selectedIcon = iconName + workout.workoutIconSystemName = iconName }) { Image(systemName: iconName) - .foregroundStyle(selectedColor) + .foregroundStyle(workout.workoutIconColorName.color) .padding() .background() .cornerRadius(8) @@ -60,13 +65,13 @@ struct WorkoutIconSelector: View { ContentUnavailableView.search } } - .navigationTitle("Select a Workout Icon") } + } #Preview { NavigationView() { - WorkoutIconSelector() + WorkoutIconSelector(workout: Workout.sampleData) } }