ソースを参照

Merge pull request #518 from dnzxy/fix-fpu-processing

Fix FPU Processing for Possible out of range Values
Sam King 1 年間 前
コミット
cf64276e09

+ 7 - 3
Trio.xcodeproj/project.pbxproj

@@ -247,6 +247,7 @@
 		3B997DCB2DC00849006B6BB2 /* JSONImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */; };
 		3B997DCB2DC00849006B6BB2 /* JSONImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */; };
 		3B997DCF2DC00A3A006B6BB2 /* JSONImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */; };
 		3B997DCF2DC00A3A006B6BB2 /* JSONImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */; };
 		3B997DD32DC02AEF006B6BB2 /* glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B997DD12DC02AEF006B6BB2 /* glucose.json */; };
 		3B997DD32DC02AEF006B6BB2 /* glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B997DD12DC02AEF006B6BB2 /* glucose.json */; };
+		3BA8D1B32DDB87150006191F /* DecimalExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BA8D1B22DDB870F0006191F /* DecimalExtensions.swift */; };
 		3BAD36B22D7CDC1A00CC298D /* MainLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BAD36B12D7CDC1400CC298D /* MainLoadingView.swift */; };
 		3BAD36B22D7CDC1A00CC298D /* MainLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BAD36B12D7CDC1400CC298D /* MainLoadingView.swift */; };
 		3BAD36CC2D7D420E00CC298D /* CoreDataInitializationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BAD36CB2D7D420500CC298D /* CoreDataInitializationCoordinator.swift */; };
 		3BAD36CC2D7D420E00CC298D /* CoreDataInitializationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BAD36CB2D7D420500CC298D /* CoreDataInitializationCoordinator.swift */; };
 		3BCA5F7C2DC7B16400A7EAC7 /* pumphistory-with-external.json in Resources */ = {isa = PBXBuildFile; fileRef = 3BCA5F7B2DC7B15400A7EAC7 /* pumphistory-with-external.json */; };
 		3BCA5F7C2DC7B16400A7EAC7 /* pumphistory-with-external.json in Resources */ = {isa = PBXBuildFile; fileRef = 3BCA5F7B2DC7B15400A7EAC7 /* pumphistory-with-external.json */; };
@@ -1056,6 +1057,7 @@
 		3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporter.swift; sourceTree = "<group>"; };
 		3B997DCA2DC00849006B6BB2 /* JSONImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporter.swift; sourceTree = "<group>"; };
 		3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporterTests.swift; sourceTree = "<group>"; };
 		3B997DCE2DC00A3A006B6BB2 /* JSONImporterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONImporterTests.swift; sourceTree = "<group>"; };
 		3B997DD12DC02AEF006B6BB2 /* glucose.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = glucose.json; sourceTree = "<group>"; };
 		3B997DD12DC02AEF006B6BB2 /* glucose.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = glucose.json; sourceTree = "<group>"; };
+		3BA8D1B22DDB870F0006191F /* DecimalExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalExtensions.swift; sourceTree = "<group>"; };
 		3BAD36B12D7CDC1400CC298D /* MainLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainLoadingView.swift; sourceTree = "<group>"; };
 		3BAD36B12D7CDC1400CC298D /* MainLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainLoadingView.swift; sourceTree = "<group>"; };
 		3BAD36CB2D7D420500CC298D /* CoreDataInitializationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataInitializationCoordinator.swift; sourceTree = "<group>"; };
 		3BAD36CB2D7D420500CC298D /* CoreDataInitializationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataInitializationCoordinator.swift; sourceTree = "<group>"; };
 		3BCA5F7B2DC7B15400A7EAC7 /* pumphistory-with-external.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "pumphistory-with-external.json"; sourceTree = "<group>"; };
 		3BCA5F7B2DC7B15400A7EAC7 /* pumphistory-with-external.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "pumphistory-with-external.json"; sourceTree = "<group>"; };
@@ -2442,13 +2444,14 @@
 		38A504F625DDA0E200C5B9E8 /* Extensions */ = {
 		38A504F625DDA0E200C5B9E8 /* Extensions */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				CE2FAD39297D93F0001A872C /* BloodGlucoseExtensions.swift */,
+				3BA8D1B22DDB870F0006191F /* DecimalExtensions.swift */,
 				DDB37CC62D05127500D99BF4 /* FontExtensions.swift */,
 				DDB37CC62D05127500D99BF4 /* FontExtensions.swift */,
-				38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */,
-				38BF021625E7CBBC00579895 /* PumpManagerExtensions.swift */,
 				CEB434E628B9053300B70274 /* LoopUIColorPalette+Default.swift */,
 				CEB434E628B9053300B70274 /* LoopUIColorPalette+Default.swift */,
 				CE48C86328CA69D5007C0598 /* OmniBLEPumpManagerExtensions.swift */,
 				CE48C86328CA69D5007C0598 /* OmniBLEPumpManagerExtensions.swift */,
 				CE48C86528CA6B48007C0598 /* OmniPodManagerExtensions.swift */,
 				CE48C86528CA6B48007C0598 /* OmniPodManagerExtensions.swift */,
-				CE2FAD39297D93F0001A872C /* BloodGlucoseExtensions.swift */,
+				38BF021625E7CBBC00579895 /* PumpManagerExtensions.swift */,
+				38A5049125DD9C4000C5B9E8 /* UserDefaultsExtensions.swift */,
 			);
 			);
 			path = Extensions;
 			path = Extensions;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -4535,6 +4538,7 @@
 				DDD163122C4C689900CD525A /* AdjustmentsStateModel.swift in Sources */,
 				DDD163122C4C689900CD525A /* AdjustmentsStateModel.swift in Sources */,
 				BD47FDD72D8B64D20043966B /* CarbRatioStepView.swift in Sources */,
 				BD47FDD72D8B64D20043966B /* CarbRatioStepView.swift in Sources */,
 				3B2F77862D7E52ED005ED9FA /* TDD.swift in Sources */,
 				3B2F77862D7E52ED005ED9FA /* TDD.swift in Sources */,
+				3BA8D1B32DDB87150006191F /* DecimalExtensions.swift in Sources */,
 				DD3F1F892D9E078D00DCE7B3 /* TherapySettingEditorView.swift in Sources */,
 				DD3F1F892D9E078D00DCE7B3 /* TherapySettingEditorView.swift in Sources */,
 				DD1745132C54169400211FAC /* DevicesView.swift in Sources */,
 				DD1745132C54169400211FAC /* DevicesView.swift in Sources */,
 				7F7B756BE8543965D9FDF1A2 /* DataTableDataFlow.swift in Sources */,
 				7F7B756BE8543965D9FDF1A2 /* DataTableDataFlow.swift in Sources */,

+ 7 - 0
Trio/Sources/APS/Extensions/DecimalExtensions.swift

@@ -0,0 +1,7 @@
+import Foundation
+
+extension Decimal {
+    func clamp(to pickerSetting: PickerSetting) -> Decimal {
+        max(min(self, pickerSetting.max), pickerSetting.min)
+    }
+}

+ 18 - 10
Trio/Sources/APS/Storage/CarbsStorage.swift

@@ -27,6 +27,8 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
 
 
     private let updateSubject = PassthroughSubject<Void, Never>()
     private let updateSubject = PassthroughSubject<Void, Never>()
 
 
+    private let settingsProvider = PickerSettingsProvider.shared
+
     var updatePublisher: AnyPublisher<Void, Never> {
     var updatePublisher: AnyPublisher<Void, Never> {
         updateSubject.eraseToAnyPublisher()
         updateSubject.eraseToAnyPublisher()
     }
     }
@@ -111,7 +113,7 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
 
 
      - Returns: The computed duration in hours.
      - Returns: The computed duration in hours.
      */
      */
-    private func calculateComputedDuration(fpus: Decimal, timeCap: Int) -> Int {
+    private func calculateComputedDuration(fpus: Decimal, timeCap: Decimal) -> Decimal {
         switch fpus {
         switch fpus {
         case ..<2:
         case ..<2:
             return 3
             return 3
@@ -145,22 +147,25 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
         createdAt: Date,
         createdAt: Date,
         actualDate: Date?
         actualDate: Date?
     ) -> ([CarbsEntry], Decimal) {
     ) -> ([CarbsEntry], Decimal) {
-        let interval = settings.settings.minuteInterval
-        let timeCap = settings.settings.timeCap
-        let adjustment = settings.settings.individualAdjustmentFactor
-        let delay = settings.settings.delay
+        let trioSettings = settings.settings
+        let providerSettings = settingsProvider.settings
+
+        let interval = trioSettings.minuteInterval.clamp(to: providerSettings.minuteInterval)
+        let timeCap = trioSettings.timeCap.clamp(to: providerSettings.timeCap)
+        let adjustment = trioSettings.individualAdjustmentFactor.clamp(to: providerSettings.individualAdjustmentFactor)
+        let delay = trioSettings.delay.clamp(to: providerSettings.delay)
 
 
         let kcal = protein * 4 + fat * 9
         let kcal = protein * 4 + fat * 9
         let carbEquivalents = (kcal / 10) * adjustment
         let carbEquivalents = (kcal / 10) * adjustment
         let fpus = carbEquivalents / 10
         let fpus = carbEquivalents / 10
         var computedDuration = calculateComputedDuration(fpus: fpus, timeCap: timeCap)
         var computedDuration = calculateComputedDuration(fpus: fpus, timeCap: timeCap)
 
 
-        var carbEquivalentSize: Decimal = carbEquivalents / Decimal(computedDuration)
-        carbEquivalentSize /= Decimal(60 / interval)
+        var carbEquivalentSize: Decimal = carbEquivalents / computedDuration
+        carbEquivalentSize /= Decimal(60) / interval
 
 
         if carbEquivalentSize < 1.0 {
         if carbEquivalentSize < 1.0 {
             carbEquivalentSize = 1.0
             carbEquivalentSize = 1.0
-            computedDuration = Int(carbEquivalents / carbEquivalentSize)
+            computedDuration = min(carbEquivalents / carbEquivalentSize, timeCap)
         }
         }
 
 
         let roundedEquivalent: Double = round(Double(carbEquivalentSize * 10)) / 10
         let roundedEquivalent: Double = round(Double(carbEquivalentSize * 10)) / 10
@@ -172,9 +177,12 @@ final class BaseCarbsStorage: CarbsStorage, Injectable {
         var futureCarbArray = [CarbsEntry]()
         var futureCarbArray = [CarbsEntry]()
         var firstIndex = true
         var firstIndex = true
 
 
+        // convert Decimal minutes to TimeInterval in seconds
+        let delayTimeInterval = TimeInterval(delay * 60)
+        let intervalTimeInterval = TimeInterval(interval * 60)
         while carbEquivalents > 0, numberOfEquivalents > 0 {
         while carbEquivalents > 0, numberOfEquivalents > 0 {
-            useDate = firstIndex ? useDate.addingTimeInterval(delay.minutes.timeInterval) : useDate
-                .addingTimeInterval(interval.minutes.timeInterval)
+            useDate = firstIndex ? useDate.addingTimeInterval(delayTimeInterval) : useDate
+                .addingTimeInterval(intervalTimeInterval)
             firstIndex = false
             firstIndex = false
 
 
             let eachCarbEntry = CarbsEntry(
             let eachCarbEntry = CarbsEntry(

+ 6 - 6
Trio/Sources/Models/TrioSettings.swift

@@ -42,9 +42,9 @@ struct TrioSettings: JSON, Equatable {
     var showCarbsRequiredBadge: Bool = true
     var showCarbsRequiredBadge: Bool = true
     var useFPUconversion: Bool = true
     var useFPUconversion: Bool = true
     var individualAdjustmentFactor: Decimal = 0.5
     var individualAdjustmentFactor: Decimal = 0.5
-    var timeCap: Int = 8
-    var minuteInterval: Int = 30
-    var delay: Int = 60
+    var timeCap: Decimal = 8
+    var minuteInterval: Decimal = 30
+    var delay: Decimal = 60
     var useAppleHealth: Bool = false
     var useAppleHealth: Bool = false
     var smoothGlucose: Bool = false
     var smoothGlucose: Bool = false
     var eA1cDisplayUnit: EstimatedA1cDisplayUnit = .percent
     var eA1cDisplayUnit: EstimatedA1cDisplayUnit = .percent
@@ -167,15 +167,15 @@ extension TrioSettings: Decodable {
             settings.overrideFactor = overrideFactor
             settings.overrideFactor = overrideFactor
         }
         }
 
 
-        if let timeCap = try? container.decode(Int.self, forKey: .timeCap) {
+        if let timeCap = try? container.decode(Decimal.self, forKey: .timeCap) {
             settings.timeCap = timeCap
             settings.timeCap = timeCap
         }
         }
 
 
-        if let minuteInterval = try? container.decode(Int.self, forKey: .minuteInterval) {
+        if let minuteInterval = try? container.decode(Decimal.self, forKey: .minuteInterval) {
             settings.minuteInterval = minuteInterval
             settings.minuteInterval = minuteInterval
         }
         }
 
 
-        if let delay = try? container.decode(Int.self, forKey: .delay) {
+        if let delay = try? container.decode(Decimal.self, forKey: .delay) {
             settings.delay = delay
             settings.delay = delay
         }
         }
 
 

+ 13 - 24
Trio/Sources/Modules/MealSettings/MealSettingsStateModel.swift

@@ -16,36 +16,25 @@ extension MealSettings {
         override func subscribe() {
         override func subscribe() {
             units = settingsManager.settings.units
             units = settingsManager.settings.units
 
 
-            subscribeSetting(\.useFPUconversion, on: $useFPUconversion) { useFPUconversion = $0 }
             subscribeSetting(\.maxCarbs, on: $maxCarbs) { maxCarbs = $0 }
             subscribeSetting(\.maxCarbs, on: $maxCarbs) { maxCarbs = $0 }
             subscribeSetting(\.maxFat, on: $maxFat) { maxFat = $0 }
             subscribeSetting(\.maxFat, on: $maxFat) { maxFat = $0 }
             subscribeSetting(\.maxProtein, on: $maxProtein) { maxProtein = $0 }
             subscribeSetting(\.maxProtein, on: $maxProtein) { maxProtein = $0 }
 
 
-            subscribeSetting(\.timeCap, on: $timeCap.map(Int.init), initial: {
-                timeCap = Decimal($0)
-            }, map: {
-                $0
-            })
-
             subscribePreferencesSetting(\.maxMealAbsorptionTime, on: $maxMealAbsorptionTime) { maxMealAbsorptionTime = $0 }
             subscribePreferencesSetting(\.maxMealAbsorptionTime, on: $maxMealAbsorptionTime) { maxMealAbsorptionTime = $0 }
 
 
-            subscribeSetting(\.minuteInterval, on: $minuteInterval.map(Int.init), initial: {
-                minuteInterval = Decimal($0)
-            }, map: {
-                $0
-            })
-
-            subscribeSetting(\.delay, on: $delay.map(Int.init), initial: {
-                delay = Decimal($0)
-            }, map: {
-                $0
-            })
-
-            subscribeSetting(\.individualAdjustmentFactor, on: $individualAdjustmentFactor, initial: {
-                individualAdjustmentFactor = $0
-            }, map: {
-                $0
-            })
+            subscribeSetting(\.useFPUconversion, on: $useFPUconversion) { useFPUconversion = $0 }
+
+            // "Fat and Protein Delay"
+            subscribeSetting(\.delay, on: $delay) { delay = $0 }
+
+            // "Maximum Duration"
+            subscribeSetting(\.timeCap, on: $timeCap) { timeCap = $0 }
+
+            // "Spread Interval"
+            subscribeSetting(\.minuteInterval, on: $minuteInterval) { minuteInterval = $0 }
+
+            // "Fat and Protein Percentage"
+            subscribeSetting(\.individualAdjustmentFactor, on: $individualAdjustmentFactor) { individualAdjustmentFactor = $0 }
         }
         }
     }
     }
 }
 }