146 lines
5.1 KiB
Swift
146 lines
5.1 KiB
Swift
import Foundation
|
||
import SwiftData
|
||
import SwiftUI
|
||
|
||
@Model
|
||
final class Split {
|
||
var name: String = ""
|
||
var intro: String = ""
|
||
|
||
@Relationship(deleteRule: .cascade, inverse: \SplitExerciseAssignment.split)
|
||
var exercises: [SplitExerciseAssignment]? = []
|
||
|
||
@Relationship(deleteRule: .nullify, inverse: \Workout.split)
|
||
var workouts: [Workout]? = []
|
||
|
||
init(name: String, intro: String) {
|
||
self.name = name
|
||
self.intro = intro
|
||
}
|
||
|
||
static let unnamed = "Unnamed Split"
|
||
}
|
||
|
||
// MARK: - EditableEntity Conformance
|
||
|
||
extension Split: EditableEntity {
|
||
var count: Int? {
|
||
return self.exercises?.count
|
||
}
|
||
|
||
static func createNew() -> Split {
|
||
return Split(name: "", intro: "")
|
||
}
|
||
|
||
static var navigationTitle: String {
|
||
return "Splits"
|
||
}
|
||
|
||
@ViewBuilder
|
||
static func formView(for model: Split) -> some View {
|
||
EntityAddEditView(model: model) { $model in
|
||
SplitFormView(model: $model)
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Private Form View
|
||
|
||
fileprivate struct SplitFormView: View {
|
||
@Binding var model: Split
|
||
|
||
@State private var showingAddSheet: Bool = false
|
||
@State private var itemToEdit: SplitExerciseAssignment? = nil
|
||
@State private var itemToDelete: SplitExerciseAssignment? = nil
|
||
|
||
var body: some View {
|
||
Section(header: Text("Name")) {
|
||
TextField("Name", text: $model.name)
|
||
.bold()
|
||
}
|
||
|
||
Section(header: Text("Description")) {
|
||
TextEditor(text: $model.intro)
|
||
.frame(minHeight: 100)
|
||
}
|
||
|
||
Section(header: Text("Exercises")) {
|
||
NavigationLink {
|
||
NavigationStack {
|
||
Form {
|
||
List {
|
||
if let assignments = model.exercises, !assignments.isEmpty {
|
||
let sortedAssignments = assignments.sorted(by: { $0.order == $1.order ? $0.exercise?.name ?? Exercise.unnamed < $1.exercise?.name ?? Exercise.unnamed : $0.order < $1.order })
|
||
ForEach(sortedAssignments) { item in
|
||
ListItem(
|
||
title: item.exercise?.name ?? Exercise.unnamed,
|
||
subtitle: "\(item.sets) × \(item.reps) × \(item.weight) lbs"
|
||
)
|
||
.swipeActions {
|
||
Button(role: .destructive) {
|
||
itemToDelete = item
|
||
} label: {
|
||
Label("Delete", systemImage: "trash")
|
||
}
|
||
Button {
|
||
itemToEdit = item
|
||
} label: {
|
||
Label("Edit", systemImage: "pencil")
|
||
}
|
||
.tint(.indigo)
|
||
}
|
||
}
|
||
} else {
|
||
Text("No exercises added yet.")
|
||
}
|
||
}
|
||
}
|
||
.navigationTitle("Exercises")
|
||
}
|
||
.toolbar {
|
||
ToolbarItem(placement: .navigationBarTrailing) {
|
||
Button(action: { showingAddSheet.toggle() }) {
|
||
Image(systemName: "plus")
|
||
}
|
||
}
|
||
}
|
||
.sheet (isPresented: $showingAddSheet) {
|
||
ExercisePickerView { exercise in
|
||
itemToEdit = SplitExerciseAssignment(
|
||
order: 0,
|
||
sets: exercise.sets,
|
||
reps: exercise.reps,
|
||
weight: exercise.weight,
|
||
split: model,
|
||
exercise: exercise
|
||
)
|
||
}
|
||
}
|
||
.sheet(item: $itemToEdit) { item in
|
||
SplitExerciseAssignmentAddEditView(model: item)
|
||
}
|
||
.confirmationDialog(
|
||
"Delete Exercise?",
|
||
isPresented: .constant(itemToDelete != nil),
|
||
titleVisibility: .visible
|
||
) {
|
||
Button("Delete", role: .destructive) {
|
||
if let item = itemToDelete {
|
||
withAnimation {
|
||
model.exercises?.removeAll { $0.id == item.id }
|
||
itemToDelete = nil
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
} label: {
|
||
ListItem(
|
||
text: "Exercises",
|
||
count: model.exercises?.count ?? 0
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|