WIP
This commit is contained in:
@@ -8,8 +8,9 @@
|
||||
import Foundation
|
||||
import WatchConnectivity
|
||||
|
||||
enum WatchActions: String, Codable {
|
||||
enum WatchActions: Codable {
|
||||
case nextExercise
|
||||
case workoutComplete(Data)
|
||||
}
|
||||
|
||||
class BridgeModule: NSObject, ObservableObject {
|
||||
@@ -26,11 +27,17 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
var currentExerciseIdx: Int = -1
|
||||
|
||||
var workoutStartDate: Date?
|
||||
|
||||
// workoutEndDate ties into WatchPackageModel.workoutEndDate which
|
||||
// tells the watch app to stop the workout
|
||||
var workoutEndDate: Date?
|
||||
@Published var currentWorkoutRunTimeInSeconds: Int = -1
|
||||
private var currentWorkoutRunTimer: Timer?
|
||||
|
||||
@Published var isInWorkout = false
|
||||
var completedWorkoutFromWatch: (() -> Void)?
|
||||
var totalCaloire: Float?
|
||||
var heartRates: [Int]?
|
||||
|
||||
func start(workout: Workout, atExerciseIndex: Int = 0) {
|
||||
self.currentWorkout = workout
|
||||
@@ -64,15 +71,14 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
|
||||
currentExercise = 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
|
||||
workoutStartDate = nil
|
||||
workoutEndDate = nil
|
||||
|
||||
let watchModel = WatchPackageModel(currentExerciseName: "", currentTimeLeft: -100, workoutStartDate: Date())
|
||||
let data = try! JSONEncoder().encode(watchModel)
|
||||
send(data)
|
||||
}
|
||||
|
||||
private func startWorkoutTimer() {
|
||||
@@ -140,11 +146,22 @@ class BridgeModule: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
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) {
|
||||
if let model = try? JSONDecoder().decode(WatchActions.self, from: messageData) {
|
||||
switch model {
|
||||
case .nextExercise:
|
||||
nextExercise()
|
||||
case .workoutComplete(let data):
|
||||
let model = try! JSONDecoder().decode(WatchFinishWorkoutModel.self, from: data)
|
||||
totalCaloire = Float(model.totalBurnedEnergery)
|
||||
heartRates = model.allHeartRates
|
||||
completedWorkoutFromWatch?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
completed workout view
|
||||
add notes and slider for difficulty
|
||||
-completed workout view
|
||||
- add notes and slider for difficulty
|
||||
|
||||
-apple watch
|
||||
|
||||
account view
|
||||
workout history view
|
||||
apple watch
|
||||
calorie upload
|
||||
edit weights on workouts
|
||||
|
||||
video view on iphone during workout
|
||||
|
||||
edit weights on workouts
|
||||
|
||||
@@ -19,37 +19,18 @@ struct CompletedWorkoutView: View {
|
||||
|
||||
var body: 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)
|
||||
|
||||
}
|
||||
topViews()
|
||||
|
||||
Divider()
|
||||
calsBurned()
|
||||
|
||||
Text("how hard was this shit")
|
||||
|
||||
HStack {
|
||||
Text("easy")
|
||||
Spacer()
|
||||
Text("Death")
|
||||
}
|
||||
|
||||
Slider(value: $difficulty, in: 0...5, step: 1)
|
||||
heartRates()
|
||||
|
||||
rateWorkout()
|
||||
|
||||
Divider()
|
||||
|
||||
TextField("Notes", text: $notes)
|
||||
|
||||
// Divider()
|
||||
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Upload", action: {
|
||||
@@ -66,6 +47,57 @@ struct CompletedWorkoutView: View {
|
||||
.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]) {
|
||||
var _postBody = postBody
|
||||
_postBody["difficulty"] = difficulty
|
||||
|
||||
@@ -34,10 +34,7 @@ struct WorkoutDetailView: View {
|
||||
ExerciseListView(workout: workout)
|
||||
ActionsView(completedWorkout: {
|
||||
bridgeModule.workoutEndDate = Date()
|
||||
if let workoutData = createWorkoutData() {
|
||||
presentedSheet = .completedWorkout(workoutData)
|
||||
bridgeModule.resetCurrentWorkout()
|
||||
}
|
||||
bridgeModule.sendWorkoutCompleteToWatch()
|
||||
}, workout: workout)
|
||||
.frame(height: 44)
|
||||
|
||||
@@ -55,6 +52,14 @@ struct WorkoutDetailView: View {
|
||||
.interactiveDismissDisabled()
|
||||
}
|
||||
}
|
||||
.onAppear{
|
||||
bridgeModule.completedWorkoutFromWatch = {
|
||||
if let workoutData = createWorkoutData() {
|
||||
presentedSheet = .completedWorkout(workoutData)
|
||||
bridgeModule.resetCurrentWorkout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createWorkoutData() -> [String:Any]? {
|
||||
@@ -68,7 +73,9 @@ struct WorkoutDetailView: View {
|
||||
"workout_start_time": startTime,
|
||||
"workout_end_time": endTime,
|
||||
"workout": workoutid,
|
||||
"total_time": bridgeModule.currentWorkoutRunTimeInSeconds
|
||||
"total_time": bridgeModule.currentWorkoutRunTimeInSeconds,
|
||||
"total_calories": bridgeModule.totalCaloire ?? -1,
|
||||
"heart_rates": bridgeModule.heartRates ?? [Int]()
|
||||
] as [String : Any]
|
||||
|
||||
return postBody
|
||||
|
||||
@@ -13,3 +13,8 @@ struct WatchPackageModel: Codable {
|
||||
var workoutStartDate: Date
|
||||
var workoutEndDate: Date?
|
||||
}
|
||||
|
||||
struct WatchFinishWorkoutModel: Codable {
|
||||
var totalBurnedEnergery: Double
|
||||
var allHeartRates: [Int]
|
||||
}
|
||||
|
||||
@@ -16,12 +16,9 @@ class WatchMainViewModel: NSObject, ObservableObject {
|
||||
@Published var heartValue: Int?
|
||||
|
||||
let healthStore = HKHealthStore()
|
||||
var hkWorkoutSession: HKWorkoutSession? {
|
||||
didSet {
|
||||
print("here")
|
||||
}
|
||||
}
|
||||
var hkWorkoutSession: HKWorkoutSession?
|
||||
var hkBuilder: HKLiveWorkoutBuilder?
|
||||
var heartRates = [Int]()
|
||||
|
||||
override init() {
|
||||
session = WCSession.default
|
||||
@@ -71,6 +68,10 @@ extension WatchMainViewModel: WCSessionDelegate {
|
||||
func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
|
||||
if let model = try? JSONDecoder().decode(WatchPackageModel.self, from: messageData) {
|
||||
DispatchQueue.main.async {
|
||||
if model.currentTimeLeft == -100 {
|
||||
self.watchPackageModel = nil
|
||||
return
|
||||
}
|
||||
if self.watchPackageModel?.workoutEndDate != nil {
|
||||
self.watchPackageModel = nil
|
||||
self.stopWorkout()
|
||||
@@ -157,6 +158,14 @@ extension WatchMainViewModel: HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDele
|
||||
DispatchQueue.main.async() {
|
||||
self.hkWorkoutSession = 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 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:
|
||||
|
||||
Reference in New Issue
Block a user