fix repetitive save of WorkoutItem, add: Onboarding, Defaults, Settings, Trainer/Trainee skeletons, reorder files, remove all Bindable

This commit is contained in:
Felix Förtsch
2024-09-04 18:44:28 +02:00
parent 0905ea7d3f
commit d82d0cd9fa
25 changed files with 426 additions and 134 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
//
// AddWorkoutView.swift
// AddWorkout.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 17.08.24.
@@ -11,7 +11,7 @@ struct AddWorkout: View {
@Environment(\.modelContext) private var modelContext
@Environment(\.dismiss) private var dismiss
@Bindable var workout: Workout
@State var workout: Workout
var body: some View {
Form {
@@ -12,54 +12,38 @@ struct AddWorkoutItemToWorkout: View {
@Environment(\.modelContext) private var modelContext
@Query(sort: \Exercise.name) private var exercises: [Exercise]
@Bindable var workout: Workout
@State var workout: Workout
// TODO: Add (i) Button that allows editing an exercise (maybe requires NavigationStack?)
var body: some View {
Group {
List {
Section(header: Text("Utilities")) {
AddExerciseToWorkoutListItem(WorkoutItem(workoutItems: []), workout)
// AddExerciseToWorkoutListItem(WorkoutItem(workoutItems: []), workout)
}
Section(header: Text("Excersises")) {
if !exercises.isEmpty {
ForEach(exercises) { exercise in
AddExerciseToWorkoutListItem(WorkoutItem(from: exercise), workout)
}} else {
ContentUnavailableView {
// TODO: Add Button that allows adding an exercise
Label("No Exercises", systemImage: Exercise.systemImage)
AddItemButton(label: exercise.name) {
let workoutItem = WorkoutItem(from: exercise)
addWorkoutItemtoWorkout(workoutItem)
}
}
} else {
ContentUnavailableView {
// TODO: Add Button that allows adding an exercise
Label("No Exercises", systemImage: Exercise.systemImage)
}
}
}
}
}
}
}
struct AddExerciseToWorkoutListItem: View {
@Environment(\.modelContext) private var modelContext
var workoutItem: WorkoutItem
var workout: Workout
init(_ workoutItem: WorkoutItem, _ workout: Workout) {
self.workoutItem = workoutItem
self.workout = workout
}
var body: some View {
Button(action: {
workout.add(workoutItem: workoutItem)
}) {
HStack {
Text(workoutItem.name)
.foregroundStyle(.black)
Spacer()
Image(systemName: "plus.circle.fill")
.foregroundStyle(.green)
}
}
private func addWorkoutItemtoWorkout(_ workoutItem: WorkoutItem) {
workout.add(workoutItem: workoutItem)
// TODO: Handle saving in a way the user knows when it's saved
// modelContext.save()
}
}
-67
View File
@@ -1,67 +0,0 @@
//
// Workout.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 10.08.24.
//
import Foundation
import SwiftData
@Model
final class Workout: Identifiable {
var id = UUID()
var name: String
static var systemImage = "figure.run.square.stack"
// Other properties and methods
var timestamp: Date = Date.now
@Relationship(deleteRule: .cascade) var workoutItems: [WorkoutItem] = []
init(name: String) {
self.name = name
}
func add(workoutItem: WorkoutItem) {
self.workoutItems.append(workoutItem)
updateExercisePositions()
}
func add(workoutItems: [WorkoutItem]) {
for workoutItem in workoutItems {
self.workoutItems.append(workoutItem)
}
updateExercisePositions()
}
func moveWorkoutItem(from source: IndexSet, to destination: Int) {
workoutItems.move(fromOffsets: source, toOffset: destination)
updateExercisePositions()
}
private func updateExercisePositions() {
for (index, exercise) in workoutItems.enumerated() {
exercise.position = index
}
}
}
extension Workout {
private convenience init(name: String, exercises: [WorkoutItem]) {
self.init(name: name)
self.workoutItems = exercises
}
static let sampleData: Workout = {
var workout = Workout(name: "Recommended Routine")
for workoutItem in WorkoutItem.sampleData {
workout.add(workoutItem: workoutItem)
}
return workout
}()
}
+26 -10
View File
@@ -1,5 +1,5 @@
//
// WorkoutDetailsView.swift
// WorkoutDetail.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 10.08.24.
@@ -12,8 +12,8 @@ struct WorkoutDetail: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) private var modelContext
@Bindable var workout: Workout
@State private var isPresenting = false
@State var workout: Workout
@State private var isPresentingExerciseLibrary = false
var body: some View {
@@ -47,18 +47,17 @@ struct WorkoutDetail: View {
EditButton()
}
}
.sheet(isPresented: $isPresenting) {
NavigationStack {
AddWorkoutItemToWorkout(workout: workout)
}
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
.sheet(isPresented: $isPresentingExerciseLibrary) {
AddWorkoutItemToWorkout(workout: workout)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
}
}
private func addWorkoutItemToWorkout() {
withAnimation {
isPresenting = true
isPresentingExerciseLibrary = true
}
}
@@ -92,3 +91,20 @@ struct WorkoutDetail: View {
.modelContainer(SampleData.shared.modelContainer)
}
}
#Preview("Debug") {
TabView {
WorkoutDetail(workout: Workout.sampleData)
.tabItem {
Image(systemName: "figure.run.square.stack")
Text("Workouts")
}
DebugList()
.tabItem {
Image(systemName: "hammer")
Text("Debug")
}
}
.modelContainer(SampleData.shared.modelContainer)
}
-79
View File
@@ -1,79 +0,0 @@
//
// 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 workout: Workout?
var workoutItemType: WorkoutItemType
var position: Int = 0
var reps: Int = 8
// EXERCISE
var exercise: Exercise? {
didSet {
self.name = exercise?.name ?? "self.name"
}
}
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
}
// SET
var workoutItems: [WorkoutItem] = []
init(workoutItems: [WorkoutItem] = []) {
self.name = "Set"
self.workoutItemType = .set
self.reps = 3
workoutItems.forEach(addChild)
}
func addChild(_ child: WorkoutItem) {
if self.workoutItemType == .set {
self.workoutItems.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
}()
}
+1 -1
View File
@@ -1,5 +1,5 @@
//
// WorkoutLibraryView.swift
// WorkoutLibrary.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 10.08.24.