|
|
@@ -8,7 +8,7 @@ import WatchConnectivity
|
|
|
// MARK: - Properties
|
|
|
|
|
|
/// The WatchConnectivity session instance used for communication
|
|
|
- private var session: WCSession?
|
|
|
+ var session: WCSession?
|
|
|
/// Indicates if the paired iPhone is currently reachable
|
|
|
var isReachable = false
|
|
|
|
|
|
@@ -95,168 +95,6 @@ import WatchConnectivity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // MARK: - Send Data to Phone
|
|
|
-
|
|
|
- /// Sends a bolus insulin request to the paired iPhone
|
|
|
- /// - Parameters:
|
|
|
- /// - amount: The insulin amount to be delivered
|
|
|
- func sendBolusRequest(_ amount: Decimal) {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
- isBolusCanceled = false // Reset canceled state when starting new bolus
|
|
|
- activeBolusAmount = Double(truncating: amount as NSNumber) // Set active bolus amount
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "bolus": amount
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("Error sending bolus request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- /// Sends a carbohydrate entry request to the paired iPhone
|
|
|
- /// - Parameters:
|
|
|
- /// - amount: The amount of carbs in grams
|
|
|
- /// - date: The timestamp for the carb entry (defaults to current time)
|
|
|
- func sendCarbsRequest(_ amount: Int, _ date: Date = Date()) {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "carbs": amount,
|
|
|
- "date": date.timeIntervalSince1970
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("Error sending carbs request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- /// Sends a meal and bolus insulin combo request to the paired iPhone
|
|
|
- /// - Parameters:
|
|
|
- /// - amount: The insulin amount to be delivered
|
|
|
- /// - isExternal: Indicates if the bolus is from an external source
|
|
|
- func sendMealBolusComboRequest(carbsAmount _: Decimal, bolusAmount: Decimal, _ date: Date = Date()) {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "bolus": bolusAmount,
|
|
|
- "carbs": bolusAmount,
|
|
|
- "date": date.timeIntervalSince1970
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("Error sending meal bolus combo request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- isMealBolusCombo = true
|
|
|
- }
|
|
|
-
|
|
|
- func sendCancelOverrideRequest() {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "cancelOverride": true
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("⌚️ Error sending cancel override request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- func sendActivateOverrideRequest(presetName: String) {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "activateOverride": presetName
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("⌚️ Error sending activate override request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- func sendCancelTempTargetRequest() {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "cancelTempTarget": true
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("⌚️ Error sending cancel temp target request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- func sendActivateTempTargetRequest(presetName: String) {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "activateTempTarget": presetName
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("⌚️ Error sending activate temp target request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- func sendCancelBolusRequest() {
|
|
|
- isBolusCanceled = true
|
|
|
-
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- "cancelBolus": true
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("Error sending cancel bolus request: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- // Reset when cancelled
|
|
|
- bolusProgress = 0
|
|
|
- activeBolusAmount = 0
|
|
|
-
|
|
|
- // Display pending communication animation
|
|
|
- showCommsAnimation = true
|
|
|
- }
|
|
|
-
|
|
|
- func requestBolusRecommendation() {
|
|
|
- guard let session = session, session.isReachable else { return }
|
|
|
-
|
|
|
- let message: [String: Any] = [
|
|
|
- WatchMessageKeys.requestBolusRecommendation: true,
|
|
|
- WatchMessageKeys.carbs: carbsAmount
|
|
|
- ]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("Error requesting bolus recommendation: \(error.localizedDescription)")
|
|
|
- }
|
|
|
-
|
|
|
- if bolusAmount == 0 {
|
|
|
- showBolusCalculationProgress = true
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
// MARK: – Handle Acknowledgement Messages FROM Phone
|
|
|
|
|
|
func handleAcknowledgment(success: Bool, message: String, isFinal: Bool = true) {
|
|
|
@@ -284,146 +122,6 @@ import WatchConnectivity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- func requestWatchStateUpdate() {
|
|
|
- guard let session = session, session.activationState == .activated else {
|
|
|
- print("⌚️ Session not activated, activating...")
|
|
|
- session?.activate()
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if session.isReachable {
|
|
|
- print("⌚️ Request an update for watch state from Trio iPhone app...")
|
|
|
-
|
|
|
- let message = [WatchMessageKeys.requestWatchUpdate: WatchMessageKeys.watchState]
|
|
|
-
|
|
|
- session.sendMessage(message, replyHandler: nil) { error in
|
|
|
- print("⌚️ Update request for fresh watch state data: \(error.localizedDescription)")
|
|
|
- }
|
|
|
- } else {
|
|
|
- print("⌚️ Phone not reachable for watch state update")
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private func processRawDataForWatchState(_ message: [String: Any]) {
|
|
|
- if let currentGlucose = message[WatchMessageKeys.currentGlucose] as? String {
|
|
|
- self.currentGlucose = currentGlucose
|
|
|
- }
|
|
|
-
|
|
|
- if let currentGlucoseColorString = message[WatchMessageKeys.currentGlucoseColorString] as? String {
|
|
|
- self.currentGlucoseColorString = currentGlucoseColorString
|
|
|
- }
|
|
|
-
|
|
|
- if let trend = message[WatchMessageKeys.trend] as? String {
|
|
|
- self.trend = trend
|
|
|
- }
|
|
|
-
|
|
|
- if let delta = message[WatchMessageKeys.delta] as? String {
|
|
|
- self.delta = delta
|
|
|
- }
|
|
|
-
|
|
|
- if let iob = message[WatchMessageKeys.iob] as? String {
|
|
|
- self.iob = iob
|
|
|
- }
|
|
|
-
|
|
|
- if let cob = message[WatchMessageKeys.cob] as? String {
|
|
|
- self.cob = cob
|
|
|
- }
|
|
|
-
|
|
|
- if let lastLoopTime = message[WatchMessageKeys.lastLoopTime] as? String {
|
|
|
- self.lastLoopTime = lastLoopTime
|
|
|
- }
|
|
|
-
|
|
|
- if let glucoseData = message[WatchMessageKeys.glucoseValues] as? [[String: Any]] {
|
|
|
- glucoseValues = glucoseData.compactMap { data in
|
|
|
- guard let glucose = data["glucose"] as? Double,
|
|
|
- let timestamp = data["date"] as? TimeInterval,
|
|
|
- let colorString = data["color"] as? String
|
|
|
- else { return nil }
|
|
|
-
|
|
|
- return (
|
|
|
- Date(timeIntervalSince1970: timestamp),
|
|
|
- glucose,
|
|
|
- colorString.toColor() // Convert colorString to Color
|
|
|
- )
|
|
|
- }
|
|
|
- .sorted { $0.date < $1.date }
|
|
|
- }
|
|
|
-
|
|
|
- if let overrideData = message[WatchMessageKeys.overridePresets] as? [[String: Any]] {
|
|
|
- overridePresets = overrideData.compactMap { data in
|
|
|
- guard let name = data["name"] as? String,
|
|
|
- let isEnabled = data["isEnabled"] as? Bool
|
|
|
- else { return nil }
|
|
|
- return OverridePresetWatch(name: name, isEnabled: isEnabled)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let tempTargetData = message[WatchMessageKeys.tempTargetPresets] as? [[String: Any]] {
|
|
|
- tempTargetPresets = tempTargetData.compactMap { data in
|
|
|
- guard let name = data["name"] as? String,
|
|
|
- let isEnabled = data["isEnabled"] as? Bool
|
|
|
- else { return nil }
|
|
|
- return TempTargetPresetWatch(name: name, isEnabled: isEnabled)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let bolusProgress = message[WatchMessageKeys.bolusProgress] as? Double {
|
|
|
- if !isBolusCanceled {
|
|
|
- self.bolusProgress = bolusProgress
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let bolusWasCanceled = message[WatchMessageKeys.bolusCanceled] as? Bool, bolusWasCanceled {
|
|
|
- bolusProgress = 0
|
|
|
- activeBolusAmount = 0
|
|
|
-// return
|
|
|
- }
|
|
|
-
|
|
|
- if let maxBolusValue = message[WatchMessageKeys.maxBolus] {
|
|
|
- print("⌚️ Received maxBolus: \(maxBolusValue) of type \(type(of: maxBolusValue))")
|
|
|
- if let decimalValue = (maxBolusValue as? NSNumber)?.decimalValue {
|
|
|
- maxBolus = decimalValue
|
|
|
- print("⌚️ Converted maxBolus to: \(decimalValue)")
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let maxCarbsValue = message[WatchMessageKeys.maxCarbs] {
|
|
|
- if let decimalValue = (maxCarbsValue as? NSNumber)?.decimalValue {
|
|
|
- maxCarbs = decimalValue
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let maxFatValue = message[WatchMessageKeys.maxFat] {
|
|
|
- if let decimalValue = (maxFatValue as? NSNumber)?.decimalValue {
|
|
|
- maxFat = decimalValue
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let maxProteinValue = message[WatchMessageKeys.maxProtein] {
|
|
|
- if let decimalValue = (maxProteinValue as? NSNumber)?.decimalValue {
|
|
|
- maxProtein = decimalValue
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let maxIOBValue = message[WatchMessageKeys.maxIOB] {
|
|
|
- if let decimalValue = (maxIOBValue as? NSNumber)?.decimalValue {
|
|
|
- maxIOB = decimalValue
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let maxCOBValue = message[WatchMessageKeys.maxCOB] {
|
|
|
- if let decimalValue = (maxCOBValue as? NSNumber)?.decimalValue {
|
|
|
- maxCOB = decimalValue
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if let bolusIncrement = message[WatchMessageKeys.bolusIncrement] {
|
|
|
- if let decimalValue = (bolusIncrement as? NSNumber)?.decimalValue {
|
|
|
- self.bolusIncrement = decimalValue
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
// MARK: - WCSessionDelegate
|
|
|
|
|
|
/// Called when the session has completed activation
|
|
|
@@ -448,8 +146,7 @@ import WatchConnectivity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Handles incoming messages from the paired iPhone
|
|
|
- /// Updates local glucose data, trend, and delta information
|
|
|
+ /// Handles incoming messages from the paired iPhone when Phone is in the foreground
|
|
|
func session(_: WCSession, didReceiveMessage message: [String: Any]) {
|
|
|
print("⌚️ Watch received data: \(message)")
|
|
|
|
|
|
@@ -469,6 +166,7 @@ import WatchConnectivity
|
|
|
self.showSyncingAnimation = false
|
|
|
}
|
|
|
}
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
// Else if the message is an "ack" at the top level
|
|
|
@@ -483,7 +181,37 @@ import WatchConnectivity
|
|
|
self.showSyncingAnimation = false
|
|
|
}
|
|
|
processWatchMessage(message)
|
|
|
+ return
|
|
|
|
|
|
+ // Recommended bolus is also not part of the WatchState message, hence the extra condition here
|
|
|
+ } else if
|
|
|
+ let recommendedBolus = message[WatchMessageKeys.recommendedBolus] as? NSNumber
|
|
|
+ {
|
|
|
+ print("⌚️ Received recommended bolus: \(recommendedBolus)")
|
|
|
+ self.recommendedBolus = recommendedBolus.decimalValue
|
|
|
+ showBolusCalculationProgress = false
|
|
|
+ return
|
|
|
+
|
|
|
+ // Handle bolus progress updates
|
|
|
+ } else if
|
|
|
+ let progress = message[WatchMessageKeys.bolusProgress] as? Double
|
|
|
+ {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if !self.isBolusCanceled {
|
|
|
+ self.bolusProgress = progress
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+
|
|
|
+ // Handle bolus cancellation
|
|
|
+ } else if
|
|
|
+ message[WatchMessageKeys.bolusCanceled] as? Bool == true
|
|
|
+ {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.bolusProgress = 0
|
|
|
+ self.activeBolusAmount = 0
|
|
|
+ }
|
|
|
+ return
|
|
|
} else {
|
|
|
print("⌚️ Faulty data. Skipping...")
|
|
|
DispatchQueue.main.async {
|
|
|
@@ -492,6 +220,7 @@ import WatchConnectivity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Handles incoming messages from the paired iPhone when Phone is in the background
|
|
|
func session(_: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
|
|
|
print("⌚️ Watch received data: \(userInfo)")
|
|
|
|
|
|
@@ -511,6 +240,7 @@ import WatchConnectivity
|
|
|
self.showSyncingAnimation = false
|
|
|
}
|
|
|
}
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
// Else if the message is an "ack" at the top level
|
|
|
@@ -525,7 +255,37 @@ import WatchConnectivity
|
|
|
self.showSyncingAnimation = false
|
|
|
}
|
|
|
processWatchMessage(userInfo)
|
|
|
+ return
|
|
|
+
|
|
|
+ // Recommended bolus is also not part of the WatchState message, hence the extra condition here
|
|
|
+ } else if
|
|
|
+ let recommendedBolus = userInfo[WatchMessageKeys.recommendedBolus] as? NSNumber
|
|
|
+ {
|
|
|
+ print("⌚️ Received recommended bolus: \(recommendedBolus)")
|
|
|
+ self.recommendedBolus = recommendedBolus.decimalValue
|
|
|
+ showBolusCalculationProgress = false
|
|
|
+ return
|
|
|
|
|
|
+ // Handle bolus progress updates
|
|
|
+ } else if
|
|
|
+ let progress = userInfo[WatchMessageKeys.bolusProgress] as? Double
|
|
|
+ {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ if !self.isBolusCanceled {
|
|
|
+ self.bolusProgress = progress
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+
|
|
|
+ // Handle bolus cancellation
|
|
|
+ } else if
|
|
|
+ userInfo[WatchMessageKeys.bolusCanceled] as? Bool == true
|
|
|
+ {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.bolusProgress = 0
|
|
|
+ self.activeBolusAmount = 0
|
|
|
+ }
|
|
|
+ return
|
|
|
} else {
|
|
|
print("⌚️ Faulty data. Skipping...")
|
|
|
DispatchQueue.main.async {
|
|
|
@@ -534,6 +294,65 @@ import WatchConnectivity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// Called when the reachability status of the paired iPhone changes
|
|
|
+ /// Updates the local reachability status
|
|
|
+ func sessionReachabilityDidChange(_ session: WCSession) {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ print("⌚️ Watch reachability changed: \(session.isReachable)")
|
|
|
+
|
|
|
+ if session.isReachable {
|
|
|
+ // request fresh data from watch
|
|
|
+ self.requestWatchStateUpdate()
|
|
|
+
|
|
|
+ // reset input amounts
|
|
|
+ self.bolusAmount = 0
|
|
|
+ self.carbsAmount = 0
|
|
|
+ // reset auth progress
|
|
|
+ self.confirmationProgress = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Handles incoming messages that either contain an acknowledgement or fresh watchState data (<15 min)
|
|
|
+ private func processWatchMessage(_ message: [String: Any]) {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ // 1) Acknowledgment logic
|
|
|
+ if let acknowledged = message[WatchMessageKeys.acknowledged] as? Bool,
|
|
|
+ let ackMessage = message[WatchMessageKeys.message] as? String
|
|
|
+ {
|
|
|
+ DispatchQueue.main.async {
|
|
|
+ self.showSyncingAnimation = false
|
|
|
+ }
|
|
|
+
|
|
|
+ print("⌚️ Received acknowledgment: \(ackMessage), success: \(acknowledged)")
|
|
|
+
|
|
|
+ switch ackMessage {
|
|
|
+ case "Saving carbs...":
|
|
|
+ self.isMealBolusCombo = true
|
|
|
+ self.mealBolusStep = .savingCarbs
|
|
|
+ self.showCommsAnimation = true
|
|
|
+ self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: false)
|
|
|
+ case "Enacting bolus...":
|
|
|
+ self.isMealBolusCombo = true
|
|
|
+ self.mealBolusStep = .enactingBolus
|
|
|
+ self.showCommsAnimation = true
|
|
|
+ self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: false)
|
|
|
+ case "Carbs and bolus logged successfully":
|
|
|
+ self.isMealBolusCombo = false
|
|
|
+ self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: true)
|
|
|
+ default:
|
|
|
+ self.isMealBolusCombo = false
|
|
|
+ self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2) Raw watchState data
|
|
|
+ if let watchStateData = message[WatchMessageKeys.watchState] as? [String: Any] {
|
|
|
+ self.scheduleUIUpdate(with: watchStateData)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/// Accumulate new data, set isSyncing, and debounce final update
|
|
|
private func scheduleUIUpdate(with newData: [String: Any]) {
|
|
|
// 1) Mark as syncing
|
|
|
@@ -579,88 +398,122 @@ import WatchConnectivity
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private func processWatchMessage(_ message: [String: Any]) {
|
|
|
- DispatchQueue.main.async {
|
|
|
- // 1) Acknowledgment logic
|
|
|
- if let acknowledged = message[WatchMessageKeys.acknowledged] as? Bool,
|
|
|
- let ackMessage = message[WatchMessageKeys.message] as? String
|
|
|
- {
|
|
|
- DispatchQueue.main.async {
|
|
|
- self.showSyncingAnimation = false
|
|
|
- }
|
|
|
+ /// Updates the UI properties
|
|
|
+ private func processRawDataForWatchState(_ message: [String: Any]) {
|
|
|
+ if let currentGlucose = message[WatchMessageKeys.currentGlucose] as? String {
|
|
|
+ self.currentGlucose = currentGlucose
|
|
|
+ }
|
|
|
|
|
|
- print("⌚️ Received acknowledgment: \(ackMessage), success: \(acknowledged)")
|
|
|
+ if let currentGlucoseColorString = message[WatchMessageKeys.currentGlucoseColorString] as? String {
|
|
|
+ self.currentGlucoseColorString = currentGlucoseColorString
|
|
|
+ }
|
|
|
|
|
|
- switch ackMessage {
|
|
|
- case "Saving carbs...":
|
|
|
- self.isMealBolusCombo = true
|
|
|
- self.mealBolusStep = .savingCarbs
|
|
|
- self.showCommsAnimation = true
|
|
|
- self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: false)
|
|
|
- case "Enacting bolus...":
|
|
|
- self.isMealBolusCombo = true
|
|
|
- self.mealBolusStep = .enactingBolus
|
|
|
- self.showCommsAnimation = true
|
|
|
- self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: false)
|
|
|
- case "Carbs and bolus logged successfully":
|
|
|
- self.isMealBolusCombo = false
|
|
|
- self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: true)
|
|
|
- default:
|
|
|
- self.isMealBolusCombo = false
|
|
|
- self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: true)
|
|
|
- }
|
|
|
+ if let trend = message[WatchMessageKeys.trend] as? String {
|
|
|
+ self.trend = trend
|
|
|
+ }
|
|
|
+
|
|
|
+ if let delta = message[WatchMessageKeys.delta] as? String {
|
|
|
+ self.delta = delta
|
|
|
+ }
|
|
|
+
|
|
|
+ if let iob = message[WatchMessageKeys.iob] as? String {
|
|
|
+ self.iob = iob
|
|
|
+ }
|
|
|
+
|
|
|
+ if let cob = message[WatchMessageKeys.cob] as? String {
|
|
|
+ self.cob = cob
|
|
|
+ }
|
|
|
+
|
|
|
+ if let lastLoopTime = message[WatchMessageKeys.lastLoopTime] as? String {
|
|
|
+ self.lastLoopTime = lastLoopTime
|
|
|
+ }
|
|
|
+
|
|
|
+ if let glucoseData = message[WatchMessageKeys.glucoseValues] as? [[String: Any]] {
|
|
|
+ glucoseValues = glucoseData.compactMap { data in
|
|
|
+ guard let glucose = data["glucose"] as? Double,
|
|
|
+ let timestamp = data["date"] as? TimeInterval,
|
|
|
+ let colorString = data["color"] as? String
|
|
|
+ else { return nil }
|
|
|
+
|
|
|
+ return (
|
|
|
+ Date(timeIntervalSince1970: timestamp),
|
|
|
+ glucose,
|
|
|
+ colorString.toColor() // Convert colorString to Color
|
|
|
+ )
|
|
|
}
|
|
|
+ .sorted { $0.date < $1.date }
|
|
|
+ }
|
|
|
|
|
|
- // 2) Bolus progress
|
|
|
- if let progress = message[WatchMessageKeys.bolusProgress] as? Double {
|
|
|
- if !self.isBolusCanceled {
|
|
|
- self.bolusProgress = progress
|
|
|
- }
|
|
|
- DispatchQueue.main.async {
|
|
|
- self.showSyncingAnimation = false
|
|
|
- }
|
|
|
+ if let overrideData = message[WatchMessageKeys.overridePresets] as? [[String: Any]] {
|
|
|
+ overridePresets = overrideData.compactMap { data in
|
|
|
+ guard let name = data["name"] as? String,
|
|
|
+ let isEnabled = data["isEnabled"] as? Bool
|
|
|
+ else { return nil }
|
|
|
+ return OverridePresetWatch(name: name, isEnabled: isEnabled)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // 3) Bolus cancellation
|
|
|
- if message[WatchMessageKeys.bolusCanceled] as? Bool == true {
|
|
|
- self.bolusProgress = 0
|
|
|
- self.activeBolusAmount = 0
|
|
|
- DispatchQueue.main.async {
|
|
|
- self.showSyncingAnimation = false
|
|
|
- }
|
|
|
+ if let tempTargetData = message[WatchMessageKeys.tempTargetPresets] as? [[String: Any]] {
|
|
|
+ tempTargetPresets = tempTargetData.compactMap { data in
|
|
|
+ guard let name = data["name"] as? String,
|
|
|
+ let isEnabled = data["isEnabled"] as? Bool
|
|
|
+ else { return nil }
|
|
|
+ return TempTargetPresetWatch(name: name, isEnabled: isEnabled)
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // 4) Recommended bolus
|
|
|
- if let recommendedBolus = message[WatchMessageKeys.recommendedBolus] as? NSNumber {
|
|
|
- self.recommendedBolus = recommendedBolus.decimalValue
|
|
|
- self.showBolusCalculationProgress = false
|
|
|
- DispatchQueue.main.async {
|
|
|
- self.showSyncingAnimation = false
|
|
|
- }
|
|
|
+ if let bolusProgress = message[WatchMessageKeys.bolusProgress] as? Double {
|
|
|
+ if !isBolusCanceled {
|
|
|
+ self.bolusProgress = bolusProgress
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // 5) Raw watchState data
|
|
|
- if let watchStateData = message[WatchMessageKeys.watchState] as? [String: Any] {
|
|
|
- self.scheduleUIUpdate(with: watchStateData)
|
|
|
+ if let bolusWasCanceled = message[WatchMessageKeys.bolusCanceled] as? Bool, bolusWasCanceled {
|
|
|
+ bolusProgress = 0
|
|
|
+ activeBolusAmount = 0
|
|
|
+ }
|
|
|
+
|
|
|
+ if let maxBolusValue = message[WatchMessageKeys.maxBolus] {
|
|
|
+ print("⌚️ Received maxBolus: \(maxBolusValue) of type \(type(of: maxBolusValue))")
|
|
|
+ if let decimalValue = (maxBolusValue as? NSNumber)?.decimalValue {
|
|
|
+ maxBolus = decimalValue
|
|
|
+ print("⌚️ Converted maxBolus to: \(decimalValue)")
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /// Called when the reachability status of the paired iPhone changes
|
|
|
- /// Updates the local reachability status
|
|
|
- func sessionReachabilityDidChange(_ session: WCSession) {
|
|
|
- DispatchQueue.main.async {
|
|
|
- print("⌚️ Watch reachability changed: \(session.isReachable)")
|
|
|
+ if let maxCarbsValue = message[WatchMessageKeys.maxCarbs] {
|
|
|
+ if let decimalValue = (maxCarbsValue as? NSNumber)?.decimalValue {
|
|
|
+ maxCarbs = decimalValue
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if session.isReachable {
|
|
|
- // request fresh data from watch
|
|
|
- self.requestWatchStateUpdate()
|
|
|
+ if let maxFatValue = message[WatchMessageKeys.maxFat] {
|
|
|
+ if let decimalValue = (maxFatValue as? NSNumber)?.decimalValue {
|
|
|
+ maxFat = decimalValue
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // reset input amounts
|
|
|
- self.bolusAmount = 0
|
|
|
- self.carbsAmount = 0
|
|
|
- // reset auth progress
|
|
|
- self.confirmationProgress = 0
|
|
|
+ if let maxProteinValue = message[WatchMessageKeys.maxProtein] {
|
|
|
+ if let decimalValue = (maxProteinValue as? NSNumber)?.decimalValue {
|
|
|
+ maxProtein = decimalValue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let maxIOBValue = message[WatchMessageKeys.maxIOB] {
|
|
|
+ if let decimalValue = (maxIOBValue as? NSNumber)?.decimalValue {
|
|
|
+ maxIOB = decimalValue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let maxCOBValue = message[WatchMessageKeys.maxCOB] {
|
|
|
+ if let decimalValue = (maxCOBValue as? NSNumber)?.decimalValue {
|
|
|
+ maxCOB = decimalValue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let bolusIncrement = message[WatchMessageKeys.bolusIncrement] {
|
|
|
+ if let decimalValue = (bolusIncrement as? NSNumber)?.decimalValue {
|
|
|
+ self.bolusIncrement = decimalValue
|
|
|
}
|
|
|
}
|
|
|
}
|