polscm32 aka Marvout 1 년 전
부모
커밋
b6770ea455

+ 17 - 4
Trio Watch App Extension/Views/BolusInputView.swift

@@ -13,6 +13,19 @@ struct BolusInputView: View {
 
     @FocusState private var isCrownFocused: Bool
 
+    private var effectiveBolusLimit: Double {
+        // Extract current IOB from string and convert to Double
+        let currentIOB = Double(state.iob?.replacingOccurrences(of: " U", with: "") ?? "0") ?? 0
+
+        // Calculate available IOB
+        let availableIOB = max(0, Double(truncating: state.maxIOB as NSNumber) - currentIOB)
+
+        return min(
+            Double(truncating: state.maxBolus as NSNumber),
+            availableIOB
+        )
+    }
+
     var body: some View {
         VStack {
             if state.carbsAmount > 0 {
@@ -49,7 +62,7 @@ struct BolusInputView: View {
                     .digitalCrownRotation(
                         $bolusAmount,
                         from: 0,
-                        through: 150.0, // TODO: use maxBolus here
+                        through: effectiveBolusLimit,
                         by: 1, // TODO: use pump increment here
                         sensitivity: .medium,
                         isContinuous: false,
@@ -58,7 +71,6 @@ struct BolusInputView: View {
 
                 Spacer()
 
-                // TODO: introduce maxBolus here, disable button if bolusAmount > maxBolus
                 // "+" Button
                 Button(action: {
                     bolusAmount += 0.5
@@ -68,6 +80,7 @@ struct BolusInputView: View {
                         .foregroundColor(.blue)
                 }
                 .buttonStyle(.borderless)
+                .disabled(bolusAmount >= effectiveBolusLimit)
             }.padding(.horizontal)
 
             Text("Insulin")
@@ -78,12 +91,12 @@ struct BolusInputView: View {
             Spacer()
 
             Button("Log Bolus") {
-                state.bolusAmount = bolusAmount
+                state.bolusAmount = min(bolusAmount, effectiveBolusLimit)
                 navigationState.path.append(NavigationDestinations.bolusConfirm)
             }
             .buttonStyle(.bordered)
             .tint(.blue)
-            .disabled(!(bolusAmount > 0.0))
+            .disabled(!(bolusAmount > 0.0) || bolusAmount >= effectiveBolusLimit)
         }
         .toolbar {
             ToolbarItem(placement: .topBarTrailing) {

+ 18 - 6
Trio Watch App Extension/Views/CarbsInputView.swift

@@ -12,6 +12,19 @@ struct CarbsInputView: View {
     let state: WatchState
     let continueToBolus: Bool
 
+    private var effectiveCarbsLimit: Double {
+        // Extract current COB from string and convert to Double
+        let currentCOB = Double(state.cob?.replacingOccurrences(of: " g", with: "") ?? "0") ?? 0
+
+        // Calculate available COB
+        let availableCOB = max(0, Double(truncating: state.maxCOB as NSNumber) - currentCOB)
+
+        return min(
+            Double(truncating: state.maxCarbs as NSNumber),
+            availableCOB
+        )
+    }
+
     var body: some View {
         let buttonLabel = continueToBolus ? "Proceed" : "Log Carbs"
 
@@ -43,7 +56,7 @@ struct CarbsInputView: View {
                     .digitalCrownRotation(
                         $carbsAmount,
                         from: 0,
-                        through: 150.0, // TODO: introduce maxCarbs here
+                        through: effectiveCarbsLimit,
                         by: 1,
                         sensitivity: .medium,
                         isContinuous: false,
@@ -52,7 +65,6 @@ struct CarbsInputView: View {
 
                 Spacer()
 
-                // TODO: introduce maxCarbs here, disable button if carbsAmount > maxCarbs
                 // "+" Button
                 Button(action: {
                     carbsAmount += 1
@@ -62,6 +74,7 @@ struct CarbsInputView: View {
                         .foregroundColor(.orange)
                 }
                 .buttonStyle(.borderless)
+                .disabled(carbsAmount >= effectiveCarbsLimit)
             }.padding(.horizontal)
 
             Text("Carbohydrates")
@@ -73,18 +86,17 @@ struct CarbsInputView: View {
 
             Button(buttonLabel) {
                 if continueToBolus {
-                    state.carbsAmount = Int(carbsAmount)
+                    state.carbsAmount = Int(min(carbsAmount, effectiveCarbsLimit))
                     navigationState.path.append(NavigationDestinations.bolusInput)
                 } else {
-                    state.sendCarbsRequest(Int(carbsAmount))
-
                     // TODO: add a fancy success animation
+                    state.sendCarbsRequest(Int(min(carbsAmount, effectiveCarbsLimit)))
                     navigationState.resetToRoot()
                 }
             }
             .buttonStyle(.bordered)
             .tint(.orange)
-            .disabled(!(carbsAmount > 0.0))
+            .disabled(!(carbsAmount > 0.0) || carbsAmount >= effectiveCarbsLimit)
         }
         .toolbar {
             ToolbarItem(placement: .topBarTrailing) {

+ 48 - 0
Trio Watch App Extension/WatchState.swift

@@ -32,6 +32,15 @@ import WatchConnectivity
 
     var bolusProgress: Double = 0.0
     var isBolusCanceled = false
+
+    // Safety limits
+    var maxBolus: Decimal = 10
+    var maxCarbs: Decimal = 250
+    var maxFat: Decimal = 250
+    var maxProtein: Decimal = 250
+    var maxIOB: Decimal = 0
+    var maxCOB: Decimal = 120
+
     override init() {
         super.init()
         setupSession()
@@ -247,6 +256,45 @@ import WatchConnectivity
                     self.bolusProgress = bolusProgress
                 }
             }
+
+            // Debug print für die Safety Limits
+            if let maxBolusValue = message["maxBolus"] {
+                print("⌚️ Received maxBolus: \(maxBolusValue) of type \(type(of: maxBolusValue))")
+                if let decimalValue = (maxBolusValue as? NSNumber)?.decimalValue {
+                    self.maxBolus = decimalValue
+                    print("⌚️ Converted maxBolus to: \(decimalValue)")
+                }
+            }
+
+            if let maxCarbsValue = message["maxCarbs"] {
+                if let decimalValue = (maxCarbsValue as? NSNumber)?.decimalValue {
+                    self.maxCarbs = decimalValue
+                }
+            }
+
+            if let maxFatValue = message["maxFat"] {
+                if let decimalValue = (maxFatValue as? NSNumber)?.decimalValue {
+                    self.maxFat = decimalValue
+                }
+            }
+
+            if let maxProteinValue = message["maxProtein"] {
+                if let decimalValue = (maxProteinValue as? NSNumber)?.decimalValue {
+                    self.maxProtein = decimalValue
+                }
+            }
+
+            if let maxIOBValue = message["maxIOB"] {
+                if let decimalValue = (maxIOBValue as? NSNumber)?.decimalValue {
+                    self.maxIOB = decimalValue
+                }
+            }
+
+            if let maxCOBValue = message["maxCOB"] {
+                if let decimalValue = (maxCOBValue as? NSNumber)?.decimalValue {
+                    self.maxCOB = decimalValue
+                }
+            }
         }
     }
 

+ 21 - 1
Trio/Sources/Models/WatchState.swift

@@ -12,6 +12,14 @@ struct WatchState: Hashable, Equatable, Sendable {
     var overridePresets: [OverridePresetWatch] = []
     var tempTargetPresets: [TempTargetPresetWatch] = []
 
+    // Safety limits
+    var maxBolus: Decimal = 10.0
+    var maxCarbs: Decimal = 250
+    var maxFat: Decimal = 250
+    var maxProtein: Decimal = 250
+    var maxIOB: Decimal = 0
+    var maxCOB: Decimal = 120
+
     static func == (lhs: WatchState, rhs: WatchState) -> Bool {
         lhs.currentGlucose == rhs.currentGlucose &&
             lhs.trend == rhs.trend &&
@@ -25,7 +33,13 @@ struct WatchState: Hashable, Equatable, Sendable {
             lhs.cob == rhs.cob &&
             lhs.lastLoopTime == rhs.lastLoopTime &&
             lhs.overridePresets == rhs.overridePresets &&
-            lhs.tempTargetPresets == rhs.tempTargetPresets
+            lhs.tempTargetPresets == rhs.tempTargetPresets &&
+            lhs.maxBolus == rhs.maxBolus &&
+            lhs.maxCarbs == rhs.maxCarbs &&
+            lhs.maxFat == rhs.maxFat &&
+            lhs.maxProtein == rhs.maxProtein &&
+            lhs.maxIOB == rhs.maxIOB &&
+            lhs.maxCOB == rhs.maxCOB
     }
 
     func hash(into hasher: inout Hasher) {
@@ -42,5 +56,11 @@ struct WatchState: Hashable, Equatable, Sendable {
         hasher.combine(lastLoopTime)
         hasher.combine(overridePresets)
         hasher.combine(tempTargetPresets)
+        hasher.combine(maxBolus)
+        hasher.combine(maxCarbs)
+        hasher.combine(maxFat)
+        hasher.combine(maxProtein)
+        hasher.combine(maxIOB)
+        hasher.combine(maxCOB)
     }
 }

+ 52 - 7
Trio/Sources/Services/WatchManager/AppleWatchManager.swift

@@ -13,6 +13,7 @@ protocol WatchManager {}
 final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchManager {
     private var session: WCSession?
 
+    @Injected() var broadcaster: Broadcaster!
     @Injected() private var glucoseStorage: GlucoseStorage!
     @Injected() private var apsManager: APSManager!
     @Injected() private var settingsManager: SettingsManager!
@@ -35,6 +36,9 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
         injectServices(resolver)
         setupWatchSession()
         units = settingsManager.settings.units
+        broadcaster.register(SettingsObserver.self, observer: self)
+        broadcaster.register(PumpSettingsObserver.self, observer: self)
+        broadcaster.register(PreferencesObserver.self, observer: self)
 
         // Observer for OrefDetermination and adjustments
         coreDataPublisher =
@@ -204,6 +208,14 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
             // Set units
             watchState.units = self.units
 
+            // Add settings values
+            watchState.maxBolus = self.settingsManager.pumpSettings.maxBolus
+            watchState.maxCarbs = self.settingsManager.settings.maxCarbs
+            watchState.maxFat = self.settingsManager.settings.maxFat
+            watchState.maxProtein = self.settingsManager.settings.maxProtein
+            watchState.maxIOB = self.settingsManager.preferences.maxIOB
+            watchState.maxCOB = self.settingsManager.preferences.maxCOB
+
             debug(
                 .watchManager,
 
@@ -244,18 +256,18 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
         }
 
         let message: [String: Any] = [
-            "currentGlucose": state.currentGlucose ?? "0",
-            "trend": state.trend ?? "?",
-            "delta": state.delta ?? "0",
+            "currentGlucose": state.currentGlucose ?? "",
+            "trend": state.trend ?? "",
+            "delta": state.delta ?? "",
+            "iob": state.iob ?? "",
+            "cob": state.cob ?? "",
+            "lastLoopTime": state.lastLoopTime ?? "",
             "glucoseValues": state.glucoseValues.map { value in
                 [
                     "glucose": value.glucose,
                     "date": value.date.timeIntervalSince1970
                 ]
             },
-            "iob": state.iob ?? "0",
-            "cob": state.cob ?? "0",
-            "lastLoopTime": state.lastLoopTime ?? "--",
             "overridePresets": state.overridePresets.map { preset in
                 [
                     "name": preset.name,
@@ -267,7 +279,13 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
                     "name": preset.name,
                     "isEnabled": preset.isEnabled
                 ]
-            }
+            },
+            "maxBolus": state.maxBolus,
+            "maxCarbs": state.maxCarbs,
+            "maxFat": state.maxFat,
+            "maxProtein": state.maxProtein,
+            "maxIOB": state.maxIOB,
+            "maxCOB": state.maxCOB
         ]
 
         debug(.watchManager, "📱 Sending to watch - Message content:")
@@ -651,3 +669,30 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
         }
     }
 }
+
+// TODO: - is there a better approach than setting up the watch state every time a setting has changed?
+extension BaseWatchManager: SettingsObserver, PumpSettingsObserver, PreferencesObserver {
+    // to update maxCOB, maxIOB
+    func preferencesDidChange(_: Preferences) {
+        Task {
+            let state = await self.setupWatchState()
+            self.sendDataToWatch(state)
+        }
+    }
+
+    // to update maxBolus
+    func pumpSettingsDidChange(_: PumpSettings) {
+        Task {
+            let state = await self.setupWatchState()
+            self.sendDataToWatch(state)
+        }
+    }
+
+    // to update the rest
+    func settingsDidChange(_: TrioSettings) {
+        Task {
+            let state = await self.setupWatchState()
+            self.sendDataToWatch(state)
+        }
+    }
+}