/ BalanceKit / WorkoutView.swift
WorkoutView.swift
1 // 2 // WorkoutView.swift 3 // BalanceKit 4 // 5 // Created by Alexander Kunau on 12.07.25. 6 // 7 8 import SwiftUI 9 10 struct WorkoutView: View { 11 @ObservedObject var workoutManager: WorkoutManager 12 @ObservedObject var userProfile: UserProfile 13 @EnvironmentObject var dataManager: FoodDataManager // Hinzugefügt für Zugriff auf healthManager 14 @State private var showingAddWorkout = false 15 @State private var selectedDate = Date() 16 @State private var selectedTab = 0 17 18 var body: some View { 19 VStack(spacing: 0) { 20 // Tab Selector 21 Picker("Ansicht", selection: $selectedTab) { 22 Text("Übersicht").tag(0) 23 Text("Training").tag(1) 24 } 25 .pickerStyle(.segmented) 26 .padding() 27 28 if selectedTab == 0 { 29 // Dashboard Ansicht 30 WorkoutDashboardView(workoutManager: workoutManager) 31 } else { 32 // Original Training Liste 33 trainingListView 34 } 35 } 36 .navigationTitle("Workout Tracker") 37 .toolbar { 38 if selectedTab == 1 { 39 ToolbarItem(placement: .navigationBarTrailing) { 40 Button { 41 showingAddWorkout = true 42 } label: { 43 Label("Hinzufügen", systemImage: "plus") 44 } 45 } 46 } 47 } 48 .sheet(isPresented: $showingAddWorkout) { 49 AddWorkoutView(workoutManager: workoutManager, userProfile: userProfile, date: selectedDate) 50 } 51 } 52 53 private var trainingListView: some View { 54 List { 55 // Empty section for top spacing 56 Section { 57 EmptyView() 58 } 59 .frame(height: 0) 60 .listRowBackground(Color.clear) 61 62 Section(header: Text("Kalender")) { 63 DatePicker("Datum", selection: $selectedDate, displayedComponents: .date) 64 .datePickerStyle(.compact) 65 66 HStack { 67 Text("Verbrannte Kalorien heute:") 68 .font(.headline) 69 Spacer() 70 Text("\(workoutManager.totalCaloriesBurnedWithHealthKit(date: selectedDate, healthManager: dataManager.healthManager)) kcal") 71 .fontWeight(.bold) 72 .foregroundColor(.green) 73 } 74 75 HStack { 76 Text("Verbrannte Kalorien diese Woche:") 77 .font(.headline) 78 Spacer() 79 Text("\(workoutManager.totalCaloriesBurnedForWeek(startingFrom: selectedDate)) kcal") 80 .fontWeight(.bold) 81 .foregroundColor(.blue) 82 } 83 } 84 85 Section(header: Text("Trainingseinheiten für \(formattedDate)")) { 86 let dayWorkouts = workoutManager.workoutsForDay(selectedDate) 87 88 if dayWorkouts.isEmpty { 89 Text("Keine Trainingseinheiten an diesem Tag") 90 .foregroundColor(.secondary) 91 .italic() 92 } else { 93 ForEach(dayWorkouts) { workout in 94 VStack(alignment: .leading, spacing: 4) { 95 HStack { 96 Image(systemName: workout.type.icon) 97 .foregroundColor(.blue) 98 .frame(width: 24, height: 24) 99 100 VStack(alignment: .leading) { 101 Text(workout.type.rawValue) 102 .font(.headline) 103 104 Text(formattedTime(for: workout.date)) 105 .font(.caption) 106 .foregroundColor(.secondary) 107 } 108 109 Spacer() 110 111 VStack(alignment: .trailing) { 112 Text("\(workout.caloriesBurned) kcal") 113 .fontWeight(.bold) 114 .foregroundColor(.green) 115 116 Text("\(Int(workout.duration / 60)) Min.") 117 .font(.caption) 118 .foregroundColor(.secondary) 119 } 120 } 121 122 if !workout.notes.isEmpty { 123 Text(workout.notes) 124 .font(.caption) 125 .foregroundColor(.secondary) 126 .padding(.leading, 28) 127 } 128 } 129 .padding(.vertical, 4) 130 } 131 .onDelete { indexSet in 132 // Konvertiere Indizes aus der gefilterten Liste in Indizes der Hauptliste 133 let workoutsToDelete = indexSet.map { dayWorkouts[$0] } 134 for workout in workoutsToDelete { 135 if let index = workoutManager.workouts.firstIndex(where: { $0.id == workout.id }) { 136 workoutManager.workouts.remove(at: index) 137 } 138 } 139 } 140 } 141 } 142 143 // Zusätzliche Informationen für den Benutzer 144 VStack(alignment: .leading, spacing: 4) { 145 Text("Hinweis:") 146 .font(.caption) 147 .fontWeight(.bold) 148 Text("Verbrannte Kalorien werden in der Tagesübersicht automatisch von deiner Kalorienbilanz abgezogen.") 149 .font(.caption) 150 .foregroundColor(.secondary) 151 } 152 .padding(.vertical, 6) 153 } 154 } 155 156 private var formattedDate: String { 157 let formatter = DateFormatter() 158 formatter.dateStyle = .medium 159 return formatter.string(from: selectedDate) 160 } 161 162 private func formattedTime(for date: Date) -> String { 163 let formatter = DateFormatter() 164 formatter.timeStyle = .short 165 return formatter.string(from: date) 166 } 167 } 168 169 struct AddWorkoutView: View { 170 @Environment(\.dismiss) private var dismiss 171 @ObservedObject var workoutManager: WorkoutManager 172 @ObservedObject var userProfile: UserProfile 173 174 var date: Date 175 176 @State private var selectedWorkoutType: WorkoutType = .running 177 @State private var duration = 30.0 // in Minuten 178 @State private var notes = "" 179 180 var body: some View { 181 NavigationStack { 182 Form { 183 Section(header: Text("Trainingsdetails")) { 184 Picker("Trainingsart", selection: $selectedWorkoutType) { 185 ForEach(WorkoutType.allCases) { type in 186 Label { 187 Text(type.rawValue) 188 } icon: { 189 Image(systemName: type.icon) 190 } 191 .tag(type) 192 } 193 } 194 195 VStack(alignment: .leading) { 196 Text("Dauer: \(Int(duration)) Minuten") 197 Slider(value: $duration, in: 5...180, step: 5) 198 } 199 200 // Kalorienvorschau 201 HStack { 202 Text("Geschätzte Kalorien:") 203 Spacer() 204 Text("\(estimatedCalories) kcal") 205 .fontWeight(.bold) 206 .foregroundColor(.green) 207 } 208 209 TextField("Notizen (optional)", text: $notes) 210 } 211 212 Section { 213 Button("Speichern") { 214 workoutManager.addWorkout( 215 type: selectedWorkoutType, 216 durationInMinutes: duration, 217 date: date, 218 userWeight: userProfile.weight, 219 notes: notes 220 ) 221 dismiss() 222 } 223 } 224 } 225 .navigationTitle("Training hinzufügen") 226 .navigationBarTitleDisplayMode(.inline) 227 .toolbar { 228 ToolbarItem(placement: .cancellationAction) { 229 Button("Abbrechen") { 230 dismiss() 231 } 232 } 233 } 234 } 235 } 236 237 // Berechnung der geschätzten Kalorien basierend auf den aktuellen Eingaben 238 private var estimatedCalories: Int { 239 Workout.calculateCalories( 240 type: selectedWorkoutType, 241 durationInMinutes: duration, 242 weightInKg: userProfile.weight 243 ) 244 } 245 } 246 247 #Preview { 248 NavigationStack { 249 WorkoutView(workoutManager: WorkoutManager(), userProfile: UserProfile()) 250 } 251 }