try to fix watch stuff

This commit is contained in:
Trey t
2024-07-01 21:22:12 -05:00
parent cee84d7776
commit f1781744ca
14 changed files with 187 additions and 157 deletions

View File

@@ -8,18 +8,20 @@
import SwiftUI
struct MainWatchView: View {
@StateObject var vm = WatchMainViewModel.shared
@ObservedObject var vm = WatchMainViewModel.shared
@ObservedObject var watchWorkout = WatchWorkout.shared
var body: some View {
VStack {
HStack {
if vm.isInWorkout {
if watchWorkout.isInWorkout {
HStack {
Text(vm.watchPackageModel.currentExerciseName)
.font(.body)
.foregroundColor(.white)
.lineLimit(10)
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: .infinity, alignment: .leading)
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
Text("\(vm.watchPackageModel.currentTimeLeft )")
.font(.title)
@@ -27,28 +29,27 @@ struct MainWatchView: View {
.lineLimit(10)
.fixedSize(horizontal: false, vertical: true)
}
}
HStack {
if let heartValue = vm.heartValue {
VStack {
Image(systemName: "heart.fill")
.font(Font.system(size: 22))
.scaledToFit()
.minimumScaleFactor(0.01)
.lineLimit(1)
.foregroundColor(.red)
Text("\(heartValue)")
.font(Font.system(size: 55))
.scaledToFit()
.minimumScaleFactor(0.01)
.lineLimit(1)
.foregroundColor(.red)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
if vm.isInWorkout {
HStack {
if let heartValue = watchWorkout.heartValue {
VStack {
Image(systemName: "heart.fill")
.font(Font.system(size: 22))
.scaledToFit()
.minimumScaleFactor(0.01)
.lineLimit(1)
.foregroundColor(.red)
Text("\(heartValue)")
.font(Font.system(size: 55))
.scaledToFit()
.minimumScaleFactor(0.01)
.lineLimit(1)
.foregroundColor(.red)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
Button(action: {
vm.nextExercise()
}, label: {
@@ -57,12 +58,10 @@ struct MainWatchView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity)
})
.buttonStyle(BorderedButtonStyle(tint: .green))
} else {
VStack {
Text("No Werkout")
Text("🍑")
}
}
} else {
Text("No Werkout")
Text("🍑")
}
}
}

View File

@@ -9,6 +9,7 @@ import SwiftUI
struct WatchControlView: View {
@StateObject var vm = WatchMainViewModel.shared
@StateObject var watchWorkout = WatchWorkout.shared
var body: some View {
HStack {
@@ -44,7 +45,7 @@ struct WatchControlView: View {
Button(action: {
vm.pauseWorkout()
}, label: {
if vm.isPaused {
if watchWorkout.isPaused {
Image(systemName: "play")
.font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)

View File

@@ -0,0 +1,41 @@
//
// WatchDelegate.swift
// Werkout_watch Watch App
//
// Created by Trey Tartt on 7/1/24.
//
import WatchKit
import HealthKit
class WatchDelegate: NSObject, WKApplicationDelegate {
func applicationDidFinishLaunching() {
autorizeHealthKit()
}
func applicationDidBecomeActive() {
}
func applicationWillResignActive() {
}
func handle(_ workoutConfiguration: HKWorkoutConfiguration) {
// WatchWorkout.shared.startWorkout()
}
func autorizeHealthKit() {
let healthKitTypes: Set = [
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .oxygenSaturation)!,
HKQuantityType.workoutType()
]
HKHealthStore().requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (succ, error) in
if !succ {
fatalError("Error requesting authorization from health store: \(String(describing: error)))")
}
}
}
}

View File

@@ -18,8 +18,10 @@ extension WatchMainViewModel: WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print("activation did complete")
}
func send(_ data: Data) {
}
class DataSender {
static func send(_ data: Data) {
guard WCSession.default.activationState == .activated else {
return
}

View File

@@ -12,81 +12,59 @@ import HealthKit
class WatchMainViewModel: NSObject, ObservableObject {
static let shared = WatchMainViewModel()
var session: WCSession
@Published var isInWorkout = false
@Published var watchPackageModel = WatchMainViewModel.defualtPackageModle
@Published var heartValue: Int?
static var defualtPackageModle: WatchPackageModel {
WatchPackageModel(currentExerciseName: "", currentExerciseID: -1, currentTimeLeft: -1, workoutStartDate: Date())
}
let healthStore = HKHealthStore()
var hkWorkoutSession: HKWorkoutSession?
var hkBuilder: HKLiveWorkoutBuilder?
var heartRates = [Int]()
@Published var isPaused = false
override init() {
session = WCSession.default
super.init()
session.delegate = self
session.activate()
autorizeHealthKit()
}
func autorizeHealthKit() {
let healthKitTypes: Set = [
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .oxygenSaturation)!,
HKQuantityType.workoutType()
]
healthStore.requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (succ, error) in
if !succ {
fatalError("Error requesting authorization from health store: \(String(describing: error)))")
}
}
}
// actions from view
func nextExercise() {
let nextExerciseAction = WatchActions.nextExercise
let data = try! JSONEncoder().encode(nextExerciseAction)
send(data)
DataSender.send(data)
WKInterfaceDevice.current().play(.start)
}
func restartExercise() {
let nextExerciseAction = WatchActions.restartExercise
let data = try! JSONEncoder().encode(nextExerciseAction)
send(data)
DataSender.send(data)
WKInterfaceDevice.current().play(.start)
}
func previousExercise() {
let nextExerciseAction = WatchActions.previousExercise
let data = try! JSONEncoder().encode(nextExerciseAction)
send(data)
DataSender.send(data)
WKInterfaceDevice.current().play(.start)
}
func completeWorkout() {
let nextExerciseAction = WatchActions.stopWorkout
let data = try! JSONEncoder().encode(nextExerciseAction)
send(data)
DataSender.send(data)
WKInterfaceDevice.current().play(.start)
}
func pauseWorkout() {
let nextExerciseAction = WatchActions.pauseWorkout
let data = try! JSONEncoder().encode(nextExerciseAction)
send(data)
isPaused = !isPaused
DataSender.send(data)
WKInterfaceDevice.current().play(.start)
WatchWorkout.shared.togglePaused()
}
func dataToAction(messageData: Data) {
@@ -94,27 +72,19 @@ class WatchMainViewModel: NSObject, ObservableObject {
DispatchQueue.main.async {
switch model {
case .inExercise(let newWatchPackageModel):
if !self.isInWorkout {
self.startWorkout()
}
WatchWorkout.shared.startWorkout()
if self.watchPackageModel.currentExerciseID != newWatchPackageModel.currentExerciseID {
self.isPaused = false
WKInterfaceDevice.current().play(.start)
}
self.watchPackageModel = newWatchPackageModel
case .reset:
self.isInWorkout = false
self.watchPackageModel = WatchMainViewModel.defualtPackageModle
self.stopWorkout(sendDetails: false)
WatchWorkout.shared.stopWorkout(sendDetails: false)
case .endWorkout:
self.isInWorkout = false
self.watchPackageModel = WatchMainViewModel.defualtPackageModle
self.stopWorkout(sendDetails: true)
WatchWorkout.shared.stopWorkout(sendDetails: true)
case .startWorkout:
if self.isInWorkout {
self.stopWorkout(sendDetails: false)
}
self.startWorkout()
WatchWorkout.shared.startWorkout()
}
}
}

View File

@@ -1,96 +1,85 @@
//
// WatchMainViewModel+WorkoutActions.swift
// WatchWorkout.swift
// Werkout_watch Watch App
//
// Created by Trey Tartt on 6/19/24.
// Created by Trey Tartt on 7/1/24.
//
import Foundation
import WatchConnectivity
import SwiftUI
import HealthKit
extension WatchMainViewModel {
func initWorkout() -> Bool {
let configuration = HKWorkoutConfiguration()
configuration.activityType = .functionalStrengthTraining
configuration.locationType = .indoor
class WatchWorkout: NSObject, ObservableObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {
static let shared = WatchWorkout()
@Published var heartValue: Int?
let healthStore = HKHealthStore()
var hkWorkoutSession: HKWorkoutSession
var hkBuilder: HKLiveWorkoutBuilder
var heartRates = [Int]()
@Published var isInWorkout = false
@Published var isPaused = false
private override init() {
do {
let configuration = HKWorkoutConfiguration()
configuration.activityType = .functionalStrengthTraining
configuration.locationType = .indoor
hkWorkoutSession = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
hkBuilder = hkWorkoutSession?.associatedWorkoutBuilder()
hkBuilder = hkWorkoutSession.associatedWorkoutBuilder()
super.init()
hkWorkoutSession.delegate = self
hkBuilder.delegate = self
/// Set the workout builder's data source.
hkBuilder.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
workoutConfiguration: configuration)
} catch {
fatalError("Unable to create the workout session!")
fatalError()
}
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
if isInWorkout { 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)))")
}
// 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
isPaused = false
WKInterfaceDevice.current().play(.start)
} else {
print("did not init workout")
}
isInWorkout = true
//WKInterfaceDevice.current().play(.start)
}
func stopWorkout(sendDetails: Bool) {
guard let hkWorkoutSession = hkWorkoutSession, let hkBuilder = hkBuilder else {
return
}
hkWorkoutSession.end()
self.heartRates.removeAll()
self.isInWorkout = false
hkBuilder.endCollection(withEnd: Date()) { (success, error) in
hkBuilder.finishWorkout { (workout, error) in
if !success || error != nil { return }
self.hkBuilder.finishWorkout { (workout, error) in
guard let workout = workout else { return }
if !sendDetails { return }
DispatchQueue.main.async() {
self.hkWorkoutSession = nil
self.hkBuilder = nil
self.heartRates.removeAll()
self.isInWorkout = false
self.isPaused = false
guard let id = workout?.uuid else {
return
}
let watchFinishWorkoutModel = WatchFinishWorkoutModel(healthKitUUID: id)
let watchFinishWorkoutModel = WatchFinishWorkoutModel(healthKitUUID: workout.uuid)
let data = try! JSONEncoder().encode(watchFinishWorkoutModel)
let watchAction = WatchActions.workoutComplete(data)
let watchActionData = try! JSONEncoder().encode(watchAction)
if sendDetails {
self.send(watchActionData)
}
DataSender.send(watchActionData)
}
}
}
}
}
extension WatchMainViewModel: HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {
func togglePaused() {
self.isPaused.toggle()
}
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
print("[workoutSession] Changed State: \(toState.rawValue)")
}

View File

@@ -9,6 +9,8 @@ import SwiftUI
@main
struct Werkout_watch_Watch_AppApp: App {
@WKApplicationDelegateAdaptor(WatchDelegate.self) var delegate: WatchDelegate
var body: some Scene {
WindowGroup {
ContentView()