try to fix watch stuff
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1C0494812C23C53E003D18BB /* WatchMainViewModel+WorkoutActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494802C23C53E003D18BB /* WatchMainViewModel+WorkoutActions.swift */; };
|
|
||||||
1C0494832C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494822C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift */; };
|
1C0494832C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494822C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift */; };
|
||||||
1C0494872C23E7BD003D18BB /* BridgeModule+Watch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494862C23E7BD003D18BB /* BridgeModule+Watch.swift */; };
|
1C0494872C23E7BD003D18BB /* BridgeModule+Watch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494862C23E7BD003D18BB /* BridgeModule+Watch.swift */; };
|
||||||
1C0494882C23E7C5003D18BB /* BridgeModule+Watch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494862C23E7BD003D18BB /* BridgeModule+Watch.swift */; };
|
1C0494882C23E7C5003D18BB /* BridgeModule+Watch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494862C23E7BD003D18BB /* BridgeModule+Watch.swift */; };
|
||||||
@@ -17,6 +16,8 @@
|
|||||||
1C04948E2C25CD3D003D18BB /* BridgeModule+WorkoutActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494892C25CB4F003D18BB /* BridgeModule+WorkoutActions.swift */; };
|
1C04948E2C25CD3D003D18BB /* BridgeModule+WorkoutActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494892C25CB4F003D18BB /* BridgeModule+WorkoutActions.swift */; };
|
||||||
1C0494932C25CEF0003D18BB /* BridgeModule+Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494922C25CEF0003D18BB /* BridgeModule+Timer.swift */; };
|
1C0494932C25CEF0003D18BB /* BridgeModule+Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494922C25CEF0003D18BB /* BridgeModule+Timer.swift */; };
|
||||||
1C0494942C25CEF4003D18BB /* BridgeModule+Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494922C25CEF0003D18BB /* BridgeModule+Timer.swift */; };
|
1C0494942C25CEF4003D18BB /* BridgeModule+Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0494922C25CEF0003D18BB /* BridgeModule+Timer.swift */; };
|
||||||
|
1C1A3C722C3373E10010CDD5 /* WatchDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A3C712C3373E10010CDD5 /* WatchDelegate.swift */; };
|
||||||
|
1C1A3C742C3376150010CDD5 /* WatchWorkout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C1A3C732C3376150010CDD5 /* WatchWorkout.swift */; };
|
||||||
1C31C8842A53AE3E00350540 /* short_beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 1C31C8822A53AE3E00350540 /* short_beep.m4a */; };
|
1C31C8842A53AE3E00350540 /* short_beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 1C31C8822A53AE3E00350540 /* short_beep.m4a */; };
|
||||||
1C31C8852A53AE3E00350540 /* long_beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 1C31C8832A53AE3E00350540 /* long_beep.m4a */; };
|
1C31C8852A53AE3E00350540 /* long_beep.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 1C31C8832A53AE3E00350540 /* long_beep.m4a */; };
|
||||||
1C31C8872A55B2CC00350540 /* PlayerUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C31C8862A55B2CC00350540 /* PlayerUIView.swift */; };
|
1C31C8872A55B2CC00350540 /* PlayerUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C31C8862A55B2CC00350540 /* PlayerUIView.swift */; };
|
||||||
@@ -154,12 +155,13 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1C0494802C23C53E003D18BB /* WatchMainViewModel+WorkoutActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatchMainViewModel+WorkoutActions.swift"; sourceTree = "<group>"; };
|
|
||||||
1C0494822C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatchMainViewModel+WCSessionDelegate.swift"; sourceTree = "<group>"; };
|
1C0494822C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatchMainViewModel+WCSessionDelegate.swift"; sourceTree = "<group>"; };
|
||||||
1C0494862C23E7BD003D18BB /* BridgeModule+Watch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeModule+Watch.swift"; sourceTree = "<group>"; };
|
1C0494862C23E7BD003D18BB /* BridgeModule+Watch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeModule+Watch.swift"; sourceTree = "<group>"; };
|
||||||
1C0494892C25CB4F003D18BB /* BridgeModule+WorkoutActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeModule+WorkoutActions.swift"; sourceTree = "<group>"; };
|
1C0494892C25CB4F003D18BB /* BridgeModule+WorkoutActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeModule+WorkoutActions.swift"; sourceTree = "<group>"; };
|
||||||
1C04948B2C25CB80003D18BB /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
|
1C04948B2C25CB80003D18BB /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
|
||||||
1C0494922C25CEF0003D18BB /* BridgeModule+Timer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeModule+Timer.swift"; sourceTree = "<group>"; };
|
1C0494922C25CEF0003D18BB /* BridgeModule+Timer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeModule+Timer.swift"; sourceTree = "<group>"; };
|
||||||
|
1C1A3C712C3373E10010CDD5 /* WatchDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
1C1A3C732C3376150010CDD5 /* WatchWorkout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchWorkout.swift; sourceTree = "<group>"; };
|
||||||
1C31C8822A53AE3E00350540 /* short_beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = short_beep.m4a; sourceTree = "<group>"; };
|
1C31C8822A53AE3E00350540 /* short_beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = short_beep.m4a; sourceTree = "<group>"; };
|
||||||
1C31C8832A53AE3E00350540 /* long_beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = long_beep.m4a; sourceTree = "<group>"; };
|
1C31C8832A53AE3E00350540 /* long_beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = long_beep.m4a; sourceTree = "<group>"; };
|
||||||
1C31C8862A55B2CC00350540 /* PlayerUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerUIView.swift; sourceTree = "<group>"; };
|
1C31C8862A55B2CC00350540 /* PlayerUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerUIView.swift; sourceTree = "<group>"; };
|
||||||
@@ -511,11 +513,12 @@
|
|||||||
children = (
|
children = (
|
||||||
1CF65AB72A4534DC0042FFBD /* Werkout_watch Watch App.entitlements */,
|
1CF65AB72A4534DC0042FFBD /* Werkout_watch Watch App.entitlements */,
|
||||||
1CF65AB82A45387B0042FFBD /* Werkout-watch-Watch-App-Info.plist */,
|
1CF65AB82A45387B0042FFBD /* Werkout-watch-Watch-App-Info.plist */,
|
||||||
|
1C1A3C732C3376150010CDD5 /* WatchWorkout.swift */,
|
||||||
|
1C1A3C712C3373E10010CDD5 /* WatchDelegate.swift */,
|
||||||
1CF65A972A452D270042FFBD /* ContentView.swift */,
|
1CF65A972A452D270042FFBD /* ContentView.swift */,
|
||||||
1C5190D32A59AEDE00885849 /* MainWatchView.swift */,
|
1C5190D32A59AEDE00885849 /* MainWatchView.swift */,
|
||||||
1C5190D12A59ACA400885849 /* WatchControlView.swift */,
|
1C5190D12A59ACA400885849 /* WatchControlView.swift */,
|
||||||
1CF65AB52A4532940042FFBD /* WatchMainViewModel.swift */,
|
1CF65AB52A4532940042FFBD /* WatchMainViewModel.swift */,
|
||||||
1C0494802C23C53E003D18BB /* WatchMainViewModel+WorkoutActions.swift */,
|
|
||||||
1C0494822C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift */,
|
1C0494822C23C56E003D18BB /* WatchMainViewModel+WCSessionDelegate.swift */,
|
||||||
1CF65A952A452D270042FFBD /* Werkout_watchApp.swift */,
|
1CF65A952A452D270042FFBD /* Werkout_watchApp.swift */,
|
||||||
1CF65A992A452D290042FFBD /* Assets.xcassets */,
|
1CF65A992A452D290042FFBD /* Assets.xcassets */,
|
||||||
@@ -735,6 +738,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
1C4AFF222A885EBD0027710B /* PreviewData.swift in Sources */,
|
1C4AFF222A885EBD0027710B /* PreviewData.swift in Sources */,
|
||||||
|
1C1A3C722C3373E10010CDD5 /* WatchDelegate.swift in Sources */,
|
||||||
1CF65A982A452D270042FFBD /* ContentView.swift in Sources */,
|
1CF65A982A452D270042FFBD /* ContentView.swift in Sources */,
|
||||||
1CF65A962A452D270042FFBD /* Werkout_watchApp.swift in Sources */,
|
1CF65A962A452D270042FFBD /* Werkout_watchApp.swift in Sources */,
|
||||||
1C4AFF192A65CD6F0027710B /* Superset.swift in Sources */,
|
1C4AFF192A65CD6F0027710B /* Superset.swift in Sources */,
|
||||||
@@ -759,7 +763,7 @@
|
|||||||
1C04948E2C25CD3D003D18BB /* BridgeModule+WorkoutActions.swift in Sources */,
|
1C04948E2C25CD3D003D18BB /* BridgeModule+WorkoutActions.swift in Sources */,
|
||||||
1C5190D42A59AEDE00885849 /* MainWatchView.swift in Sources */,
|
1C5190D42A59AEDE00885849 /* MainWatchView.swift in Sources */,
|
||||||
1CF65AB42A4530200042FFBD /* WatchPackageModel.swift in Sources */,
|
1CF65AB42A4530200042FFBD /* WatchPackageModel.swift in Sources */,
|
||||||
1C0494812C23C53E003D18BB /* WatchMainViewModel+WorkoutActions.swift in Sources */,
|
1C1A3C742C3376150010CDD5 /* WatchWorkout.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ extension BridgeModule {
|
|||||||
currentWorkoutRunTimer = nil
|
currentWorkoutRunTimer = nil
|
||||||
currentWorkoutRunTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { timer in
|
currentWorkoutRunTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { timer in
|
||||||
self.currentWorkoutRunTimeInSeconds += 1
|
self.currentWorkoutRunTimeInSeconds += 1
|
||||||
|
self.sendCurrentExerciseToWatch()
|
||||||
})
|
})
|
||||||
currentWorkoutRunTimer?.fire()
|
currentWorkoutRunTimer?.fire()
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,6 @@ extension BridgeModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendCurrentExerciseToWatch()
|
|
||||||
} else {
|
} else {
|
||||||
nextExercise()
|
nextExercise()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ extension BridgeModule {
|
|||||||
if let duration = exercise.duration, duration > 0 {
|
if let duration = exercise.duration, duration > 0 {
|
||||||
self.startExerciseTimerWith(duration: duration)
|
self.startExerciseTimerWith(duration: duration)
|
||||||
}
|
}
|
||||||
self.sendCurrentExerciseToWatch()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +103,9 @@ extension BridgeModule {
|
|||||||
|
|
||||||
func resetCurrentWorkout() {
|
func resetCurrentWorkout() {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
if self.isInWorkout {
|
||||||
|
self.sendWorkoutCompleteToWatch()
|
||||||
|
}
|
||||||
self.currentWorkoutRunTimeInSeconds = 0
|
self.currentWorkoutRunTimeInSeconds = 0
|
||||||
self.currentWorkoutRunTimer?.invalidate()
|
self.currentWorkoutRunTimer?.invalidate()
|
||||||
self.currentWorkoutRunTimer = nil
|
self.currentWorkoutRunTimer = nil
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ struct ExternalWorkoutDetailView: View {
|
|||||||
ExtCountdownView()
|
ExtCountdownView()
|
||||||
.padding(.leading, 50)
|
.padding(.leading, 50)
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 20)
|
||||||
|
|
||||||
if extShowNextVideo && extThotStyle != .off {
|
if extShowNextVideo && extThotStyle != .off {
|
||||||
PlayerView(player: $smallAVPlayer)
|
PlayerView(player: $smallAVPlayer)
|
||||||
.frame(width: metrics.size.width * 0.2,
|
.frame(width: metrics.size.width * 0.2,
|
||||||
@@ -60,6 +61,34 @@ struct ExternalWorkoutDetailView: View {
|
|||||||
.edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VStack {
|
||||||
|
HStack {
|
||||||
|
if bridgeModule.currentWorkoutRunTimeInSeconds > -1 {
|
||||||
|
Text(" \(Double(bridgeModule.currentWorkoutRunTimeInSeconds).asString(style: .positional)) ")
|
||||||
|
.font(Font.system(size: 120))
|
||||||
|
.minimumScaleFactor(0.01)
|
||||||
|
.lineLimit(1)
|
||||||
|
.padding()
|
||||||
|
.bold()
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.strokeBorder(Color.black, lineWidth: 0.8)
|
||||||
|
.background(Color(uiColor: UIColor(red: 148/255,
|
||||||
|
green: 0,
|
||||||
|
blue: 211/255,
|
||||||
|
alpha: 0.5)))
|
||||||
|
.clipped()
|
||||||
|
)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.leading, 50)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.onChange(of: bridgeModule.isInWorkout, perform: { _ in
|
.onChange(of: bridgeModule.isInWorkout, perform: { _ in
|
||||||
playVideos()
|
playVideos()
|
||||||
|
|||||||
@@ -176,9 +176,8 @@ struct WorkoutDetailView: View {
|
|||||||
bridgeModule.completedWorkout = {
|
bridgeModule.completedWorkout = {
|
||||||
if let workoutData = createWorkoutData() {
|
if let workoutData = createWorkoutData() {
|
||||||
workoutComplete = .completedWorkout(workoutData)
|
workoutComplete = .completedWorkout(workoutData)
|
||||||
} else {
|
|
||||||
bridgeModule.resetCurrentWorkout()
|
|
||||||
}
|
}
|
||||||
|
bridgeModule.resetCurrentWorkout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onReceive(NotificationCenter.default.publisher(
|
.onReceive(NotificationCenter.default.publisher(
|
||||||
|
|||||||
@@ -21,16 +21,6 @@ struct ExtCountdownView: View {
|
|||||||
.minimumScaleFactor(0.01)
|
.minimumScaleFactor(0.01)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
if bridgeModule.currentWorkoutRunTimeInSeconds > -1 {
|
|
||||||
Text("\(Double(bridgeModule.currentWorkoutRunTimeInSeconds).asString(style: .positional))")
|
|
||||||
.font(Font.system(size: 100))
|
|
||||||
.scaledToFit()
|
|
||||||
.minimumScaleFactor(0.01)
|
|
||||||
.lineLimit(1)
|
|
||||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
|
||||||
.padding(.trailing, 100)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.frame(height: metrics.size.height * 0.5)
|
.frame(height: metrics.size.height * 0.5)
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,20 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct MainWatchView: View {
|
struct MainWatchView: View {
|
||||||
@StateObject var vm = WatchMainViewModel.shared
|
@ObservedObject var vm = WatchMainViewModel.shared
|
||||||
|
@ObservedObject var watchWorkout = WatchWorkout.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
if watchWorkout.isInWorkout {
|
||||||
if vm.isInWorkout {
|
HStack {
|
||||||
|
|
||||||
Text(vm.watchPackageModel.currentExerciseName)
|
Text(vm.watchPackageModel.currentExerciseName)
|
||||||
.font(.body)
|
.font(.body)
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.lineLimit(10)
|
.lineLimit(10)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
Divider()
|
Divider()
|
||||||
Text("\(vm.watchPackageModel.currentTimeLeft )")
|
Text("\(vm.watchPackageModel.currentTimeLeft )")
|
||||||
.font(.title)
|
.font(.title)
|
||||||
@@ -27,28 +29,27 @@ struct MainWatchView: View {
|
|||||||
.lineLimit(10)
|
.lineLimit(10)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.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: {
|
Button(action: {
|
||||||
vm.nextExercise()
|
vm.nextExercise()
|
||||||
}, label: {
|
}, label: {
|
||||||
@@ -57,12 +58,10 @@ struct MainWatchView: View {
|
|||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
})
|
})
|
||||||
.buttonStyle(BorderedButtonStyle(tint: .green))
|
.buttonStyle(BorderedButtonStyle(tint: .green))
|
||||||
} else {
|
|
||||||
VStack {
|
|
||||||
Text("No Werkout")
|
|
||||||
Text("🍑")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Text("No Werkout")
|
||||||
|
Text("🍑")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct WatchControlView: View {
|
struct WatchControlView: View {
|
||||||
@StateObject var vm = WatchMainViewModel.shared
|
@StateObject var vm = WatchMainViewModel.shared
|
||||||
|
@StateObject var watchWorkout = WatchWorkout.shared
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
@@ -44,7 +45,7 @@ struct WatchControlView: View {
|
|||||||
Button(action: {
|
Button(action: {
|
||||||
vm.pauseWorkout()
|
vm.pauseWorkout()
|
||||||
}, label: {
|
}, label: {
|
||||||
if vm.isPaused {
|
if watchWorkout.isPaused {
|
||||||
Image(systemName: "play")
|
Image(systemName: "play")
|
||||||
.font(.title)
|
.font(.title)
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
|||||||
41
iphone/Werkout_watch Watch App/WatchDelegate.swift
Normal file
41
iphone/Werkout_watch Watch App/WatchDelegate.swift
Normal 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)))")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,8 +18,10 @@ extension WatchMainViewModel: WCSessionDelegate {
|
|||||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
print("activation did complete")
|
print("activation did complete")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func send(_ data: Data) {
|
|
||||||
|
class DataSender {
|
||||||
|
static func send(_ data: Data) {
|
||||||
guard WCSession.default.activationState == .activated else {
|
guard WCSession.default.activationState == .activated else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,81 +12,59 @@ import HealthKit
|
|||||||
|
|
||||||
class WatchMainViewModel: NSObject, ObservableObject {
|
class WatchMainViewModel: NSObject, ObservableObject {
|
||||||
static let shared = WatchMainViewModel()
|
static let shared = WatchMainViewModel()
|
||||||
|
|
||||||
var session: WCSession
|
var session: WCSession
|
||||||
|
|
||||||
@Published var isInWorkout = false
|
|
||||||
@Published var watchPackageModel = WatchMainViewModel.defualtPackageModle
|
@Published var watchPackageModel = WatchMainViewModel.defualtPackageModle
|
||||||
|
|
||||||
@Published var heartValue: Int?
|
|
||||||
|
|
||||||
static var defualtPackageModle: WatchPackageModel {
|
static var defualtPackageModle: WatchPackageModel {
|
||||||
WatchPackageModel(currentExerciseName: "", currentExerciseID: -1, currentTimeLeft: -1, workoutStartDate: Date())
|
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() {
|
override init() {
|
||||||
session = WCSession.default
|
session = WCSession.default
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
session.delegate = self
|
session.delegate = self
|
||||||
session.activate()
|
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
|
// actions from view
|
||||||
func nextExercise() {
|
func nextExercise() {
|
||||||
let nextExerciseAction = WatchActions.nextExercise
|
let nextExerciseAction = WatchActions.nextExercise
|
||||||
let data = try! JSONEncoder().encode(nextExerciseAction)
|
let data = try! JSONEncoder().encode(nextExerciseAction)
|
||||||
send(data)
|
DataSender.send(data)
|
||||||
WKInterfaceDevice.current().play(.start)
|
WKInterfaceDevice.current().play(.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func restartExercise() {
|
func restartExercise() {
|
||||||
let nextExerciseAction = WatchActions.restartExercise
|
let nextExerciseAction = WatchActions.restartExercise
|
||||||
let data = try! JSONEncoder().encode(nextExerciseAction)
|
let data = try! JSONEncoder().encode(nextExerciseAction)
|
||||||
send(data)
|
DataSender.send(data)
|
||||||
WKInterfaceDevice.current().play(.start)
|
WKInterfaceDevice.current().play(.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func previousExercise() {
|
func previousExercise() {
|
||||||
let nextExerciseAction = WatchActions.previousExercise
|
let nextExerciseAction = WatchActions.previousExercise
|
||||||
let data = try! JSONEncoder().encode(nextExerciseAction)
|
let data = try! JSONEncoder().encode(nextExerciseAction)
|
||||||
send(data)
|
DataSender.send(data)
|
||||||
WKInterfaceDevice.current().play(.start)
|
WKInterfaceDevice.current().play(.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func completeWorkout() {
|
func completeWorkout() {
|
||||||
let nextExerciseAction = WatchActions.stopWorkout
|
let nextExerciseAction = WatchActions.stopWorkout
|
||||||
let data = try! JSONEncoder().encode(nextExerciseAction)
|
let data = try! JSONEncoder().encode(nextExerciseAction)
|
||||||
send(data)
|
DataSender.send(data)
|
||||||
WKInterfaceDevice.current().play(.start)
|
WKInterfaceDevice.current().play(.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pauseWorkout() {
|
func pauseWorkout() {
|
||||||
let nextExerciseAction = WatchActions.pauseWorkout
|
let nextExerciseAction = WatchActions.pauseWorkout
|
||||||
let data = try! JSONEncoder().encode(nextExerciseAction)
|
let data = try! JSONEncoder().encode(nextExerciseAction)
|
||||||
send(data)
|
DataSender.send(data)
|
||||||
isPaused = !isPaused
|
|
||||||
WKInterfaceDevice.current().play(.start)
|
WKInterfaceDevice.current().play(.start)
|
||||||
|
WatchWorkout.shared.togglePaused()
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataToAction(messageData: Data) {
|
func dataToAction(messageData: Data) {
|
||||||
@@ -94,27 +72,19 @@ class WatchMainViewModel: NSObject, ObservableObject {
|
|||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
switch model {
|
switch model {
|
||||||
case .inExercise(let newWatchPackageModel):
|
case .inExercise(let newWatchPackageModel):
|
||||||
if !self.isInWorkout {
|
WatchWorkout.shared.startWorkout()
|
||||||
self.startWorkout()
|
|
||||||
}
|
|
||||||
if self.watchPackageModel.currentExerciseID != newWatchPackageModel.currentExerciseID {
|
if self.watchPackageModel.currentExerciseID != newWatchPackageModel.currentExerciseID {
|
||||||
self.isPaused = false
|
|
||||||
WKInterfaceDevice.current().play(.start)
|
WKInterfaceDevice.current().play(.start)
|
||||||
}
|
}
|
||||||
self.watchPackageModel = newWatchPackageModel
|
self.watchPackageModel = newWatchPackageModel
|
||||||
case .reset:
|
case .reset:
|
||||||
self.isInWorkout = false
|
|
||||||
self.watchPackageModel = WatchMainViewModel.defualtPackageModle
|
self.watchPackageModel = WatchMainViewModel.defualtPackageModle
|
||||||
self.stopWorkout(sendDetails: false)
|
WatchWorkout.shared.stopWorkout(sendDetails: false)
|
||||||
case .endWorkout:
|
case .endWorkout:
|
||||||
self.isInWorkout = false
|
|
||||||
self.watchPackageModel = WatchMainViewModel.defualtPackageModle
|
self.watchPackageModel = WatchMainViewModel.defualtPackageModle
|
||||||
self.stopWorkout(sendDetails: true)
|
WatchWorkout.shared.stopWorkout(sendDetails: true)
|
||||||
case .startWorkout:
|
case .startWorkout:
|
||||||
if self.isInWorkout {
|
WatchWorkout.shared.startWorkout()
|
||||||
self.stopWorkout(sendDetails: false)
|
|
||||||
}
|
|
||||||
self.startWorkout()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +1,85 @@
|
|||||||
//
|
//
|
||||||
// WatchMainViewModel+WorkoutActions.swift
|
// WatchWorkout.swift
|
||||||
// Werkout_watch Watch App
|
// Werkout_watch Watch App
|
||||||
//
|
//
|
||||||
// Created by Trey Tartt on 6/19/24.
|
// Created by Trey Tartt on 7/1/24.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import WatchConnectivity
|
|
||||||
import SwiftUI
|
|
||||||
import HealthKit
|
import HealthKit
|
||||||
|
|
||||||
extension WatchMainViewModel {
|
class WatchWorkout: NSObject, ObservableObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {
|
||||||
func initWorkout() -> Bool {
|
static let shared = WatchWorkout()
|
||||||
let configuration = HKWorkoutConfiguration()
|
|
||||||
configuration.activityType = .functionalStrengthTraining
|
@Published var heartValue: Int?
|
||||||
configuration.locationType = .indoor
|
|
||||||
|
let healthStore = HKHealthStore()
|
||||||
|
var hkWorkoutSession: HKWorkoutSession
|
||||||
|
var hkBuilder: HKLiveWorkoutBuilder
|
||||||
|
var heartRates = [Int]()
|
||||||
|
@Published var isInWorkout = false
|
||||||
|
@Published var isPaused = false
|
||||||
|
|
||||||
|
private override init() {
|
||||||
do {
|
do {
|
||||||
|
let configuration = HKWorkoutConfiguration()
|
||||||
|
configuration.activityType = .functionalStrengthTraining
|
||||||
|
configuration.locationType = .indoor
|
||||||
|
|
||||||
hkWorkoutSession = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
|
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 {
|
} 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() {
|
func startWorkout() {
|
||||||
// Initialize our workout
|
if isInWorkout { return }
|
||||||
if initWorkout() {
|
// Start the workout session and begin data collection
|
||||||
|
hkWorkoutSession.startActivity(with: Date())
|
||||||
guard let hkWorkoutSession = hkWorkoutSession, let hkBuilder = hkBuilder else {
|
hkBuilder.beginCollection(withStart: Date()) { (succ, error) in
|
||||||
return
|
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) {
|
func stopWorkout(sendDetails: Bool) {
|
||||||
guard let hkWorkoutSession = hkWorkoutSession, let hkBuilder = hkBuilder else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hkWorkoutSession.end()
|
hkWorkoutSession.end()
|
||||||
|
self.heartRates.removeAll()
|
||||||
|
self.isInWorkout = false
|
||||||
|
|
||||||
hkBuilder.endCollection(withEnd: Date()) { (success, error) in
|
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() {
|
DispatchQueue.main.async() {
|
||||||
self.hkWorkoutSession = nil
|
let watchFinishWorkoutModel = WatchFinishWorkoutModel(healthKitUUID: workout.uuid)
|
||||||
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 data = try! JSONEncoder().encode(watchFinishWorkoutModel)
|
let data = try! JSONEncoder().encode(watchFinishWorkoutModel)
|
||||||
let watchAction = WatchActions.workoutComplete(data)
|
let watchAction = WatchActions.workoutComplete(data)
|
||||||
let watchActionData = try! JSONEncoder().encode(watchAction)
|
let watchActionData = try! JSONEncoder().encode(watchAction)
|
||||||
|
DataSender.send(watchActionData)
|
||||||
if sendDetails {
|
|
||||||
self.send(watchActionData)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func togglePaused() {
|
||||||
extension WatchMainViewModel: HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {
|
self.isPaused.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
|
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
|
||||||
print("[workoutSession] Changed State: \(toState.rawValue)")
|
print("[workoutSession] Changed State: \(toState.rawValue)")
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,8 @@ import SwiftUI
|
|||||||
|
|
||||||
@main
|
@main
|
||||||
struct Werkout_watch_Watch_AppApp: App {
|
struct Werkout_watch_Watch_AppApp: App {
|
||||||
|
@WKApplicationDelegateAdaptor(WatchDelegate.self) var delegate: WatchDelegate
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ContentView()
|
||||||
|
|||||||
Reference in New Issue
Block a user