Files
WerkoutIOS/iphone/Werkout_watch Watch App/WatchMainViewModel+WorkoutActions.swift

125 lines
4.8 KiB
Swift

//
// WatchMainViewModel+WorkoutActions.swift
// Werkout_watch Watch App
//
// Created by Trey Tartt on 6/19/24.
//
import Foundation
import WatchConnectivity
import SwiftUI
import HealthKit
extension WatchMainViewModel {
func initWorkout() -> Bool {
let configuration = HKWorkoutConfiguration()
configuration.activityType = .functionalStrengthTraining
configuration.locationType = .indoor
do {
hkWorkoutSession = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
hkBuilder = hkWorkoutSession?.associatedWorkoutBuilder()
} catch {
fatalError("Unable to create the workout session!")
}
guard let hkWorkoutSession = hkWorkoutSession, let hkBuilder = hkBuilder else {
return false
}
// Setup session and builder.
hkWorkoutSession.delegate = self
hkBuilder.delegate = self
/// Set the workout builder's data source.
hkBuilder.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
workoutConfiguration: configuration)
return true
}
func startWorkout() {
// Initialize our workout
if initWorkout() {
guard let hkWorkoutSession = hkWorkoutSession, let hkBuilder = hkBuilder else {
return
}
// Start the workout session and begin data collection
hkWorkoutSession.startActivity(with: Date())
hkBuilder.beginCollection(withStart: Date()) { (succ, error) in
if !succ {
fatalError("Error beginning collection from builder: \(String(describing: error)))")
}
}
isInWorkout = true
} else {
print("did not init workout")
}
}
func stopWorkout(sendDetails: Bool) {
guard let hkWorkoutSession = hkWorkoutSession, let hkBuilder = hkBuilder else {
return
}
hkWorkoutSession.end()
hkBuilder.endCollection(withEnd: Date()) { (success, error) in
hkBuilder.finishWorkout { (workout, error) in
DispatchQueue.main.async() {
self.hkWorkoutSession = nil
self.hkBuilder = nil
self.heartRates.removeAll()
self.isInWorkout = false
guard let id = workout?.uuid else {
return
}
let watchFinishWorkoutModel = WatchFinishWorkoutModel(healthKitUUID: id)
let data = try! JSONEncoder().encode(watchFinishWorkoutModel)
let watchAction = WatchActions.workoutComplete(data)
let watchActionData = try! JSONEncoder().encode(watchAction)
if sendDetails {
self.send(watchActionData)
}
}
}
}
}
}
extension WatchMainViewModel: HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
print("[workoutSession] Changed State: \(toState.rawValue)")
}
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
print("[workoutSession] Encountered an error: \(error)")
}
func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) {
for type in collectedTypes {
guard let quantityType = type as? HKQuantityType else {
return
}
switch quantityType {
case HKQuantityType.quantityType(forIdentifier: .heartRate):
DispatchQueue.main.async() {
let statistics = workoutBuilder.statistics(for: quantityType)
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
let value = statistics!.mostRecentQuantity()?.doubleValue(for: heartRateUnit)
self.heartValue = Int(Double(round(1 * value!) / 1))
self.heartRates.append(Int(Double(round(1 * value!) / 1)))
print("[workoutBuilder] Heart Rate: \(String(describing: self.heartValue))")
}
default:
return
}
}
}
func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
guard let workoutEventType = workoutBuilder.workoutEvents.last?.type else { return }
print("[workoutBuilderDidCollectEvent] Workout Builder changed event: \(workoutEventType.rawValue)")
}
}