Files
workoutsplus/WorkoutsPlus/Workout/WorkoutLibrary.swift

120 lines
3.3 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
@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: {
Button(action: {
activeWorkoutSession = workout.start()
}) {
Image(systemName: "play.fill")
.foregroundStyle(.green)
}
// TODO: Decide if icon should appear here/create custom view
// Image(systemName: workout.workoutIconSystemName)
// .foregroundStyle(workout.workoutIconColorName.color)
Text(workout.name)
}
}
.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)
}