Przeglądaj źródła

batch process state and show sync animation

Co-Authored-By: polscm32 <polscm32@users.noreply.github.com>
polscm32 aka Marvout 1 rok temu
rodzic
commit
67e0ade233

+ 2 - 2
Trio Watch App Extension/Views/GlucoseTrendView.swift

@@ -51,13 +51,13 @@ struct GlucoseTrendView: View {
                 VStack(alignment: .center) {
                     Text(state.currentGlucose)
                         .fontWeight(.semibold)
-                        .font(.system(is40mm ? .title2 : .title, design: .rounded))
+                        .font(.system(is40mm ? .title2 : .title))
                         .foregroundStyle(state.currentGlucoseColorString.toColor())
 
                     if let delta = state.delta {
                         Text(delta)
                             .fontWeight(.semibold)
-                            .font(.system(.caption, design: .rounded))
+                            .font(.system(.caption))
                             .foregroundStyle(.secondary)
                     }
                 }

+ 15 - 0
Trio Watch App Extension/Views/TrioMainWatchView.swift

@@ -40,6 +40,21 @@ struct TrioMainWatchView: View {
     )
 
     var body: some View {
+        ZStack {
+            if !state.showSyncingAnimation {
+                mainTabView
+            } else {
+                trioBackgroundColor.ignoresSafeArea()
+
+                VStack {
+                    ProgressView("Syncing...")
+                    Spacer()
+                }
+            }
+        }
+    }
+
+    @ViewBuilder private var mainTabView: some View {
         NavigationStack(path: $navigationPath) {
             TabView(selection: $currentPage) {
                 // Page 1: Current glucose trend in "BG bobble"

+ 94 - 15
Trio Watch App Extension/WatchState.swift

@@ -46,14 +46,14 @@ import WatchConnectivity
     // Pump specific dosing increment
     var bolusIncrement: Decimal = 0.05
 
-    // acknowlegement handling
+    // Acknowlegement handling
     var showCommsAnimation: Bool = false
     var showAcknowledgmentBanner: Bool = false
     var acknowledgementStatus: AcknowledgementStatus = .pending
     var acknowledgmentMessage: String = ""
     var shouldNavigateToRoot: Bool = true
 
-    // bolus calculation progress
+    // Bolus calculation progress
     var showBolusCalculationProgress: Bool = false
 
     // Meal bolus-specific properties
@@ -67,6 +67,17 @@ import WatchConnectivity
 
     var recommendedBolus: Decimal = 0
 
+    // Debouncing and batch processing helpers
+
+    /// Temporary storage for new data arriving via WatchConnectivity.
+    private var pendingData: [String: Any] = [:]
+
+    /// Work item to schedule finalizing the pending data.
+    private var finalizeWorkItem: DispatchWorkItem?
+
+    /// A flag to tell the UI we’re still updating.
+    var showSyncingAnimation: Bool = false
+
     override init() {
         super.init()
         setupSession()
@@ -361,7 +372,7 @@ import WatchConnectivity
         if let bolusWasCanceled = message[WatchMessageKeys.bolusCanceled] as? Bool, bolusWasCanceled {
             bolusProgress = 0
             activeBolusAmount = 0
-            return
+//            return
         }
 
         if let maxBolusValue = message[WatchMessageKeys.maxBolus] {
@@ -445,12 +456,58 @@ import WatchConnectivity
         processWatchMessage(userInfo)
     }
 
+    /// Accumulate new data, set isSyncing, and debounce final update
+    private func scheduleUIUpdate(with newData: [String: Any]) {
+        // 1) Mark as syncing
+        showSyncingAnimation = true
+
+        // 2) Merge data into our pendingData
+        pendingData.merge(newData) { _, newVal in newVal }
+
+        // 3) Cancel any previous finalization
+        finalizeWorkItem?.cancel()
+
+        // 4) Create and schedule a new finalization
+        let workItem = DispatchWorkItem { [self] in
+            self.finalizePendingData()
+        }
+        finalizeWorkItem = workItem
+
+        // e.g. 0.3 seconds after last message
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: workItem)
+    }
+
+    /// Applies all pending data to the watch state in one shot
+    private func finalizePendingData() {
+        guard !pendingData.isEmpty else {
+            // If we have no actual data, just end syncing
+            showSyncingAnimation = false
+            return
+        }
+
+        print("⌚️ Finalizing pending data: \(pendingData)")
+
+        // Actually set your main UI properties here
+        processRawDataForWatchState(pendingData)
+
+        // Clear
+        pendingData.removeAll()
+
+        // Done - but ensure this runs at least 2 sec, to avoid flickering
+        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+            self.showSyncingAnimation = false
+        }
+    }
+
     private func processWatchMessage(_ message: [String: Any]) {
         DispatchQueue.main.async {
-            // Handle acknowledgment messages first
+            // 1) Acknowledgment logic
             if let acknowledged = message[WatchMessageKeys.acknowledged] as? Bool,
                let ackMessage = message[WatchMessageKeys.message] as? String
             {
+                self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: false)
+                self.showSyncingAnimation = false
+
                 print("⌚️ Received acknowledgment: \(ackMessage), success: \(acknowledged)")
 
                 switch ackMessage {
@@ -471,35 +528,57 @@ import WatchConnectivity
                     self.isMealBolusCombo = false
                     self.handleAcknowledgment(success: acknowledged, message: ackMessage, isFinal: true)
                 }
-                return
             }
 
-            // Handle bolus progress updates
+            // 2) Bolus progress
             if let progress = message[WatchMessageKeys.bolusProgress] as? Double {
                 if !self.isBolusCanceled {
                     self.bolusProgress = progress
                 }
-                return
+                self.showSyncingAnimation = false
             }
 
-            // Handle bolus cancellation
+            // 3) Bolus cancellation
             if message[WatchMessageKeys.bolusCanceled] as? Bool == true {
                 self.bolusProgress = 0
                 self.activeBolusAmount = 0
-                return
+                self.showSyncingAnimation = false
             }
 
-            // Handle recommended bolus
+            // 4) Recommended bolus
             if let recommendedBolus = message[WatchMessageKeys.recommendedBolus] as? NSNumber {
-                print("⌚️ Received recommended bolus: \(recommendedBolus)")
                 self.recommendedBolus = recommendedBolus.decimalValue
                 self.showBolusCalculationProgress = false
-                return
+                self.showSyncingAnimation = false
             }
 
-            // Handle watch state updates
-            if let dataFromMessage = message[WatchMessageKeys.watchState] as? [String: Any] {
-                self.processRawDataForWatchState(dataFromMessage)
+            // 5) Raw watchState data
+            if let watchStateData = message[WatchMessageKeys.watchState] as? [String: Any] {
+                self.scheduleUIUpdate(with: watchStateData)
+            } else {
+                // Or if your phone sends these UI keys individually:
+                let possibleUIKeys = [
+                    WatchMessageKeys.currentGlucose,
+                    WatchMessageKeys.trend,
+                    WatchMessageKeys.iob,
+                    WatchMessageKeys.cob,
+                    WatchMessageKeys.lastLoopTime,
+                    WatchMessageKeys.glucoseValues,
+                    WatchMessageKeys.overridePresets,
+                    WatchMessageKeys.tempTargetPresets,
+                    WatchMessageKeys.maxBolus,
+                    WatchMessageKeys.maxCarbs,
+                    WatchMessageKeys.maxFat,
+                    WatchMessageKeys.maxProtein,
+                    WatchMessageKeys.maxIOB,
+                    WatchMessageKeys.maxCOB,
+                    WatchMessageKeys.bolusIncrement
+                ]
+
+                let hasUIData = message.keys.contains { possibleUIKeys.contains($0) }
+                if hasUIData {
+                    self.scheduleUIUpdate(with: message)
+                }
             }
         }
     }