add NavigationManager for programatic navigation from the root

This commit is contained in:
Felix Förtsch
2024-11-04 14:43:47 +01:00
parent c722d59aff
commit 19b3d89010
6 changed files with 73 additions and 12 deletions

View File

@@ -0,0 +1,26 @@
//
// NavigationManager.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 04.11.24.
//
import SwiftUI
class NavigationManager: ObservableObject {
@Published var path = NavigationPath()
func navigateFromRoot(to destination: NavigationDestination) {
path = NavigationPath()
path.append(destination)
}
}
enum NavigationDestination: Hashable {
case activeWorkoutSession
case workoutLibrary
case workoutLog
case exerciseLibrary
case settings
case debug
}

View File

@@ -10,6 +10,7 @@ import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@StateObject private var navigationManager = NavigationManager()
@Default(\.isOnboarding) var isOnboarding
@Default(\.isWorkingOut) var isWorkingOut
@@ -17,7 +18,7 @@ struct ContentView: View {
@State var activeWorkoutSession: WorkoutSession?
var body: some View {
NavigationStack {
NavigationStack(path: $navigationManager.path) {
List {
Section {
VStack {
@@ -73,30 +74,33 @@ struct ContentView: View {
}
}
Section {
NavigationLink(destination: WorkoutLog()) {
NavigationLink(value: NavigationDestination.workoutLog) {
Label("Workout Log", systemImage: "calendar.badge.clock")
}
NavigationLink(destination: WorkoutLibrary(activeWorkoutSession: $activeWorkoutSession)) {
NavigationLink(value: NavigationDestination.workoutLibrary) {
Label("Workouts", systemImage: "figure.run.square.stack")
}
NavigationLink(destination: ExerciseLibrary()) {
NavigationLink(value: NavigationDestination.exerciseLibrary) {
Label("Exercises", systemImage: "figure.run")
}
}
Section {
Label("Food Log", systemImage: "list.bullet.clipboard")
NavigationLink(destination: Label("Add Food", systemImage: "plus")) {
Label("Food Library", systemImage: "fork.knife")
}
}
Section {
NavigationLink(destination: Settings()) {
NavigationLink(value: NavigationDestination.settings) {
Label("Settings", systemImage: "gear")
}
NavigationLink(destination: DebugList()) {
NavigationLink(value: NavigationDestination.debug) {
Label("Debug", systemImage: "hammer")
}
}
@@ -120,10 +124,32 @@ struct ContentView: View {
}
}
}
.navigationDestination(for: NavigationDestination.self) { destination in
switch destination {
case .activeWorkoutSession:
if let _ = activeWorkoutSession {
ActiveWorkoutSession(activeWorkoutSession: Binding(
get: { activeWorkoutSession! },
set: { activeWorkoutSession = $0 }
))
}
case .workoutLibrary:
WorkoutLibrary(activeWorkoutSession: $activeWorkoutSession)
case .workoutLog:
WorkoutLog()
case .exerciseLibrary:
ExerciseLibrary()
case .settings:
Settings()
case .debug:
DebugList()
}
}
}
.environmentObject(navigationManager)
.sheet(isPresented: $isOnboarding) { Onboarding() }
}
}
#Preview("No Workout Session") {

View File

@@ -11,6 +11,7 @@ import SwiftData
struct WorkoutDetail: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) private var modelContext
@EnvironmentObject private var navigationManager: NavigationManager
@Default(\.isWorkingOut) var isWorkingOut
@@ -73,6 +74,7 @@ struct WorkoutDetail: View {
Button(action: {
isWorkingOut = true
activeWorkoutSession = workout.start()
navigationManager.navigateFromRoot(to: .activeWorkoutSession)
}) {
HStack {
Image(systemName: "play.fill")

View File

@@ -7,10 +7,9 @@
import SwiftUI
// TODO: We need color pairs (one for light mode one for dark)
struct WorkoutIconSelector: View {
@State var workout: Workout
@State private var searchText: String = ""
var filteredIcons: [String] {
if searchText.isEmpty {

View File

@@ -10,6 +10,7 @@ import SwiftData
struct WorkoutLibrary: View {
@Environment(\.modelContext) private var modelContext
@EnvironmentObject private var navigationManager: NavigationManager
@Default(\.isWorkingOut) var isWorkingOut
@Binding var activeWorkoutSession: WorkoutSession?
@@ -44,8 +45,9 @@ struct WorkoutLibrary: View {
if !isWorkingOut {
Button {
activeWorkoutSession = workout.start()
navigationManager.navigateFromRoot(to: .activeWorkoutSession)
} label: {
Label("Start", systemImage: "play")
Label("Quick Start Workout", systemImage: "play")
.tint(.green)
}
}

View File

@@ -24,6 +24,9 @@ final class WorkoutSessionItem: Nameable, Positionable {
var actualReps: Int?
var actualValue: Double?
var startDate: Date?
var stopDate: Date?
init(workoutSession: WorkoutSession, planned: WorkoutItem) {
self.workoutSession = workoutSession
self.name = planned.exercise.name
@@ -33,4 +36,7 @@ final class WorkoutSessionItem: Nameable, Positionable {
self.unit = planned.unit
self.metric = planned.metric
}
func start() { startDate = .now }
func stop() { stopDate = .now }
}