add NavigationManager for programatic navigation from the root
This commit is contained in:
26
WorkoutsPlus/Configuration/NavigationManager.swift
Normal file
26
WorkoutsPlus/Configuration/NavigationManager.swift
Normal 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
|
||||
}
|
||||
@@ -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") {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user