Files
workouts/Workouts/Models/Split.swift
2025-07-25 17:42:25 -04:00

147 lines
5.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
text: item.setup.isEmpty ? nil : item.setup,
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
)
}
}
}
}