misc watch stuff including taps, sounds, maybe working

This commit is contained in:
Trey t
2024-06-21 14:34:23 -05:00
parent 7ce996e451
commit cee84d7776
9 changed files with 61 additions and 36 deletions

View File

@@ -6,12 +6,16 @@
// //
import AVKit import AVKit
import AVFoundation
class AudioEngine { class AudioEngine {
// var audioPlayer: AVAudioPlayer? static let shared = AudioEngine()
// var avPlayer: AVPlayer? private init() { }
static func playRemoteAudio(fromURL url: URL) { var audioPlayer: AVAudioPlayer?
var avPlayer: AVPlayer?
func playRemoteAudio(fromURL url: URL) {
#if os(iOS) #if os(iOS)
let playerItem = AVPlayerItem(url: url) let playerItem = AVPlayerItem(url: url)
do { do {
@@ -20,15 +24,15 @@ class AudioEngine {
options: [.mixWithOthers]) options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true) try AVAudioSession.sharedInstance().setActive(true)
let avPlayer = AVPlayer(playerItem: playerItem) avPlayer = AVPlayer(playerItem: playerItem)
avPlayer.play() avPlayer?.play()
} catch { } catch {
print("ERROR") print("ERROR")
} }
#endif #endif
} }
static func playBeep() { func playBeep() {
#if os(iOS) #if os(iOS)
if let path = Bundle.main.path(forResource: "short_beep", ofType: "m4a") { if let path = Bundle.main.path(forResource: "short_beep", ofType: "m4a") {
do { do {
@@ -37,8 +41,8 @@ class AudioEngine {
options: [.mixWithOthers]) options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true) try AVAudioSession.sharedInstance().setActive(true)
let audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path)) audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
audioPlayer.play() audioPlayer?.play()
} catch { } catch {
print("ERROR") print("ERROR")
} }
@@ -46,7 +50,7 @@ class AudioEngine {
#endif #endif
} }
static func playFinished() { func playFinished() {
#if os(iOS) #if os(iOS)
if let path = Bundle.main.path(forResource: "long_beep", ofType: "m4a") { if let path = Bundle.main.path(forResource: "long_beep", ofType: "m4a") {
do { do {
@@ -55,8 +59,8 @@ class AudioEngine {
options: [.mixWithOthers]) options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true) try AVAudioSession.sharedInstance().setActive(true)
let audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path)) audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
audioPlayer.play() audioPlayer?.play()
} catch { } catch {
print("ERROR") print("ERROR")
} }

View File

@@ -42,11 +42,11 @@ extension BridgeModule {
switch audioQueue.audioType { switch audioQueue.audioType {
case .shortBeep: case .shortBeep:
AudioEngine.playBeep() AudioEngine.shared.playBeep()
case .finishBeep: case .finishBeep:
AudioEngine.playFinished() AudioEngine.shared.playFinished()
case .remoteURL(let url): case .remoteURL(let url):
AudioEngine.playRemoteAudio(fromURL: url) AudioEngine.shared.playRemoteAudio(fromURL: url)
} }
} }
} }

View File

