Files
workoutsplus/WorkoutsPlus/Features/Workout/WorkoutLibrary.swift
2024-10-28 12:00:56 +01:00

126 lines
3.4 KiB
Swift

//
// WorkoutLibrary.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 10.08.24.
//
import SwiftUI
import SwiftData
struct WorkoutLibrary: View {
@Environment(\.modelContext) private var modelContext
@Default(\.isWorkingOut) var isWorkingOut
@Binding var activeWorkoutSession: WorkoutSession?
@Query(sort: \Workout.name) private var workouts: [Workout]
@State private var newWorkout: Workout = Workout(name: "")
@State private var newWorkoutName: String = ""
@State private var isAddingWorkout: Bool = false
@FocusState private var isInputFieldFocused: Bool
@State private var searchText: String = ""
var filteredItems: [Workout] {
if searchText.isEmpty { return workouts }
else { return workouts.filter { $0.name.localizedCaseInsensitiveContains(searchText) }
}
}
var body: some View {
Group {
List {
ForEach(filteredItems) { workout in
NavigationLink {
WorkoutDetail(activeWorkoutSession: $activeWorkoutSession, workout: workout)
} label: {
Image(systemName: workout.workoutIconSystemName)
.foregroundStyle(workout.workoutIconColorName.color)
Text(workout.name)
}
.swipeActions(edge: .leading) {
if !isWorkingOut {
Button {
activeWorkoutSession = workout.start()
} label: {
Label("Start", systemImage: "play")
.tint(.green)
}
}
}
}
.onDelete(perform: deleteWorkout)
if filteredItems.isEmpty {
ContentUnavailableView.search(text: searchText)
}
if isAddingWorkout {
// TODO: On tap-out of the text field, it should lose focus
TextField("New Workout", text: $newWorkoutName, onCommit: {
save(workout: newWorkout)
})
.textInputAutocapitalization(.words)
.focused($isInputFieldFocused)
}
// TODO: When pressing the button again, it should check if something is being added already and if yes, save it.
AddItemButton(label: "Workout", action: addWorkout)
}
.searchable(text: $searchText)
}
.navigationTitle("Workouts")
.toolbar {
ToolbarItem() {
EditButton()
}
}
}
private func addWorkout() {
withAnimation {
newWorkout = Workout(name: "")
newWorkoutName = ""
isAddingWorkout = true
isInputFieldFocused = true
}
}
private func save(workout: Workout) {
withAnimation {
newWorkout.name = newWorkoutName
if !workout.name.isEmpty {
modelContext.insert(workout)
try? modelContext.save()
}
isAddingWorkout = false
}
}
private func deleteWorkout(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(workouts[index])
}
try? modelContext.save()
}
}
}
#Preview("With Sample Data") {
@Previewable @State var activeWorkoutSession: WorkoutSession?
NavigationStack {
WorkoutLibrary(activeWorkoutSession: $activeWorkoutSession)
}
.modelContainer(SampleData.shared.modelContainer)
}
#Preview("Empty Database") {
@Previewable @State var activeWorkoutSession: WorkoutSession?
NavigationStack {
WorkoutLibrary(activeWorkoutSession: $activeWorkoutSession)
}
.modelContainer(for: Workout.self, inMemory: true)
}