fix repetitive save of WorkoutItem, add: Onboarding, Defaults, Settings, Trainer/Trainee skeletons, reorder files, remove all Bindable
This commit is contained in:
@@ -12,9 +12,7 @@ struct AddItemButton: View {
|
||||
var action: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
action()
|
||||
}) {
|
||||
Button(action: action) {
|
||||
HStack {
|
||||
Image(systemName: "plus.circle.fill")
|
||||
.foregroundStyle(.green)
|
||||
|
||||
@@ -20,23 +20,7 @@ struct ExerciseListItem: View {
|
||||
Button(action: {
|
||||
// workout.addExercise(from: exercise)
|
||||
}) {
|
||||
HStack {
|
||||
Text(String(exercise.reps))
|
||||
.font(.system(size: 14, weight: .bold))
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 20, height: 10)
|
||||
.padding(8)
|
||||
.background(Color.blue)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
Text(exercise.name)
|
||||
.foregroundStyle(.black)
|
||||
Spacer()
|
||||
Stepper(
|
||||
value: $exercise.reps,
|
||||
in: 0...100,
|
||||
step: 1
|
||||
) {}
|
||||
}
|
||||
StepperListItem(itemName: exercise.name, itemValue: $exercise.reps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
WorkoutsPlus/Components/StepperListItem.swift
Normal file
43
WorkoutsPlus/Components/StepperListItem.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// StepperListItem.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 04.09.24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct StepperListItem: View {
|
||||
@State var itemName: String
|
||||
@Binding var itemValue: Int
|
||||
|
||||
var body: some View {
|
||||
Stepper(
|
||||
value: $itemValue,
|
||||
in: 0...100,
|
||||
step: 1
|
||||
) {
|
||||
HStack {
|
||||
Text(String(itemValue))
|
||||
.font(.system(size: 14, weight: .bold))
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 20, height: 10)
|
||||
.padding(8)
|
||||
.background(Color.blue)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||
Text(itemName)
|
||||
.foregroundStyle(.black)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
@Previewable @State var value = 8
|
||||
|
||||
List {
|
||||
StepperListItem(itemName: "Short Name", itemValue: $value)
|
||||
StepperListItem(itemName: "Very very very very long name with whitespace", itemValue: $value)
|
||||
StepperListItem(itemName: "Veryveryverylonglonglonglongnamewithoutwithwhitespace", itemValue: $value)
|
||||
}
|
||||
}
|
||||
45
WorkoutsPlus/Configuration/Defaults.swift
Normal file
45
WorkoutsPlus/Configuration/Defaults.swift
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Defaults.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 04.09.24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
public class Defaults: ObservableObject {
|
||||
@AppStorage("isFirstAppStart") public var isFirstAppStart = true
|
||||
@AppStorage("isOnboarding") public var isOnboarding = true
|
||||
@AppStorage("userId") public var userId = UUID().uuidString
|
||||
|
||||
@AppStorage("sets") public var sets = 8
|
||||
@AppStorage("reps") public var reps = 8
|
||||
|
||||
public static let shared = Defaults()
|
||||
}
|
||||
|
||||
@propertyWrapper
|
||||
public struct Default<T>: DynamicProperty {
|
||||
@ObservedObject private var defaults: Defaults
|
||||
private let keyPath: ReferenceWritableKeyPath<Defaults, T>
|
||||
|
||||
public init(_ keyPath: ReferenceWritableKeyPath<Defaults, T>, defaults: Defaults = .shared) {
|
||||
self.keyPath = keyPath
|
||||
self.defaults = defaults
|
||||
}
|
||||
|
||||
public var wrappedValue: T {
|
||||
get { defaults[keyPath: keyPath] }
|
||||
nonmutating set { defaults[keyPath: keyPath] = newValue }
|
||||
}
|
||||
|
||||
public var projectedValue: Binding<T> {
|
||||
Binding(
|
||||
get: { defaults[keyPath: keyPath] },
|
||||
set: { value in
|
||||
defaults[keyPath: keyPath] = value
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,11 @@ import SwiftData
|
||||
|
||||
struct ContentView: View {
|
||||
@Environment(\.modelContext) private var modelContext
|
||||
@Default(\.isOnboarding) var isOnboarding
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
WorkoutLog()
|
||||
// WorkoutLog()
|
||||
WorkoutLibrary()
|
||||
.tabItem {
|
||||
Image(systemName: "figure.run.square.stack")
|
||||
@@ -24,7 +25,7 @@ struct ContentView: View {
|
||||
Image(systemName: "figure.run")
|
||||
Text("Exercises")
|
||||
}
|
||||
DebugExerciseList()
|
||||
DebugList()
|
||||
.tabItem {
|
||||
Image(systemName: "hammer")
|
||||
Text("Debug")
|
||||
@@ -35,6 +36,7 @@ struct ContentView: View {
|
||||
Text("Settings")
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $isOnboarding) { Onboarding() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
64
WorkoutsPlus/Debug/DebugList.swift
Normal file
64
WorkoutsPlus/Debug/DebugList.swift
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// DebugList.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 30.08.24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct DebugList: View {
|
||||
@Query(sort: \Exercise.name) private var exercises: [Exercise]
|
||||
@Query(sort: \Workout.name) private var workouts: [Workout]
|
||||
@Query(sort: \WorkoutItem.name) private var workoutItems: [WorkoutItem]
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: Text("Exercises")) {
|
||||
ForEach(exercises) { exercise in
|
||||
DebugListItem(item: exercise)
|
||||
}
|
||||
}
|
||||
Section(header: Text("Workouts")) {
|
||||
ForEach(workouts) { workout in
|
||||
DebugListItem(item: workout)
|
||||
}
|
||||
}
|
||||
Section(header: Text("WorkoutItems")) {
|
||||
ForEach(workoutItems) { workoutItem in
|
||||
VStack(alignment: .leading) {
|
||||
Text("\(workoutItem.name), pos: \(workoutItem.position), reps: \(workoutItem.reps)")
|
||||
Text(workoutItem.id.uuidString)
|
||||
.font(.system(size: 12, weight: .bold))
|
||||
.fontDesign(.monospaced)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "wrench")
|
||||
Text("Exercise Debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugListItem: View {
|
||||
var item: any Nameable
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text(item.name)
|
||||
Text(item.id.uuidString)
|
||||
.font(.system(size: 12, weight: .bold))
|
||||
.fontDesign(.monospaced)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
DebugList()
|
||||
.modelContainer(SampleData.shared.modelContainer)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//
|
||||
// DebugExerciseList.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 30.08.24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct DebugExerciseList: View {
|
||||
@Query(sort: \WorkoutItem.name) private var exercises: [WorkoutItem]
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
ForEach(exercises) { exercise in
|
||||
Text("\(exercise.name), pos: \(exercise.position)")
|
||||
}
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "figure.run.square.stack")
|
||||
Text("Exercise Debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
DebugExerciseList()
|
||||
}
|
||||
@@ -11,7 +11,7 @@ struct AddExercise: View {
|
||||
@Environment(\.modelContext) private var modelContext
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@Bindable var exercise: Exercise
|
||||
@State var exercise: Exercise
|
||||
|
||||
var body : some View {
|
||||
Form {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// ExerciseDetailsView.swift
|
||||
// ExerciseDetail.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 10.08.24.
|
||||
@@ -11,7 +11,7 @@ struct ExerciseDetail: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@Environment(\.modelContext) private var modelContext
|
||||
|
||||
@Bindable var exercise: Exercise
|
||||
@State var exercise: Exercise
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ import Foundation
|
||||
import SwiftData
|
||||
|
||||
@Model
|
||||
final class Exercise: Identifiable {
|
||||
var id = UUID()
|
||||
final class Exercise: Nameable {
|
||||
static var systemImage = "figure.run"
|
||||
|
||||
var id = UUID()
|
||||
@Attribute(.unique) var name: String
|
||||
// var metric: String = "reps"
|
||||
// var exerciseDescription: ExerciseDescription?
|
||||
34
WorkoutsPlus/Models/Person.swift
Normal file
34
WorkoutsPlus/Models/Person.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Person.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 03.09.24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftData
|
||||
|
||||
@Model
|
||||
class Trainer: Nameable {
|
||||
var id = UUID()
|
||||
var name: String = ""
|
||||
|
||||
var trainees: [Trainee] = []
|
||||
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
@Model
|
||||
class Trainee: Nameable {
|
||||
var id = UUID()
|
||||
var name: String = ""
|
||||
|
||||
var trainer: Trainer?
|
||||
|
||||
init(name: String, trainer: Trainer? = nil) {
|
||||
self.name = name
|
||||
self.trainer = trainer
|
||||
}
|
||||
}
|
||||
18
WorkoutsPlus/Models/Protocols.swift
Normal file
18
WorkoutsPlus/Models/Protocols.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Protocols.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 04.09.24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol Nameable: Identifiable {
|
||||
var id: UUID { get }
|
||||
var name: String { get }
|
||||
}
|
||||
|
||||
protocol Positionable: Identifiable {
|
||||
var id: UUID { get }
|
||||
var position: Int { get }
|
||||
}
|
||||
@@ -9,11 +9,12 @@ import Foundation
|
||||
import SwiftData
|
||||
|
||||
@Model
|
||||
final class Workout: Identifiable {
|
||||
var id = UUID()
|
||||
var name: String
|
||||
final class Workout: Nameable {
|
||||
static var systemImage = "figure.run.square.stack"
|
||||
|
||||
var id = UUID()
|
||||
@Attribute(.unique) var name: String
|
||||
|
||||
// Other properties and methods
|
||||
var timestamp: Date = Date.now
|
||||
|
||||
@@ -25,22 +26,22 @@ final class Workout: Identifiable {
|
||||
|
||||
func add(workoutItem: WorkoutItem) {
|
||||
self.workoutItems.append(workoutItem)
|
||||
updateExercisePositions()
|
||||
updateWorkoutItemsPositions()
|
||||
}
|
||||
|
||||
func add(workoutItems: [WorkoutItem]) {
|
||||
for workoutItem in workoutItems {
|
||||
self.workoutItems.append(workoutItem)
|
||||
}
|
||||
updateExercisePositions()
|
||||
updateWorkoutItemsPositions()
|
||||
}
|
||||
|
||||
func moveWorkoutItem(from source: IndexSet, to destination: Int) {
|
||||
workoutItems.move(fromOffsets: source, toOffset: destination)
|
||||
updateExercisePositions()
|
||||
updateWorkoutItemsPositions()
|
||||
}
|
||||
|
||||
private func updateExercisePositions() {
|
||||
private func updateWorkoutItemsPositions() {
|
||||
for (index, exercise) in workoutItems.enumerated() {
|
||||
exercise.position = index
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Exercise.swift
|
||||
// WorkoutItem.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 10.08.24.
|
||||
@@ -9,10 +9,10 @@ import Foundation
|
||||
import SwiftData
|
||||
|
||||
@Model
|
||||
final class WorkoutItem: Identifiable {
|
||||
final class WorkoutItem: Nameable, Positionable {
|
||||
var id = UUID()
|
||||
var name: String
|
||||
|
||||
|
||||
var workout: Workout?
|
||||
var workoutItemType: WorkoutItemType
|
||||
var position: Int = 0
|
||||
@@ -20,11 +20,9 @@ final class WorkoutItem: Identifiable {
|
||||
var reps: Int = 8
|
||||
|
||||
// EXERCISE
|
||||
var exercise: Exercise? {
|
||||
didSet {
|
||||
self.name = exercise?.name ?? "self.name"
|
||||
}
|
||||
}
|
||||
var exercise: Exercise?
|
||||
// TODO: Think about what's happening when an exercise (template) is deleted or changed
|
||||
// { didSet { self.name = exercise?.name ?? "self.name" } }
|
||||
|
||||
init(_ reps: Int, _ exercise: String) {
|
||||
self.workoutItemType = .exercise
|
||||
82
WorkoutsPlus/Onboarding/Onboarding.swift
Normal file
82
WorkoutsPlus/Onboarding/Onboarding.swift
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Onboarding.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 04.09.24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Onboarding: View {
|
||||
@Default(\.isFirstAppStart) var isFirstAppStart
|
||||
@Default(\.isOnboarding) var isOnboarding
|
||||
@Default(\.userId) var userId
|
||||
|
||||
@State private var currentPage = 0
|
||||
let totalPages = 3
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack {
|
||||
TabView(selection: $currentPage) {
|
||||
ForEach(0..<totalPages, id: \.self) { index in
|
||||
VStack {
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "scribble.variable")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 150, height: 150)
|
||||
.foregroundColor(.blue)
|
||||
|
||||
Text("userID: \(userId)")
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.bold)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.top, 40)
|
||||
|
||||
Text("Erfahren Sie, wie MyApp Ihnen helfen kann, produktiver zu sein.")
|
||||
.font(.title3)
|
||||
.foregroundColor(.gray)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, 40)
|
||||
.padding(.top, 20)
|
||||
|
||||
Spacer()
|
||||
|
||||
HStack {
|
||||
if currentPage > 0 {
|
||||
Button("Zurück") {
|
||||
currentPage -= 1
|
||||
}
|
||||
.padding(.horizontal, 40)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(currentPage == totalPages - 1 ? "Los geht's!" : "Weiter") {
|
||||
if currentPage < totalPages - 1 {
|
||||
currentPage += 1
|
||||
} else {
|
||||
if (isFirstAppStart) {
|
||||
userId = UUID().uuidString
|
||||
}
|
||||
isFirstAppStart = false
|
||||
isOnboarding = false
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 40)
|
||||
}
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
.tag(index)
|
||||
}
|
||||
}
|
||||
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
Onboarding()
|
||||
}
|
||||
25
WorkoutsPlus/README.md
Normal file
25
WorkoutsPlus/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Workouts+
|
||||
|
||||
- JSON Import/Export
|
||||
- Use Multipeer connect for sharing/tracking?
|
||||
- Progression-Fotos: als eigene App? -> Generalisierung zu "Foto-Track"
|
||||
- Karte mit öffentlichen Orten einbinden (AOK-Fitnesspark?)
|
||||
|
||||
## Workouts
|
||||
- time-based: 60 s
|
||||
- rep-based: 3x
|
||||
- Loops
|
||||
|
||||
## Trainingspläne
|
||||
|
||||
Idee: Platformdenken
|
||||
|
||||
App ist für Sportler mit einem Trainer. Trainer können die App nutzen, um ihre Trainees mit Trainingsplänen zu versorgen.
|
||||
Dazu muss der Trainer eine Möglichkeit bekommen bezahlt zu werden?
|
||||
|
||||
## Ernährungspläne
|
||||
|
||||
Visualisierung des Budgets (Balkendiagram, das man via DragNdrop auffüllen kann, um zu sehen, wie man hinkommt)
|
||||
mglw mehrdimensional? eine Achse kcal eine Achse Protein?
|
||||
|
||||
Energiebudget -> im ersten Schritt einfach immer denselben Ernährungsplan
|
||||
@@ -1,18 +0,0 @@
|
||||
//
|
||||
// Settings.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 30.08.24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Settings: View {
|
||||
var body: some View {
|
||||
Text("Settings")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
Settings()
|
||||
}
|
||||
44
WorkoutsPlus/Settings/Settings.swift
Normal file
44
WorkoutsPlus/Settings/Settings.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Settings.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 30.08.24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Settings: View {
|
||||
@Default(\.isFirstAppStart) var isFirstAppStart
|
||||
@Default(\.isOnboarding) var isOnboarding
|
||||
@Default(\.userId) var userId
|
||||
@Default(\.reps) var reps
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: Text("User")) {
|
||||
Text(userId)
|
||||
TextField("name", text: $userId)
|
||||
}
|
||||
Section(header: Text("Defaults")) {
|
||||
StepperListItem(itemName: "Rep Count", itemValue: $reps)
|
||||
}
|
||||
Text(String(reps))
|
||||
Section(header: Text("Danger Zone")) {
|
||||
|
||||
Toggle(isOn: $isOnboarding) {
|
||||
Text("isOnboarding")
|
||||
}
|
||||
Button("Reset App", role: .destructive, action: resetApp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func resetApp() {
|
||||
isFirstAppStart = true
|
||||
isOnboarding = true
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
Settings()
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// WorkoutLibraryView.swift
|
||||
// WorkoutLibrary.swift
|
||||
// WorkoutsPlus
|
||||
//
|
||||
// Created by Felix Förtsch on 10.08.24.
|
||||
|
||||
Reference in New Issue
Block a user