@@ -14,28 +14,22 @@ extension BridgeModule: WCSessionDelegate {
func sendResetToWatch() { func sendResetToWatch() {
let watchModel = PhoneToWatchActions.reset let watchModel = PhoneToWatchActions.reset
let data = try! JSONEncoder().encode(watchModel) let data = try! JSONEncoder().encode(watchModel)
send(data)
// user transferUserInfo b/c its guranteed to reach // self.session.transferUserInfo(["package": data])
// and end the workout
self.session.transferUserInfo(["package": data])
} }
func sendStartWorkoutToWatch() { func sendStartWorkoutToWatch() {
let model = PhoneToWatchActions.startWorkout let model = PhoneToWatchActions.startWorkout
let data = try! JSONEncoder().encode(model) let data = try! JSONEncoder().encode(model)
send(data)
// user transferUserInfo b/c its guranteed to reach // self.session.transferUserInfo(["package": data])
// and start the workout
self.session.transferUserInfo(["package": data])
} }
func sendWorkoutCompleteToWatch() { func sendWorkoutCompleteToWatch() {
let model = PhoneToWatchActions.endWorkout let model = PhoneToWatchActions.endWorkout
let data = try! JSONEncoder().encode(model) let data = try! JSONEncoder().encode(model)
send(data)
// user transferUserInfo b/c its guranteed to reach // self.session.transferUserInfo(["package": data])
// and end the workout
self.session.transferUserInfo(["package": data])
} }
func sendCurrentExerciseToWatch() { func sendCurrentExerciseToWatch() {
@@ -43,6 +37,7 @@ extension BridgeModule: WCSessionDelegate {
let duration = currentExercise.duration , let duration = currentExercise.duration ,
duration > 0 { duration > 0 {
let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name, let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name,
currentExerciseID: currentExercise.id ?? -1,
currentTimeLeft: currentExerciseTimeLeft, currentTimeLeft: currentExerciseTimeLeft,
workoutStartDate: workoutStartDate ?? Date()) workoutStartDate: workoutStartDate ?? Date())
let model = PhoneToWatchActions.inExercise(watchModel) let model = PhoneToWatchActions.inExercise(watchModel)
@@ -55,7 +50,7 @@ extension BridgeModule: WCSessionDelegate {
// if not a timer we need to set the watch display with number of reps // if not a timer we need to set the watch display with number of reps
// if timer it will set when timer updates // if timer it will set when timer updates
let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name, currentTimeLeft: reps, workoutStartDate: self.workoutStartDate ?? Date()) let watchModel = WatchPackageModel(currentExerciseName: currentExercise.exercise.name, currentExerciseID: currentExercise.id ?? -1, currentTimeLeft: reps, workoutStartDate: self.workoutStartDate ?? Date())
let model = PhoneToWatchActions.inExercise(watchModel) let model = PhoneToWatchActions.inExercise(watchModel)
let data = try! JSONEncoder().encode(model) let data = try! JSONEncoder().encode(model)
self.send(data) self.send(data)
@@ -68,7 +63,7 @@ extension BridgeModule: WCSessionDelegate {
switch model { switch model {
case .nextExercise: case .nextExercise:
nextExercise() nextExercise()
AudioEngine.playFinished() AudioEngine.shared.playFinished()
case .workoutComplete(let data): case .workoutComplete(let data):
DispatchQueue.main.async { DispatchQueue.main.async {
let model = try! JSONDecoder().decode(WatchFinishWorkoutModel.self, from: data) let model = try! JSONDecoder().decode(WatchFinishWorkoutModel.self, from: data)

View File

@@ -77,8 +77,6 @@ extension BridgeModule {
currentWorkoutRunTimer = nil currentWorkoutRunTimer = nil
isPaused = false isPaused = false
sendStartWorkoutToWatch()
if let superetExercise = currentExerciseInfo.currentExercise { if let superetExercise = currentExerciseInfo.currentExercise {
updateCurrent(exercise: superetExercise) updateCurrent(exercise: superetExercise)
startWorkoutTimer() startWorkoutTimer()
@@ -88,6 +86,7 @@ extension BridgeModule {
if WCSession.isSupported() { if WCSession.isSupported() {
session.delegate = self session.delegate = self
session.activate() session.activate()
sendStartWorkoutToWatch()
} }
} }
} }

View File

@@ -9,6 +9,7 @@ import Foundation
struct WatchPackageModel: Codable { struct WatchPackageModel: Codable {
var currentExerciseName: String var currentExerciseName: String
var currentExerciseID: Int
var currentTimeLeft: Int var currentTimeLeft: Int
var workoutStartDate: Date var workoutStartDate: Date
var workoutEndDate: Date? var workoutEndDate: Date?

View File

@@ -57,6 +57,7 @@ struct ActionsView: View {
.foregroundColor(.white) .foregroundColor(.white)
} else { } else {
Button(action: { Button(action: {
AudioEngine.shared.playFinished()
nextExercise() nextExercise()
}, label: { }, label: {
Image(systemName: "arrow.forward") Image(systemName: "arrow.forward")
@@ -68,6 +69,7 @@ struct ActionsView: View {
.foregroundColor(.white) .foregroundColor(.white)
Button(action: { Button(action: {
AudioEngine.shared.playFinished()
bridgeModule.pauseWorkout() bridgeModule.pauseWorkout()
}, label: { }, label: {
bridgeModule.isPaused ? bridgeModule.isPaused ?
@@ -84,6 +86,7 @@ struct ActionsView: View {
.foregroundColor(.white) .foregroundColor(.white)
Button(action: { Button(action: {
AudioEngine.shared.playFinished()
completedWorkout?() completedWorkout?()
}, label: { }, label: {
Image(systemName: "checkmark") Image(systemName: "checkmark")

View File

@@ -44,9 +44,15 @@ struct WatchControlView: View {
Button(action: { Button(action: {
vm.pauseWorkout() vm.pauseWorkout()
}, label: { }, label: {
Image(systemName: "pause") if vm.isPaused {
.font(.title) Image(systemName: "play")
.frame(maxWidth: .infinity, maxHeight: .infinity) .font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
Image(systemName: "pause")
.font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}) })
.buttonStyle(BorderedButtonStyle(tint: .blue)) .buttonStyle(BorderedButtonStyle(tint: .blue))

View File

@@ -51,6 +51,8 @@ extension WatchMainViewModel {
} }
} }
isInWorkout = true isInWorkout = true
isPaused = false
WKInterfaceDevice.current().play(.start)
} else { } else {
print("did not init workout") print("did not init workout")
} }
@@ -69,6 +71,7 @@ extension WatchMainViewModel {
self.hkBuilder = nil self.hkBuilder = nil
self.heartRates.removeAll() self.heartRates.removeAll()
self.isInWorkout = false self.isInWorkout = false
self.isPaused = false
guard let id = workout?.uuid else { guard let id = workout?.uuid else {
return return

View File

@@ -20,13 +20,14 @@ class WatchMainViewModel: NSObject, ObservableObject {
@Published var heartValue: Int? @Published var heartValue: Int?
static var defualtPackageModle: WatchPackageModel { static var defualtPackageModle: WatchPackageModel {
WatchPackageModel(currentExerciseName: "", currentTimeLeft: -1, workoutStartDate: Date()) WatchPackageModel(currentExerciseName: "", currentExerciseID: -1, currentTimeLeft: -1, workoutStartDate: Date())
} }
let healthStore = HKHealthStore() let healthStore = HKHealthStore()
var hkWorkoutSession: HKWorkoutSession? var hkWorkoutSession: HKWorkoutSession?
var hkBuilder: HKLiveWorkoutBuilder? var hkBuilder: HKLiveWorkoutBuilder?
var heartRates = [Int]() var heartRates = [Int]()
@Published var isPaused = false
override init() { override init() {
session = WCSession.default session = WCSession.default
@@ -56,38 +57,51 @@ class WatchMainViewModel: NSObject, ObservableObject {
let nextExerciseAction = WatchActions.nextExercise let nextExerciseAction = WatchActions.nextExercise
let data = try! JSONEncoder().encode(nextExerciseAction) let data = try! JSONEncoder().encode(nextExerciseAction)
send(data) send(data)
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) send(data)
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) send(data)
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) send(data)
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) send(data)
isPaused = !isPaused
WKInterfaceDevice.current().play(.start)
} }
func dataToAction(messageData: Data) { func dataToAction(messageData: Data) {
if let model = try? JSONDecoder().decode(PhoneToWatchActions.self, from: messageData) { if let model = try? JSONDecoder().decode(PhoneToWatchActions.self, from: messageData) {
DispatchQueue.main.async { DispatchQueue.main.async {
switch model { switch model {
case .inExercise(let data): case .inExercise(let newWatchPackageModel):
self.watchPackageModel = data if !self.isInWorkout {
self.startWorkout()
}
if self.watchPackageModel.currentExerciseID != newWatchPackageModel.currentExerciseID {
self.isPaused = false
WKInterfaceDevice.current().play(.start)
}
self.watchPackageModel = newWatchPackageModel
case .reset: case .reset:
self.isInWorkout = false self.isInWorkout = false
self.watchPackageModel = WatchMainViewModel.defualtPackageModle self.watchPackageModel = WatchMainViewModel.defualtPackageModle