Query:
I’m attempting to create an app on an apple watch that is ready to observe the repetitions of various workouts. To date, I’ve gotten down bicep curls and squats (for now). Although, I’ve an issue I’m not capable of repair. Each time I finish my exercise, it can take me to my abstract view, and after I click on performed from there, I would like it to take me again to my startScreen nevertheless it doesn’t achieve this. As a substitute, it takes me again to my exercise display screen and its simply caught there. I do know there’s loads of code to take a look at but when somebody may please assist me it could imply lots.**
**I’ve solely supplied the code that’s helpful beneath, so that you may see code for different views that I have never given code to.
Choose Subject Space
Query
Physique
I’m attempting to create an app on an apple watch that is ready to observe the repetitions of various workouts. To date, I’ve gotten down bicep curls and squats (for now). Although, I’ve an issue I’m not capable of repair. Each time I finish my exercise, it can take me to my abstract view, and after I click on performed from there, I would like it to take me again to my startScreen nevertheless it doesn’t achieve this. As a substitute, it takes me again to my exercise display screen and its simply caught there. I do know there’s loads of code to take a look at but when somebody may please assist me it could imply lots.
I’ve solely supplied the code that’s helpful beneath, so that you may see code for different views that I have never given code to.
import SwiftUI
@fundamental
struct RepBuddyWatchApp_Watch_AppApp: App {
@StateObject personal var workoutManager = WorkoutManager()
@State personal var navigationPath = NavigationPath()
var physique: some Scene {
WindowGroup {
NavigationStack(path: $navigationPath) {
StartScreen(navigationPath: $navigationPath)
.environmentObject(workoutManager) // <- Add this line
}
.sheet(isPresented: $workoutManager.showingSummaryView, onDismiss: {
print("Sheet dismissed, resetting navigationPath")
workoutManager.showingSummaryView = false // Reset the state
workoutManager.selectedWorkout = nil
}) {
SummaryView(navigationPath: $navigationPath)
.environmentObject(workoutManager)
}
}
}
}
import SwiftUI
import HealthKit
struct WorkoutType: View {
@EnvironmentObject var workoutManager: WorkoutManager
@Binding var navigationPath: NavigationPath
var workoutTypes: [(type: HKWorkoutActivityType, name: String)] = [
(.traditionalStrengthTraining, "Bench Press"),
(.traditionalStrengthTraining, "Bicep Curls"),
(.traditionalStrengthTraining, "Squats"),
(.traditionalStrengthTraining, "Tricep Extensions"),
]
var physique: some View {
Listing(workoutTypes, id: .title) { exercise in
NavigationLink(vacation spot: SessionPagingView(
navigationPath: $navigationPath,
workoutType: exercise.kind,
workoutName: exercise.title // Cross the title right here
).environmentObject(workoutManager)) {
Textual content(exercise.title)
}
}
.listStyle(.carousel)
.navigationTitle("Choose a Exercise")
.onAppear {
workoutManager.requestAuthorization { _ in }
}
}
}
#Preview {
WorkoutType(navigationPath: .fixed(NavigationPath()))
.environmentObject(WorkoutManager())
}
// Conforming HKWorkoutActivityType to Identifiable
extension HKWorkoutActivityType: @retroactive Identifiable {
public var id: UInt {
rawValue
}
var title: String {
change self {
case .working:
return "Run"
case .biking:
return "Bike"
case .strolling:
return "Stroll"
case .traditionalStrengthTraining:
return ""
default:
return ""
}
}
}
import SwiftUI
struct ControlsView: View {
@EnvironmentObject var workoutManager: WorkoutManager
var physique: some View {
HStack {
VStack {
Button {
if let session = workoutManager.session {
if session.state == .working || session.state == .paused {
workoutManager.endWorkout()
} else {
print("Exercise session is already ended or in an invalid state: (session.state)")
}
}
} label: {
Picture(systemName: "xmark")
}
.tint(Colour.pink)
.font(.title2)
Textual content("Finish")
}
VStack {
Button {
workoutManager.togglePause()
} label: {
Picture(systemName: workoutManager.working ? "pause" : "play") // Begins as "pause"
}
.tint(Colour.yellow)
.font(.title2)
Textual content(workoutManager.working ? "Pause" : "Resume") // Textual content begins as "Pause"
}
}
}
}
#Preview {
ControlsView()
.environmentObject(WorkoutManager())
}
import Basis
import HealthKit
import CoreMotion
class WorkoutManager: NSObject, ObservableObject { //added to myWorkoutsApp bc its an observable object
var selectedWorkout: HKWorkoutActivityType? {
didSet {
guard let selectedWorkout = selectedWorkout, let selectedWorkoutName = selectedWorkoutName else { return }
startWorkout(workoutType: selectedWorkout, workoutName: selectedWorkoutName)
}
}
var selectedWorkoutName: String? // New property
@Revealed var elapsedTime: TimeInterval = 0
personal var timer: Timer?
@Revealed var showingSummaryView: Bool = false {
didSet {
// Sheet dismissed
if showingSummaryView == false {
resetWorkout()
}
}
}
//REPVIEW STUFF
// Begin the suitable train monitoring
if workoutType == .traditionalStrengthTraining {
change workoutName {
case "Bench Press":
motionTracker.startTracking(train: .benchPress)
case "Squats":
motionTracker.startTracking(train: .squats)
case "Bicep Curls":
motionTracker.startTracking(train: .bicepCurls)
case "Tricep Extensions":
motionTracker.startTracking(train: .tricepExtensions)
default:
print("Unknown exercise kind: (workoutName)")
}
}
}
}
//repbuddy
personal let motionManager = CMMotionManager()
personal var lastAcceleration: Double = 0.0
personal var isCurling = false
@Revealed var curlCount = 0
func stopWorkout() {
session?.finish()
motionTracker.stopTracking()
}
override init() {
tremendous.init()
motionTracker.$repCount.assign(to: &$repCount)
}
**func resetWorkout() {
// Reset squat monitoring
// Reset normal exercise properties
selectedWorkout = nil
builder = nil
session = nil // No must name session?.finish() right here
exercise = nil
activeEnergy = 0
averageHeartRate = 0
heartRate = 0
distance = 0
working = false
}**
@Revealed var hasRequestedAuthorization = false
// Request authorization to entry HealthKit.
func requestAuthorization(completion: @escaping (Bool) -> Void) {
// MARK: - State Management
// The exercise session state.
@Revealed var working = false
func pause() {
session?.pause()
}
func resume() {
session?.resume()
}
@Revealed var isPausing: Bool = false
func togglePause() {
guard !isPausing else { return } // Stop speedy toggling
isPausing = true
if working {
pause()
working = false
motionTracker.stopTracking() // Cease monitoring reps when paused
} else {
resume()
working = true
if selectedWorkout == .traditionalStrengthTraining, let selectedWorkoutName = selectedWorkoutName {
change selectedWorkoutName {
case "Bench Press":
motionTracker.startTracking(train: .benchPress)
case "Squats":
motionTracker.startTracking(train: .squats)
case "Bicep Curls":
motionTracker.startTracking(train: .bicepCurls)
case "Tricep Extensions":
motionTracker.startTracking(train: .tricepExtensions)
default:
print("Unknown exercise: (selectedWorkoutName)")
}
}
}
DispatchQueue.fundamental.asyncAfter(deadline: .now() + 1) {
self.isPausing = false
}
}
@Revealed var isEndingWorkout = false
func endWorkout() {
guard !isEndingWorkout else { return } // Stop a number of calls
isEndingWorkout = true
print("Ending exercise, showingSummaryView: (showingSummaryView)")
guard !showingSummaryView else { return } // Stop a number of sheet displays
session?.finish()
builder?.endCollection(withEnd: Date()) { success, error in
if let error = error {
print("Failed to finish knowledge assortment: (error.localizedDescription)")
} else {
print("Knowledge assortment ended efficiently")
self.saveWorkout() // Name saveWorkout() after ending
}
}
DispatchQueue.fundamental.async {
self.showingSummaryView = true // Set off sheet
}
DispatchQueue.fundamental.asyncAfter(deadline: .now() + 1) {
self.isEndingWorkout = false
}
updateRunningState()
}
func saveWorkout() {
builder?.finishWorkout { exercise, error in
DispatchQueue.fundamental.async {
if let error = error {
print("Error saving exercise: (error.localizedDescription)")
return
}
if let exercise = exercise {
self.exercise = exercise
print("Exercise saved: (exercise)")
} else {
print("Exercise is nil")
}
}
}
}
public func updateRunningState() {
DispatchQueue.fundamental.async {
if let session = self.session {
_ = self.working
self.working = (session.state == .working)
} else {
print("No energetic session present in updateRunningState.")
self.working = false
}
}
}
}
func recoverWorkoutSession() {
healthStore.recoverActiveWorkoutSession { (session, error) in
if let session = session {
self.session = session
self.session?.delegate = self
self.builder = session.associatedWorkoutBuilder()
self.builder?.delegate = self
// Resume the session
self.session?.resume()
} else if let error = error {
print("Didn't get well exercise session: (error.localizedDescription)")
}
}
}
}
default:
print("Unknown exercise: (selectedWorkoutName)")
}
}
case .paused:
self.working = false
self.motionTracker.stopTracking() // Cease rep monitoring when paused
case .ended, .stopped, .ready:
self.working = false
self.motionTracker.stopTracking() // Guarantee reps cease when exercise ends
@unknown default:
self.working = false
}
self.updateRunningState()
}
}
// Add this technique to deal with session failures
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
DispatchQueue.fundamental.async {
print("Exercise session failed with error: (error.localizedDescription)")
}
}
}
// MARK: - HKLiveWorkoutBuilderDelegate
// MARK: - HKLiveWorkoutBuilderDelegate
extension WorkoutManager: HKLiveWorkoutBuilderDelegate {
func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
}
func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set) {
for kind in collectedTypes {
guard let quantityType = kind as? HKQuantityType else { return }
let statistics = workoutBuilder.statistics(for: quantityType)
// Replace the revealed values.
updateForStatistics(statistics)
}
// Repeatedly replace the elapsedTime from the builder
DispatchQueue.fundamental.async {
self.elapsedTime = workoutBuilder.elapsedTime
}
}
}
import SwiftUI
struct RepView: View {
@EnvironmentObject var workoutManager: WorkoutManager
var workoutName: String
var physique: some View {
VStack {
Textual content("Counting (workoutName)")
.font(.title2)
.multilineTextAlignment(.heart)
.lineLimit(4)
Textual content("(workoutManager.repCount)") // Up to date to make use of MotionTracker's rep rely
.font(.largeTitle)
.multilineTextAlignment(.heart)
.daring()
.foregroundColor(.inexperienced)
Textual content("reps accomplished")
.font(.caption)
.multilineTextAlignment(.heart)
}
}
}
#Preview {
RepView(workoutName: "Bicep Curls")
.environmentObject(WorkoutManager())
}
import SwiftUI
import HealthKit
struct SummaryView: View {
@Atmosphere(.dismiss) var dismiss
@EnvironmentObject var workoutManager: WorkoutManager
@Binding var navigationPath: NavigationPath // Make it elective
var physique: some View {
if workoutManager.exercise == nil {
ProgressView("Saving exercise")
.navigationBarHidden(true)
Button("Achieved") {
dismiss()
DispatchQueue.fundamental.async {
navigationPath.removeLast(navigationPath.rely) // Reset the navigation path
}
}
}
.scenePadding()
}
.navigationTitle("Abstract")
.navigationBarTitleDisplayMode(.inline)
}
}
}
#Preview {
SummaryView(navigationPath: .fixed(NavigationPath()))
.environmentObject(WorkoutManager())
}
struct SummaryMetricView: View {
var title: String
var worth: String
var physique: some View {
Textual content(title)
Textual content(worth)
.font(.system(.title2, design: .rounded)
.lowercaseSmallCaps()
)
.foregroundColor(.accentColor)
Divider()
}
}