This commit is contained in:
Trey t
2023-06-24 00:01:32 -05:00
parent 36400d1f79
commit 01915752b6
6 changed files with 120 additions and 46 deletions

View File

@@ -8,8 +8,9 @@
import Foundation import Foundation
import WatchConnectivity import WatchConnectivity
enum WatchActions: String, Codable { enum WatchActions: Codable {
case nextExercise case nextExercise
case workoutComplete(Data)
} }
class BridgeModule: NSObject, ObservableObject { class BridgeModule: NSObject, ObservableObject {
@@ -26,11 +27,17 @@ class BridgeModule: NSObject, ObservableObject {
var currentExerciseIdx: Int = -1 var currentExerciseIdx: Int = -1
var workoutStartDate: Date? var workoutStartDate: Date?
// workoutEndDate ties into WatchPackageModel.workoutEndDate which
// tells the watch app to stop the workout
var workoutEndDate: Date? var workoutEndDate: Date?
@Published var currentWorkoutRunTimeInSeconds: Int = -1 @Published var currentWorkoutRunTimeInSeconds: Int = -1
private var currentWorkoutRunTimer: Timer? private var currentWorkoutRunTimer: Timer?
@Published var isInWorkout = false @Published var isInWorkout = false
var completedWorkoutFromWatch: (() -> Void)?
var totalCaloire: Float?
var heartRates: [Int]?
func start(workout: Workout, atExerciseIndex: Int = 0) { func start(workout: Workout, atExerciseIndex: Int = 0) {
self.currentWorkout = workout self.currentWorkout = workout
@@ -65,14 +72,13 @@ class BridgeModule: NSObject, ObservableObject {
currentExercise = nil currentExercise = nil
currentWorkout = nil currentWorkout = nil
if isInWorkout {
let watchModel = WatchPackageModel(currentExerciseName: currentExercise?.exercise.name ?? "-", currentTimeLeft: timeLeft, workoutStartDate: workoutStartDate ?? Date(), workoutEndDate: Date())
let data = try! JSONEncoder().encode(watchModel)
send(data)
}
isInWorkout = false isInWorkout = false
workoutStartDate = nil workoutStartDate = nil
workoutEndDate = nil workoutEndDate = nil
let watchModel = WatchPackageModel(currentExerciseName: "", currentTimeLeft: -100, workoutStartDate: Date())
let data = try! JSONEncoder().encode(watchModel)
send(data)
} }
private func startWorkoutTimer() { private func startWorkoutTimer() {
@@ -140,11 +146,22 @@ class BridgeModule: NSObject, ObservableObject {
} }
extension BridgeModule: WCSessionDelegate { extension BridgeModule: WCSessionDelegate {
func sendWorkoutCompleteToWatch() {
let watchModel = WatchPackageModel(currentExerciseName: currentExercise?.exercise.name ?? "-", currentTimeLeft: timeLeft, workoutStartDate: workoutStartDate ?? Date(), workoutEndDate: Date())
let data = try! JSONEncoder().encode(watchModel)
send(data)
}
func session(_ session: WCSession, didReceiveMessageData messageData: Data) { func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
if let model = try? JSONDecoder().decode(WatchActions.self, from: messageData) { if let model = try? JSONDecoder().decode(WatchActions.self, from: messageData) {
switch model { switch model {
case .nextExercise: case .nextExercise:
nextExercise() nextExercise()
case .workoutComplete(let data):
let model = try! JSONDecoder().decode(WatchFinishWorkoutModel.self, from: data)
totalCaloire = Float(model.totalBurnedEnergery)
heartRates = model.allHeartRates
completedWorkoutFromWatch?()
} }
} }
} }

View File

@@ -1,9 +1,12 @@
completed workout view -completed workout view
add notes and slider for difficulty - add notes and slider for difficulty
-apple watch
account view account view
workout history view workout history view
apple watch
calorie upload calorie upload
edit weights on workouts
video view on iphone during workout video view on iphone during workout
edit weights on workouts

View File

@@ -19,37 +19,18 @@ struct CompletedWorkoutView: View {
var body: some View { var body: some View {
VStack { VStack {
Text(workout.name) topViews()
.frame(maxWidth: .infinity, alignment: .leading)
.font(.title3)
.padding(.top
)
if let desc = workout.description {
Text(desc)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.body)
.padding(.top)
} calsBurned()
Divider() heartRates()
Text("how hard was this shit") rateWorkout()
HStack {
Text("easy")
Spacer()
Text("Death")
}
Slider(value: $difficulty, in: 0...5, step: 1)
Divider() Divider()
TextField("Notes", text: $notes) TextField("Notes", text: $notes)
// Divider()
Spacer() Spacer()
Button("Upload", action: { Button("Upload", action: {
@@ -66,6 +47,57 @@ struct CompletedWorkoutView: View {
.padding([.leading, .trailing]) .padding([.leading, .trailing])
} }
func topViews() -> some View {
VStack {
Text(workout.name)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.title3)
.padding(.top
)
if let desc = workout.description {
Text(desc)
.frame(maxWidth: .infinity, alignment: .leading)
.font(.body)
.padding(.top)
}
}
}
func calsBurned() -> some View {
VStack {
Divider()
Text("calroies burned")
Text("\(postData["total_calories"] as! Float)")
}
}
func rateWorkout() -> some View {
VStack {
Divider()
Text("how hard was this shit")
HStack {
Text("easy")
Spacer()
Text("Death")
}
Slider(value: $difficulty, in: 0...5, step: 1)
}
}
func heartRates() -> some View {
VStack {
Divider()
if let heartRates = postData["heart_rates"] as? [Int] {
let avg = heartRates.reduce(0, +)/heartRates.count
Text("Avg heart rate: \(avg)")
}
}
}
func upload(postBody: [String: Any]) { func upload(postBody: [String: Any]) {
var _postBody = postBody var _postBody = postBody
_postBody["difficulty"] = difficulty _postBody["difficulty"] = difficulty

View File

@@ -34,10 +34,7 @@ struct WorkoutDetailView: View {
ExerciseListView(workout: workout) ExerciseListView(workout: workout)
ActionsView(completedWorkout: { ActionsView(completedWorkout: {
bridgeModule.workoutEndDate = Date() bridgeModule.workoutEndDate = Date()
if let workoutData = createWorkoutData() { bridgeModule.sendWorkoutCompleteToWatch()
presentedSheet = .completedWorkout(workoutData)
bridgeModule.resetCurrentWorkout()
}
}, workout: workout) }, workout: workout)
.frame(height: 44) .frame(height: 44)
@@ -55,6 +52,14 @@ struct WorkoutDetailView: View {
.interactiveDismissDisabled() .interactiveDismissDisabled()
} }
} }
.onAppear{
bridgeModule.completedWorkoutFromWatch = {
if let workoutData = createWorkoutData() {
presentedSheet = .completedWorkout(workoutData)
bridgeModule.resetCurrentWorkout()
}
}
}
} }
func createWorkoutData() -> [String:Any]? { func createWorkoutData() -> [String:Any]? {
@@ -68,7 +73,9 @@ struct WorkoutDetailView: View {
"workout_start_time": startTime, "workout_start_time": startTime,
"workout_end_time": endTime, "workout_end_time": endTime,
"workout": workoutid, "workout": workoutid,
"total_time": bridgeModule.currentWorkoutRunTimeInSeconds "total_time": bridgeModule.currentWorkoutRunTimeInSeconds,
"total_calories": bridgeModule.totalCaloire ?? -1,
"heart_rates": bridgeModule.heartRates ?? [Int]()
] as [String : Any] ] as [String : Any]
return postBody return postBody

View File

@@ -13,3 +13,8 @@ struct WatchPackageModel: Codable {
var workoutStartDate: Date var workoutStartDate: Date
var workoutEndDate: Date? var workoutEndDate: Date?
} }
struct WatchFinishWorkoutModel: Codable {
var totalBurnedEnergery: Double
var allHeartRates: [Int]
}

View File

@@ -16,12 +16,9 @@ class WatchMainViewModel: NSObject, ObservableObject {
@Published var heartValue: Int? @Published var heartValue: Int?
let healthStore = HKHealthStore() let healthStore = HKHealthStore()
var hkWorkoutSession: HKWorkoutSession? { var hkWorkoutSession: HKWorkoutSession?
didSet {
print("here")
}
}
var hkBuilder: HKLiveWorkoutBuilder? var hkBuilder: HKLiveWorkoutBuilder?
var heartRates = [Int]()
override init() { override init() {
session = WCSession.default session = WCSession.default
@@ -71,6 +68,10 @@ extension WatchMainViewModel: WCSessionDelegate {
func session(_ session: WCSession, didReceiveMessageData messageData: Data) { func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
if let model = try? JSONDecoder().decode(WatchPackageModel.self, from: messageData) { if let model = try? JSONDecoder().decode(WatchPackageModel.self, from: messageData) {
DispatchQueue.main.async { DispatchQueue.main.async {
if model.currentTimeLeft == -100 {
self.watchPackageModel = nil
return
}
if self.watchPackageModel?.workoutEndDate != nil { if self.watchPackageModel?.workoutEndDate != nil {
self.watchPackageModel = nil self.watchPackageModel = nil
self.stopWorkout() self.stopWorkout()
@@ -157,6 +158,14 @@ extension WatchMainViewModel: HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDele
DispatchQueue.main.async() { DispatchQueue.main.async() {
self.hkWorkoutSession = nil self.hkWorkoutSession = nil
self.hkBuilder = nil self.hkBuilder = nil
let totalEnergy = workout?.totalEnergyBurned?.doubleValue(for: .kilocalorie()) ?? -1
let watchFinishWorkoutModel = WatchFinishWorkoutModel(totalBurnedEnergery: totalEnergy, allHeartRates: self.heartRates)
let data = try! JSONEncoder().encode(watchFinishWorkoutModel)
let watchAction = WatchActions.workoutComplete(data)
let watchActionData = try! JSONEncoder().encode(watchAction)
self.send(watchActionData)
self.heartRates.removeAll()
} }
} }
} }
@@ -182,6 +191,7 @@ extension WatchMainViewModel: HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDele
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute()) let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
let value = statistics!.mostRecentQuantity()?.doubleValue(for: heartRateUnit) let value = statistics!.mostRecentQuantity()?.doubleValue(for: heartRateUnit)
self.heartValue = Int(Double(round(1 * value!) / 1)) 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))") print("[workoutBuilder] Heart Rate: \(String(describing: self.heartValue))")
} }
default: default: