Sfoglia il codice sorgente

Merge branch 'core-data-sync-trio' into CGM-new-UI

avouspierre 1 anno fa
parent
commit
556a123628

+ 4 - 4
Model/Classes+Properties/TempTargetRunStored+CoreDataProperties.swift

@@ -6,13 +6,13 @@ public extension TempTargetRunStored {
         NSFetchRequest<TempTargetRunStored>(entityName: "TempTargetRunStored")
     }
 
-    @NSManaged var startDate: Date?
-    @NSManaged var target: NSDecimalNumber?
-    @NSManaged var id: UUID?
     @NSManaged var endDate: Date?
+    @NSManaged var id: UUID?
     @NSManaged var isUploadedToNS: Bool
-    @NSManaged var tempTarget: TempTargetStored?
     @NSManaged var name: String?
+    @NSManaged var startDate: Date?
+    @NSManaged var target: NSDecimalNumber?
+    @NSManaged var tempTarget: TempTargetStored?
 }
 
 extension TempTargetRunStored: Identifiable {}

+ 6 - 6
Model/Classes+Properties/TempTargetStored+CoreDataProperties.swift

@@ -6,17 +6,17 @@ public extension TempTargetStored {
         NSFetchRequest<TempTargetStored>(entityName: "TempTargetStored")
     }
 
-    @NSManaged var enabled: Bool
     @NSManaged var date: Date?
     @NSManaged var duration: NSDecimalNumber?
-    @NSManaged var target: NSDecimalNumber?
+    @NSManaged var enabled: Bool
+    @NSManaged var halfBasalTarget: NSDecimalNumber?
     @NSManaged var id: UUID?
-    @NSManaged var name: String?
-    @NSManaged var isUploadedToNS: Bool
     @NSManaged var isPreset: Bool
-    @NSManaged var halfBasalTarget: NSDecimalNumber?
-    @NSManaged var tempTargetRun: TempTargetRunStored?
+    @NSManaged var isUploadedToNS: Bool
+    @NSManaged var name: String?
     @NSManaged var orderPosition: Int16
+    @NSManaged var target: NSDecimalNumber?
+    @NSManaged var tempTargetRun: TempTargetRunStored?
 }
 
 extension TempTargetStored: Identifiable {}

+ 0 - 4
TempTargetRunStored+CoreDataClass.swift

@@ -1,4 +0,0 @@
-import CoreData
-import Foundation
-
-@objc(TempTargetRunStored) public class TempTargetRunStored: NSManagedObject {}

+ 0 - 18
TempTargetRunStored+CoreDataProperties.swift

@@ -1,18 +0,0 @@
-import CoreData
-import Foundation
-
-public extension TempTargetRunStored {
-    @nonobjc class func fetchRequest() -> NSFetchRequest<TempTargetRunStored> {
-        NSFetchRequest<TempTargetRunStored>(entityName: "TempTargetRunStored")
-    }
-
-    @NSManaged var endDate: Date?
-    @NSManaged var id: UUID?
-    @NSManaged var isUploadedToNS: Bool
-    @NSManaged var name: String?
-    @NSManaged var startDate: Date?
-    @NSManaged var target: NSDecimalNumber?
-    @NSManaged var tempTarget: TempTargetStored?
-}
-
-extension TempTargetRunStored: Identifiable {}

+ 0 - 4
TempTargetStored+CoreDataClass.swift

@@ -1,4 +0,0 @@
-import CoreData
-import Foundation
-
-@objc(TempTargetStored) public class TempTargetStored: NSManagedObject {}

+ 0 - 22
TempTargetStored+CoreDataProperties.swift

@@ -1,22 +0,0 @@
-import CoreData
-import Foundation
-
-public extension TempTargetStored {
-    @nonobjc class func fetchRequest() -> NSFetchRequest<TempTargetStored> {
-        NSFetchRequest<TempTargetStored>(entityName: "TempTargetStored")
-    }
-
-    @NSManaged var date: Date?
-    @NSManaged var duration: NSDecimalNumber?
-    @NSManaged var enabled: Bool
-    @NSManaged var halfBasalTarget: NSDecimalNumber?
-    @NSManaged var id: UUID?
-    @NSManaged var isPreset: Bool
-    @NSManaged var isUploadedToNS: Bool
-    @NSManaged var name: String?
-    @NSManaged var orderPosition: Int16
-    @NSManaged var target: NSDecimalNumber?
-    @NSManaged var tempTargetRun: TempTargetRunStored?
-}
-
-extension TempTargetStored: Identifiable {}

+ 16 - 16
Trio.xcodeproj/project.pbxproj

@@ -208,6 +208,10 @@
 		38FEF413273B317A00574A46 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FEF412273B317A00574A46 /* HKUnit.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
+		491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */; };
+		491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */; };
+		491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */; };
+		491D6FC02D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */; };
 		5075C1608E6249A51495C422 /* TargetsEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */; };
 		53F2382465BF74DB1A967C8B /* PumpConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8630D58BDAD6D9C650B9B39 /* PumpConfigProvider.swift */; };
 		581516A42BCED84A00BF67D7 /* DebuggingIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */; };
@@ -236,10 +240,6 @@
 		5887527C2BD986E1008B081D /* OpenAPSBattery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5887527B2BD986E1008B081D /* OpenAPSBattery.swift */; };
 		58A3D53A2C96D4DE003F90FC /* AddTempTargetForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A3D5392C96D4DE003F90FC /* AddTempTargetForm.swift */; };
 		58A3D5442C96DE11003F90FC /* TempTargetStored+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A3D5432C96DE11003F90FC /* TempTargetStored+Helper.swift */; };
-		58A3D5512C96EFA8003F90FC /* TempTargetStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A3D54D2C96EFA8003F90FC /* TempTargetStored+CoreDataClass.swift */; };
-		58A3D5522C96EFA8003F90FC /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A3D54E2C96EFA8003F90FC /* TempTargetStored+CoreDataProperties.swift */; };
-		58A3D5532C96EFA8003F90FC /* TempTargetRunStored+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A3D54F2C96EFA8003F90FC /* TempTargetRunStored+CoreDataClass.swift */; };
-		58A3D5542C96EFA8003F90FC /* TempTargetRunStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A3D5502C96EFA8003F90FC /* TempTargetRunStored+CoreDataProperties.swift */; };
 		58D08B222C8DAA8E00AA37D3 /* OverrideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D08B212C8DAA8E00AA37D3 /* OverrideView.swift */; };
 		58D08B302C8DEA7500AA37D3 /* ForecastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D08B2F2C8DEA7500AA37D3 /* ForecastView.swift */; };
 		58D08B322C8DF88900AA37D3 /* DummyCharts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D08B312C8DF88900AA37D3 /* DummyCharts.swift */; };
@@ -937,6 +937,10 @@
 		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
 		44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = "<group>"; };
+		491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataClass.swift"; sourceTree = "<group>"; };
+		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
+		491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = "<group>"; };
+		491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorRootView.swift; sourceTree = "<group>"; };
 		505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ISFEditorStateModel.swift; sourceTree = "<group>"; };
 		581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggingIdentifiers.swift; sourceTree = "<group>"; };
@@ -965,10 +969,6 @@
 		5887527B2BD986E1008B081D /* OpenAPSBattery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAPSBattery.swift; sourceTree = "<group>"; };
 		58A3D5392C96D4DE003F90FC /* AddTempTargetForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTempTargetForm.swift; sourceTree = "<group>"; };
 		58A3D5432C96DE11003F90FC /* TempTargetStored+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+Helper.swift"; sourceTree = "<group>"; };
-		58A3D54D2C96EFA8003F90FC /* TempTargetStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
-		58A3D54E2C96EFA8003F90FC /* TempTargetStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetStored+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
-		58A3D54F2C96EFA8003F90FC /* TempTargetRunStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
-		58A3D5502C96EFA8003F90FC /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
 		58D08B212C8DAA8E00AA37D3 /* OverrideView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideView.swift; sourceTree = "<group>"; };
 		58D08B2F2C8DEA7500AA37D3 /* ForecastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastView.swift; sourceTree = "<group>"; };
 		58D08B312C8DF88900AA37D3 /* DummyCharts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyCharts.swift; sourceTree = "<group>"; };
@@ -3034,10 +3034,10 @@
 				DDE179412C910127003CDDB7 /* StatsData+CoreDataProperties.swift */,
 				DDE179482C910127003CDDB7 /* TempBasalStored+CoreDataClass.swift */,
 				DDE179492C910127003CDDB7 /* TempBasalStored+CoreDataProperties.swift */,
-				58A3D54F2C96EFA8003F90FC /* TempTargetRunStored+CoreDataClass.swift */,
-				58A3D5502C96EFA8003F90FC /* TempTargetRunStored+CoreDataProperties.swift */,
-				58A3D54D2C96EFA8003F90FC /* TempTargetStored+CoreDataClass.swift */,
-				58A3D54E2C96EFA8003F90FC /* TempTargetStored+CoreDataProperties.swift */,
+				491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */,
+				491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */,
+				491D6FBB2D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift */,
+				491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */,
 			);
 			path = "Classes+Properties";
 			sourceTree = "<group>";
@@ -3561,7 +3561,6 @@
 				CE7CA3552A064973004BE681 /* ListStateIntent.swift in Sources */,
 				BDF530D82B40F8AC002CAF43 /* LockScreenView.swift in Sources */,
 				195D80B72AF697B800D25097 /* DynamicSettingsDataFlow.swift in Sources */,
-				58A3D5512C96EFA8003F90FC /* TempTargetStored+CoreDataClass.swift in Sources */,
 				3862CC2E2743F9F700BF832C /* CalendarManager.swift in Sources */,
 				CEA4F62329BE10F70011ADF7 /* SavitzkyGolayFilter.swift in Sources */,
 				38B4F3C325E2A20B00E76A18 /* PumpSetupView.swift in Sources */,
@@ -3606,7 +3605,6 @@
 				DD1745552C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift in Sources */,
 				384E803825C388640086DB71 /* Script.swift in Sources */,
 				CE94597E29E9E1EE0047C9C6 /* GarminManager.swift in Sources */,
-				58A3D5542C96EFA8003F90FC /* TempTargetRunStored+CoreDataProperties.swift in Sources */,
 				3883583425EEB38000E024B2 /* PumpSettings.swift in Sources */,
 				38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */,
 				DDD1631C2C4C697400CD525A /* AddOverrideForm.swift in Sources */,
@@ -3646,7 +3644,6 @@
 				389A572026079BAA00BC102F /* Interpolation.swift in Sources */,
 				DD9ECB702CA9A0BA00AA7C45 /* RemoteControlConfigStateModel.swift in Sources */,
 				19A910382A24EF3200C8951B /* ChartsView.swift in Sources */,
-				58A3D5522C96EFA8003F90FC /* TempTargetStored+CoreDataProperties.swift in Sources */,
 				DD32CF9A2CC8247B003686D6 /* TrioRemoteControl+Meal.swift in Sources */,
 				BDF34F832C10C5B600D51995 /* DataManager.swift in Sources */,
 				38B4F3C625E5017E00E76A18 /* NotificationCenter.swift in Sources */,
@@ -3818,6 +3815,10 @@
 				9825E5E923F0B8FA80C8C7C7 /* NightscoutConfigStateModel.swift in Sources */,
 				DDA6E3222D25901100C2988C /* TempTargetHelpView.swift in Sources */,
 				58645B9D2CA2D275008AFCE7 /* DeterminationSetup.swift in Sources */,
+				491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */,
+				491D6FBE2D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift in Sources */,
+				491D6FBF2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift in Sources */,
+				491D6FC02D56741C00C49F67 /* TempTargetStored+CoreDataClass.swift in Sources */,
 				DD1745442C55C60E00211FAC /* AutosensSettingsDataFlow.swift in Sources */,
 				BDCAF2382C639F35002DC907 /* SettingItems.swift in Sources */,
 				58D08B342C8DF9A700AA37D3 /* CobIobChart.swift in Sources */,
@@ -3904,7 +3905,6 @@
 				38E98A2325F52C9300C0CED0 /* Signpost.swift in Sources */,
 				CE7CA3542A064973004BE681 /* TempPresetsIntentRequest.swift in Sources */,
 				58A3D5442C96DE11003F90FC /* TempTargetStored+Helper.swift in Sources */,
-				58A3D5532C96EFA8003F90FC /* TempTargetRunStored+CoreDataClass.swift in Sources */,
 				DD6B7CB42C7B71F700B75029 /* ForecastDisplayType.swift in Sources */,
 				DD5DC9F32CF3D9DD00AB8703 /* AdjustmentsStateModel+TempTargets.swift in Sources */,
 				F5F7E6C1B7F098F59EB67EC5 /* TargetsEditorDataFlow.swift in Sources */,

File diff suppressed because it is too large
+ 1 - 1
Trio/Resources/javascript/bundle/meal.js


File diff suppressed because it is too large
+ 1 - 1
Trio/Resources/javascript/bundle/profile.js


+ 1 - 0
Trio/Resources/json/defaults/preferences.json

@@ -14,6 +14,7 @@
   "exercise_mode" : false,
   "half_basal_exercise_target" : 160,
   "maxCOB" : 120,
+  "maxMealAbsorptionTime" : 6,
   "wide_bg_target_range" : false,
   "skip_neutral_temps" : false,
   "unsuspend_if_no_temp" : false,

+ 1 - 0
Trio/Sources/Models/DecimalPickerSettings.swift

@@ -77,6 +77,7 @@ struct DecimalPickerSettings {
         type: PickerSetting.PickerSettingType.glucose
     )
     var maxCOB = PickerSetting(value: 120, step: 5, min: 0, max: 300, type: PickerSetting.PickerSettingType.gram)
+    var maxMealAbsorptionTime = PickerSetting(value: 6, step: 1, min: 4, max: 10, type: PickerSetting.PickerSettingType.hour)
     var min5mCarbimpact = PickerSetting(value: 8, step: 1, min: 1, max: 20, type: PickerSetting.PickerSettingType.glucose)
     var remainingCarbsFraction = PickerSetting(
         value: 1.0,

+ 6 - 0
Trio/Sources/Models/Preferences.swift

@@ -16,6 +16,7 @@ struct Preferences: JSON, Equatable {
     var exerciseMode: Bool = false
     var halfBasalExerciseTarget: Decimal = 160
     var maxCOB: Decimal = 120
+    var maxMealAbsorptionTime: Decimal = 6
     var wideBGTargetRange: Bool = false
     var skipNeutralTemps: Bool = false
     var unsuspendIfNoTemp: Bool = false
@@ -72,6 +73,7 @@ extension Preferences {
         case exerciseMode = "exercise_mode"
         case halfBasalExerciseTarget = "half_basal_exercise_target"
         case maxCOB
+        case maxMealAbsorptionTime
         case wideBGTargetRange = "wide_bg_target_range"
         case skipNeutralTemps = "skip_neutral_temps"
         case unsuspendIfNoTemp = "unsuspend_if_no_temp"
@@ -184,6 +186,10 @@ extension Preferences: Decodable {
             preferences.maxCOB = maxCOB
         }
 
+        if let maxMealAbsorptionTime = try? container.decode(Decimal.self, forKey: .maxMealAbsorptionTime) {
+            preferences.maxMealAbsorptionTime = maxMealAbsorptionTime
+        }
+
         if let wideBGTargetRange = try? container.decode(Bool.self, forKey: .wideBGTargetRange) {
             preferences.wideBGTargetRange = wideBGTargetRange
         }

+ 4 - 0
Trio/Sources/Modules/MealSettings/MealSettingsStateModel.swift

@@ -11,6 +11,7 @@ extension MealSettings {
         @Published var timeCap: Decimal = 8
         @Published var minuteInterval: Decimal = 30
         @Published var delay: Decimal = 60
+        @Published var maxMealAbsorptionTime: Decimal = 6
 
         override func subscribe() {
             units = settingsManager.settings.units
@@ -19,12 +20,15 @@ extension MealSettings {
             subscribeSetting(\.maxCarbs, on: $maxCarbs) { maxCarbs = $0 }
             subscribeSetting(\.maxFat, on: $maxFat) { maxFat = $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 }
+
             subscribeSetting(\.minuteInterval, on: $minuteInterval.map(Int.init), initial: {
                 minuteInterval = Decimal($0)
             }, map: {

+ 31 - 1
Trio/Sources/Modules/MealSettings/View/MealSettingsRootView.swift

@@ -162,7 +162,7 @@ extension MealSettings {
                                             AnyView(
                                                 VStack(alignment: .leading, spacing: 5) {
                                                     Text("Max Carbs:").bold()
-                                                    Text("Enter the largest carbohydrate value allowed per meal entry")
+                                                    Text("Enter the largest carb value allowed per meal entry")
                                                     Text("Max Fat:").bold()
                                                     Text("Enter the largest fat value allowed per meal entry")
                                                     Text("Max Protein:").bold()
@@ -183,6 +183,36 @@ extension MealSettings {
                 ).listRowBackground(Color.chart)
 
                 SettingInputSection(
+                    decimalValue: $state.maxMealAbsorptionTime,
+                    booleanValue: $booleanPlaceholder,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0.map { AnyView($0) }
+                            hintLabel = "Maximum Meal Absorption Time"
+                        }
+                    ),
+                    units: state.units,
+                    type: .decimal("maxMealAbsorptionTime"),
+                    label: "Max Meal Absorption Time",
+                    miniHint: "The maximum duration for tracking carb entries in estimating Carbs on Board (COB)",
+                    verboseHint:
+                    VStack(alignment: .leading, spacing: 10) {
+                        Text("Default: 6 hours").bold()
+                        Text(
+                            "Carb entries will be fully decayed by the number of hours specified as Max Meal Absorption Time. Meals that are high in fat and/or protein can have long lasting effects on BG levels. To allow such late meal effects to be considered by the carb decay model, a longer Max Meal Absorption Time than the default 6 hours can be set."
+                        )
+                        Text(
+                            "If carb entries decay too slowly, it is possible to set a lower than default setting. But this should typically be adressed by tuning ISF and CR settings instead, which in combination determines the rate of carb decay."
+                        )
+                        Text(
+                            "Min 4 hours, max 10 hours."
+                        )
+                    }
+                )
+
+                SettingInputSection(
                     decimalValue: $decimalPlaceholder,
                     booleanValue: $state.useFPUconversion,
                     shouldDisplayHint: $shouldDisplayHint,

+ 1 - 0
Trio/Sources/Modules/Settings/SettingItems.swift

@@ -171,6 +171,7 @@ enum SettingItems {
             view: .mealSettings,
             searchContents: [
                 "Max Carbs",
+                "Max Meal Absorption Time",
                 "Max Fat",
                 "Max Protein",
                 "Display and Allow Fat and Protein Entries",

+ 2 - 0
Trio/Sources/Services/WatchManager/AppleWatchManager.swift

@@ -607,6 +607,7 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
                 carbEntry.date = date
                 carbEntry.note = "Via Watch"
                 carbEntry.isFPU = false // set this to false to ensure watch-entered carbs are displayed in main chart
+                carbEntry.isUploadedToNS = false
 
                 do {
                     guard context.hasChanges else { return }
@@ -646,6 +647,7 @@ final class BaseWatchManager: NSObject, WCSessionDelegate, Injectable, WatchMana
                     carbEntry.date = date
                     carbEntry.note = "Via Watch"
                     carbEntry.isFPU = false // set this to false to ensure watch-entered carbs are displayed in main chart
+                    carbEntry.isUploadedToNS = false
 
                     guard context.hasChanges else { return }
                     try context.save()

+ 2 - 0
Trio/Sources/Views/SettingInputSection.swift

@@ -107,6 +107,8 @@ struct SettingInputSection<VerboseHint: View>: View {
             return pickerSettingsProvider.settings.hours
         case "maxCarbs":
             return pickerSettingsProvider.settings.maxCarbs
+        case "maxMealAbsorptionTime":
+            return pickerSettingsProvider.settings.maxMealAbsorptionTime
         case "maxFat":
             return pickerSettingsProvider.settings.maxFat
         case "maxProtein":

+ 7 - 1
oref0_source_version.txt

@@ -1,6 +1,12 @@
-oref0 branch: tdd-pumpdataCheck - git version: 46deecb
+oref0 branch: maxAbsorptionTime - git version: a542ed3
 
 Last commits:
+a542ed3 use guarded maxAbsorptionTime
+4c77757 Revert "reduce dynISF logging"
+1567c76 use variable name maxMealAbsorptionTime
+61b4f85 reduce dynISF logging
+0fe81c1 introduce maxAbsorptionTime to orefmaxAbsorptionTime
+ade267d Merge pull request #37 from mountrcg/tdd-pumpdataCheck
 46deecb remove dynisf check on pumpdata calc
 2f258b2 Merge pull request #36 from mountrcg/fixTDDcheck
 4998a09 fix condition  to use weightedAverage as TDD

+ 3 - 2
trio-oref/lib/determine-basal/cob.js

@@ -12,7 +12,8 @@ function detectCarbAbsorption(inputs) {
     });
     var iob_inputs = inputs.iob_inputs;
     var basalprofile = inputs.basalprofile;
-    /* TODO why does declaring profile break tests-command-behavior.tests.sh? */ profile = inputs.iob_inputs.profile;
+    /* TODO why does declaring profile break tests-command-behavior.tests.sh? */
+    profile = inputs.iob_inputs.profile;
     var mealTime = new Date(inputs.mealTime);
     var ciTime = new Date(inputs.ciTime);
 
@@ -50,7 +51,7 @@ function detectCarbAbsorption(inputs) {
         }
         // only consider BGs for 6h after a meal for calculating COB
         var hoursAfterMeal = (bgTime-mealTime)/(60*60*1000);
-        if (hoursAfterMeal > 6 || foundPreMealBG) {
+        if (hoursAfterMeal > profile.maxMealAbsorptionTime || foundPreMealBG) {
             continue;
         } else if (hoursAfterMeal < 0) {
 //console.error("Found pre-meal BG:",glucose_data[i].glucose, bgTime, Math.round(hoursAfterMeal*100)/100);

+ 21 - 6
trio-oref/lib/meal/total.js

@@ -1,6 +1,12 @@
 var tz = require('moment-timezone');
 var calcMealCOB = require('../determine-basal/cob');
 
+function round(value, digits) {
+    if (! digits) { digits = 0; }
+    var scale = Math.pow(10, digits);
+    return Math.round(value * scale) / scale;
+}
+
 function recentCarbs(opts, time) {
     var treatments = opts.treatments;
     var profile_data = opts.profile;
@@ -41,10 +47,18 @@ function recentCarbs(opts, time) {
     var nsCarbsToRemove = 0;
     var bwCarbsToRemove = 0;
     var journalCarbsToRemove = 0;
+    var maxMealAbsorptionTime = 6;
+
+    if (typeof(profile_data.maxMealAbsorptionTime) === 'number' && ! isNaN(profile_data.maxMealAbsorptionTime)) {
+        maxMealAbsorptionTime = profile_data.maxMealAbsorptionTime;
+    } else {
+        console.error("Bad profile.maxMealAbsorptionTime:",profile_data.maxMealAbsorptionTime);
+    }
+
     treatments.forEach(function(treatment) {
         var now = time.getTime();
-        // consider carbs from up to 6 hours ago in calculating COB
-        var carbWindow = now - 6 * 60*60*1000;
+        // consider carbs from up to the meal preference maxMealAbsorptionTime hours ago in calculating COB
+        var carbWindow = now - maxMealAbsorptionTime * 60*60*1000;
         var treatmentDate = new Date(tz(treatment.timestamp));
         var treatmentTime = treatmentDate.getTime();
         if (treatmentTime > carbWindow && treatmentTime <= now) {
@@ -98,15 +112,16 @@ function recentCarbs(opts, time) {
     // calculate the current deviation and steepest deviation downslope over the last hour
     COB_inputs.ciTime = time.getTime();
     // set mealTime to 6h ago for Deviation calculations
-    COB_inputs.mealTime = time.getTime() - 6 * 60 * 60 * 1000;
+    COB_inputs.mealTime = time.getTime() - maxMealAbsorptionTime * 60 * 60 * 1000;
     var c = calcMealCOB(COB_inputs);
     //console.error(c.currentDeviation, c.slopeFromMaxDeviation);
 
     // set a hard upper limit on COB to mitigate impact of erroneous or malicious carb entry
-    if (typeof(profile.maxCOB) === 'number' && ! isNaN(profile.maxCOB)) {
-        mealCOB = Math.min( profile.maxCOB, mealCOB );
+    if (typeof(profile_data.maxCOB) === 'number' && ! isNaN(profile_data.maxCOB)) {
+        mealCOB = Math.min( profile_data.maxCOB, mealCOB );
+        console.error("mealCOB: " + round(mealCOB,1) + " with maxCOB " + profile_data.maxCOB + "g and maxMealAbsorptionTime " + maxMealAbsorptionTime + "hrs.");
     } else {
-        console.error("Bad profile.maxCOB:",profile.maxCOB);
+        console.error("Bad profile.maxCOB:",profile_data.maxCOB);
     }
 
     // if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety

+ 4 - 1
trio-oref/lib/profile/index.js

@@ -25,6 +25,7 @@ function defaults ( ) {
     // (If someone enters more carbs or stacks more; OpenAPS will just truncate dosing based on 120.
     // Essentially, this just limits AMA/SMB as a safety cap against excessive COB entry)
     , maxCOB: 120
+    , maxMealAbsorptionTime: 6 // Handling of long lasting effects of "heavy meals" containing large cqantities of fat and protein might be improved by letting the system consider meal effects for longer than the default six hours.
     , skip_neutral_temps: false // if true, don't set neutral temps
     , unsuspend_if_no_temp: false // if true, pump will un-suspend after a zero temp finishes
     , min_5m_carbimpact: 8 // mg/dL per 5m (8 mg/dL/5m corresponds to 24g/hr at a CSF of 4 mg/dL/g (x/5*60/4))
@@ -74,7 +75,7 @@ function defaults ( ) {
     , useNewFormula: false
     , enableDynamicCR: false
     , sigmoid: false
-    , weightPercentage: 0.65 
+    , weightPercentage: 0.65
     , tddAdjBasal: false // Enable adjustment of basal based on the ratio of 24 h : 10 day average TDD
     , threshold_setting: 60 // Use a configurable threshold setting
   }
@@ -111,6 +112,8 @@ function displayedDefaults () {
     profile.threshold_setting = allDefaults.threshold_setting;
     profile.enableSMB_high_bg = allDefaults.enableSMB_high_bg;
     profile.enableSMB_high_bg_target = allDefaults.enableSMB_high_bg_target;
+    profile.maxCOB = allDefaults.maxCOB;
+    profile.maxMealAbsorptionTime = allDefaults.maxMealAbsorptionTime;
 
     console.error(profile);
     return profile