Explorar o código

Added new sub setting views and custom views
* SMB Settings View created
* New reusable view element SettingInputSection created
* New reusable view element SettingInputHint created
* Added 3 settings to new SMB Setting view to test it all out
* WIP

Deniz Cengiz hai 1 ano
pai
achega
d7abf0740a

+ 52 - 12
FreeAPS.xcodeproj/project.pbxproj

@@ -390,6 +390,12 @@
 		DD1745172C54389F00211FAC /* FeatureSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745162C54389F00211FAC /* FeatureSettingsView.swift */; };
 		DD1745172C54389F00211FAC /* FeatureSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745162C54389F00211FAC /* FeatureSettingsView.swift */; };
 		DD1745192C543B5700211FAC /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745182C543B5700211FAC /* NotificationsView.swift */; };
 		DD1745192C543B5700211FAC /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745182C543B5700211FAC /* NotificationsView.swift */; };
 		DD17451D2C543C5F00211FAC /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17451C2C543C5F00211FAC /* ServicesView.swift */; };
 		DD17451D2C543C5F00211FAC /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17451C2C543C5F00211FAC /* ServicesView.swift */; };
+		DD1745202C55523E00211FAC /* SMBSettingsDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17451F2C55523E00211FAC /* SMBSettingsDataFlow.swift */; };
+		DD1745222C55524800211FAC /* SMBSettingsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745212C55524800211FAC /* SMBSettingsProvider.swift */; };
+		DD1745242C55526000211FAC /* SMBSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745232C55526000211FAC /* SMBSettingsStateModel.swift */; };
+		DD1745262C55526F00211FAC /* SMBSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745252C55526F00211FAC /* SMBSettingsView.swift */; };
+		DD1745292C55642100211FAC /* SettingInputSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745282C55642100211FAC /* SettingInputSection.swift */; };
+		DD17452B2C556E8100211FAC /* SettingInputHintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17452A2C556E8100211FAC /* SettingInputHintView.swift */; };
 		DD1DB7CC2BECCA1F0048B367 /* BuildDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */; };
 		DD1DB7CC2BECCA1F0048B367 /* BuildDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */; };
 		DD399FB31EACB9343C944C4C /* PreferencesEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA3E609094E064C99A4752C /* PreferencesEditorStateModel.swift */; };
 		DD399FB31EACB9343C944C4C /* PreferencesEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA3E609094E064C99A4752C /* PreferencesEditorStateModel.swift */; };
 		DD57C4B22C4C7103001A5B28 /* LoopStatRecord+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD57C4902C4C7103001A5B28 /* LoopStatRecord+CoreDataClass.swift */; };
 		DD57C4B22C4C7103001A5B28 /* LoopStatRecord+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD57C4902C4C7103001A5B28 /* LoopStatRecord+CoreDataClass.swift */; };
@@ -997,6 +1003,12 @@
 		DD1745162C54389F00211FAC /* FeatureSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureSettingsView.swift; sourceTree = "<group>"; };
 		DD1745162C54389F00211FAC /* FeatureSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureSettingsView.swift; sourceTree = "<group>"; };
 		DD1745182C543B5700211FAC /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
 		DD1745182C543B5700211FAC /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
 		DD17451C2C543C5F00211FAC /* ServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = "<group>"; };
 		DD17451C2C543C5F00211FAC /* ServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = "<group>"; };
+		DD17451F2C55523E00211FAC /* SMBSettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBSettingsDataFlow.swift; sourceTree = "<group>"; };
+		DD1745212C55524800211FAC /* SMBSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBSettingsProvider.swift; sourceTree = "<group>"; };
+		DD1745232C55526000211FAC /* SMBSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBSettingsStateModel.swift; sourceTree = "<group>"; };
+		DD1745252C55526F00211FAC /* SMBSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBSettingsView.swift; sourceTree = "<group>"; };
+		DD1745282C55642100211FAC /* SettingInputSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingInputSection.swift; sourceTree = "<group>"; };
+		DD17452A2C556E8100211FAC /* SettingInputHintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingInputHintView.swift; sourceTree = "<group>"; };
 		DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildDetails.swift; sourceTree = "<group>"; };
 		DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildDetails.swift; sourceTree = "<group>"; };
 		DD57C4902C4C7103001A5B28 /* LoopStatRecord+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoopStatRecord+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
 		DD57C4902C4C7103001A5B28 /* LoopStatRecord+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoopStatRecord+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
 		DD57C4912C4C7103001A5B28 /* LoopStatRecord+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoopStatRecord+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
 		DD57C4912C4C7103001A5B28 /* LoopStatRecord+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoopStatRecord+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
@@ -1337,37 +1349,38 @@
 		3811DE0325C9D31700A708ED /* Modules */ = {
 		3811DE0325C9D31700A708ED /* Modules */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				110AEDEA2C51A0AE00615CC9 /* ShortcutsConfig */,
-				DDD163032C4C67B400CD525A /* OverrideConfig */,
-				195D80B22AF696EE00D25097 /* Dynamic */,
-				BD7DA9A32AE06DBA00601B20 /* BolusCalculatorConfig */,
-				CEE9A64D2BBB411C00EB5194 /* Calibrations */,
-				190EBCC229FF134900BA767D /* StatConfig */,
-				19F95FF129F10F9C00314DDC /* Stat */,
-				CE94597C29E9E1CD0047C9C6 /* WatchConfig */,
-				19E1F7E629D0828B005C8D20 /* IconConfig */,
-				19D466A129AA2B0A004D5F33 /* FPUConfig */,
-				F90692CD274B99850037068D /* HealthKit */,
+				DD17451E2C55520000211FAC /* SMBSettings */,
 				672F63EEAE27400625E14BAD /* AutotuneConfig */,
 				672F63EEAE27400625E14BAD /* AutotuneConfig */,
 				A42F1FEDFFD0DDE00AAD54D3 /* BasalProfileEditor */,
 				A42F1FEDFFD0DDE00AAD54D3 /* BasalProfileEditor */,
 				3811DE0425C9D32E00A708ED /* Base */,
 				3811DE0425C9D32E00A708ED /* Base */,
+				C2C98283C436DB934D7E7994 /* Bolus */,
+				BD7DA9A32AE06DBA00601B20 /* BolusCalculatorConfig */,
+				CEE9A64D2BBB411C00EB5194 /* Calibrations */,
 				F75CB57ED6971B46F8756083 /* CGM */,
 				F75CB57ED6971B46F8756083 /* CGM */,
 				0610F7D6D2EC00E3BA1569F0 /* ConfigEditor */,
 				0610F7D6D2EC00E3BA1569F0 /* ConfigEditor */,
 				E42231DBF0DBE2B4B92D1B15 /* CREditor */,
 				E42231DBF0DBE2B4B92D1B15 /* CREditor */,
 				9E56E3626FAD933385101B76 /* DataTable */,
 				9E56E3626FAD933385101B76 /* DataTable */,
-				C2C98283C436DB934D7E7994 /* Bolus */,
+				195D80B22AF696EE00D25097 /* Dynamic */,
+				19D466A129AA2B0A004D5F33 /* FPUConfig */,
+				F90692CD274B99850037068D /* HealthKit */,
 				3811DE2725C9D49500A708ED /* Home */,
 				3811DE2725C9D49500A708ED /* Home */,
+				19E1F7E629D0828B005C8D20 /* IconConfig */,
 				D8F047E14D567F2B5DBEFD96 /* ISFEditor */,
 				D8F047E14D567F2B5DBEFD96 /* ISFEditor */,
 				3811DE1A25C9D48300A708ED /* Main */,
 				3811DE1A25C9D48300A708ED /* Main */,
 				5031FE61F63C2A8A8B7674DD /* ManualTempBasal */,
 				5031FE61F63C2A8A8B7674DD /* ManualTempBasal */,
 				D533BF261CDC1C3F871E7BFD /* NightscoutConfig */,
 				D533BF261CDC1C3F871E7BFD /* NightscoutConfig */,
 				F66B236E00924A05D6A9F9DF /* NotificationsConfig */,
 				F66B236E00924A05D6A9F9DF /* NotificationsConfig */,
+				DDD163032C4C67B400CD525A /* OverrideConfig */,
 				3E1C41D9301B7058AA7BF5EA /* PreferencesEditor */,
 				3E1C41D9301B7058AA7BF5EA /* PreferencesEditor */,
 				99C01B871ACAB3F32CE755C7 /* PumpConfig */,
 				99C01B871ACAB3F32CE755C7 /* PumpConfig */,
 				E493126EA71765130F64CCE5 /* PumpSettingsEditor */,
 				E493126EA71765130F64CCE5 /* PumpSettingsEditor */,
 				3811DE3825C9D4A100A708ED /* Settings */,
 				3811DE3825C9D4A100A708ED /* Settings */,
+				110AEDEA2C51A0AE00615CC9 /* ShortcutsConfig */,
 				29B478DF61BF8D270F7D8954 /* Snooze */,
 				29B478DF61BF8D270F7D8954 /* Snooze */,
+				19F95FF129F10F9C00314DDC /* Stat */,
+				190EBCC229FF134900BA767D /* StatConfig */,
 				6517011F19F244F64E1FF14B /* TargetsEditor */,
 				6517011F19F244F64E1FF14B /* TargetsEditor */,
+				CE94597C29E9E1CD0047C9C6 /* WatchConfig */,
 			);
 			);
 			path = Modules;
 			path = Modules;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1707,6 +1720,8 @@
 				38EA05FF262091870064E39B /* BolusProgressViewStyle.swift */,
 				38EA05FF262091870064E39B /* BolusProgressViewStyle.swift */,
 				38DF1785276A73D400B3528F /* TagCloudView.swift */,
 				38DF1785276A73D400B3528F /* TagCloudView.swift */,
 				DD88C8E12C50420800F2D558 /* DefinitionRow.swift */,
 				DD88C8E12C50420800F2D558 /* DefinitionRow.swift */,
+				DD1745282C55642100211FAC /* SettingInputSection.swift */,
+				DD17452A2C556E8100211FAC /* SettingInputHintView.swift */,
 			);
 			);
 			path = Views;
 			path = Views;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -2417,6 +2432,25 @@
 			path = Subviews;
 			path = Subviews;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		DD17451E2C55520000211FAC /* SMBSettings */ = {
+			isa = PBXGroup;
+			children = (
+				DD1745272C5553C400211FAC /* View */,
+				DD17451F2C55523E00211FAC /* SMBSettingsDataFlow.swift */,
+				DD1745212C55524800211FAC /* SMBSettingsProvider.swift */,
+				DD1745232C55526000211FAC /* SMBSettingsStateModel.swift */,
+			);
+			path = SMBSettings;
+			sourceTree = "<group>";
+		};
+		DD1745272C5553C400211FAC /* View */ = {
+			isa = PBXGroup;
+			children = (
+				DD1745252C55526F00211FAC /* SMBSettingsView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		DD57C46C2C4C7003001A5B28 /* Classes+Properties */ = {
 		DD57C46C2C4C7003001A5B28 /* Classes+Properties */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -2932,6 +2966,7 @@
 				38B4F3CD25E5031100E76A18 /* Broadcaster.swift in Sources */,
 				38B4F3CD25E5031100E76A18 /* Broadcaster.swift in Sources */,
 				383420D925FFEB3F002D46C1 /* Popup.swift in Sources */,
 				383420D925FFEB3F002D46C1 /* Popup.swift in Sources */,
 				110AEDEE2C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift in Sources */,
 				110AEDEE2C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift in Sources */,
+				DD1745262C55526F00211FAC /* SMBSettingsView.swift in Sources */,
 				3811DE3025C9D49500A708ED /* HomeStateModel.swift in Sources */,
 				3811DE3025C9D49500A708ED /* HomeStateModel.swift in Sources */,
 				38BF021725E7CBBC00579895 /* PumpManagerExtensions.swift in Sources */,
 				38BF021725E7CBBC00579895 /* PumpManagerExtensions.swift in Sources */,
 				CEE9A6552BBB418300EB5194 /* CalibrationsProvider.swift in Sources */,
 				CEE9A6552BBB418300EB5194 /* CalibrationsProvider.swift in Sources */,
@@ -2984,6 +3019,7 @@
 				BDF34F832C10C5B600D51995 /* DataManager.swift in Sources */,
 				BDF34F832C10C5B600D51995 /* DataManager.swift in Sources */,
 				38B4F3C625E5017E00E76A18 /* NotificationCenter.swift in Sources */,
 				38B4F3C625E5017E00E76A18 /* NotificationCenter.swift in Sources */,
 				19D466A729AA2C22004D5F33 /* FPUConfigStateModel.swift in Sources */,
 				19D466A729AA2C22004D5F33 /* FPUConfigStateModel.swift in Sources */,
+				DD17452B2C556E8100211FAC /* SettingInputHintView.swift in Sources */,
 				38E44528274E401C00EC9A94 /* Protected.swift in Sources */,
 				38E44528274E401C00EC9A94 /* Protected.swift in Sources */,
 				3811DEB625C9D88300A708ED /* UnlockManager.swift in Sources */,
 				3811DEB625C9D88300A708ED /* UnlockManager.swift in Sources */,
 				581516A42BCED84A00BF67D7 /* DebuggingIdentifiers.swift in Sources */,
 				581516A42BCED84A00BF67D7 /* DebuggingIdentifiers.swift in Sources */,
@@ -3158,6 +3194,7 @@
 				38FEF3FE2738083E00574A46 /* CGMProvider.swift in Sources */,
 				38FEF3FE2738083E00574A46 /* CGMProvider.swift in Sources */,
 				38E98A3725F5509500C0CED0 /* String+Extensions.swift in Sources */,
 				38E98A3725F5509500C0CED0 /* String+Extensions.swift in Sources */,
 				CC76E9512BD4812E008BEB61 /* Forecast+helper.swift in Sources */,
 				CC76E9512BD4812E008BEB61 /* Forecast+helper.swift in Sources */,
+				DD1745242C55526000211FAC /* SMBSettingsStateModel.swift in Sources */,
 				F90692D1274B99B60037068D /* HealthKitProvider.swift in Sources */,
 				F90692D1274B99B60037068D /* HealthKitProvider.swift in Sources */,
 				19F95FF729F10FEE00314DDC /* StatStateModel.swift in Sources */,
 				19F95FF729F10FEE00314DDC /* StatStateModel.swift in Sources */,
 				385CEAC125F2EA52002D6D5B /* Announcement.swift in Sources */,
 				385CEAC125F2EA52002D6D5B /* Announcement.swift in Sources */,
@@ -3244,6 +3281,7 @@
 				BDF34F852C10C62E00D51995 /* GlucoseData.swift in Sources */,
 				BDF34F852C10C62E00D51995 /* GlucoseData.swift in Sources */,
 				19E1F7EC29D082FE005C8D20 /* IconConfigStateModel.swift in Sources */,
 				19E1F7EC29D082FE005C8D20 /* IconConfigStateModel.swift in Sources */,
 				711C0CB42CAABE788916BC9D /* ManualTempBasalDataFlow.swift in Sources */,
 				711C0CB42CAABE788916BC9D /* ManualTempBasalDataFlow.swift in Sources */,
+				DD1745222C55524800211FAC /* SMBSettingsProvider.swift in Sources */,
 				BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */,
 				BF1667ADE69E4B5B111CECAE /* ManualTempBasalProvider.swift in Sources */,
 				583684062BD178DB00070A60 /* GlucoseStored+helper.swift in Sources */,
 				583684062BD178DB00070A60 /* GlucoseStored+helper.swift in Sources */,
 				F90692D6274B9A450037068D /* HealthKitStateModel.swift in Sources */,
 				F90692D6274B9A450037068D /* HealthKitStateModel.swift in Sources */,
@@ -3267,7 +3305,9 @@
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
 				195D80B92AF697F700D25097 /* DynamicProvider.swift in Sources */,
 				195D80B92AF697F700D25097 /* DynamicProvider.swift in Sources */,
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
+				DD1745202C55523E00211FAC /* SMBSettingsDataFlow.swift in Sources */,
 				D6D02515BBFBE64FEBE89856 /* DataTableRootView.swift in Sources */,
 				D6D02515BBFBE64FEBE89856 /* DataTableRootView.swift in Sources */,
+				DD1745292C55642100211FAC /* SettingInputSection.swift in Sources */,
 				38569349270B5DFB0002C50D /* AppGroupSource.swift in Sources */,
 				38569349270B5DFB0002C50D /* AppGroupSource.swift in Sources */,
 				F5CA3DB1F9DC8B05792BBFAA /* CGMDataFlow.swift in Sources */,
 				F5CA3DB1F9DC8B05792BBFAA /* CGMDataFlow.swift in Sources */,
 				BDF34F952C10D27300D51995 /* DeterminationData.swift in Sources */,
 				BDF34F952C10D27300D51995 /* DeterminationData.swift in Sources */,

+ 5 - 0
FreeAPS/Sources/Modules/SMBSettings/SMBSettingsDataFlow.swift

@@ -0,0 +1,5 @@
+enum SMBSettings {
+    enum Config {}
+}
+
+protocol SMBSettingsProvider: Provider {}

+ 3 - 0
FreeAPS/Sources/Modules/SMBSettings/SMBSettingsProvider.swift

@@ -0,0 +1,3 @@
+extension SMBSettings {
+    final class Provider: BaseProvider, SMBSettingsProvider {}
+}

+ 86 - 0
FreeAPS/Sources/Modules/SMBSettings/SMBSettingsStateModel.swift

@@ -0,0 +1,86 @@
+import SwiftUI
+
+extension SMBSettings {
+    final class StateModel: BaseStateModel<Provider> {
+        @Injected() var settings: SettingsManager!
+        @Injected() var storage: FileStorage!
+
+        @Published var units: GlucoseUnits = .mgdL
+        @Published var enableSMBAlways: Bool = false
+        @Published var maxDeltaBGthreshold: Decimal = 0.2
+        @Published var enableSMBWithCOB: Bool = false
+        @Published var enableSMBWithTemptarget: Bool = false
+        @Published var enableSMBAfterCarbs: Bool = false
+        @Published var allowSMBWithHighTemptarget: Bool = false
+        @Published var enableSMB_high_bg: Bool = false
+        @Published var enableSMB_high_bg_target: Decimal = 100
+        @Published var maxSMBBasalMinutes: Decimal = 30
+        @Published var smbDeliveryRatio: Decimal = 0.5
+        @Published var smbInterval: Decimal = 3
+        @Published var bolusIncrement: Decimal = 0.1 // get this from pump, dafuq?: Bool = false
+        @Published var enableUAM: Bool = false
+        @Published var maxUAMSMBBasalMinutes: Decimal = 30
+
+        var preferences: Preferences {
+            settingsManager.preferences
+        }
+
+        override func subscribe() {
+            units = settingsManager.settings.units
+            enableSMBAlways = settings.preferences.enableSMBAlways
+            maxDeltaBGthreshold = settings.preferences.maxDeltaBGthreshold
+            enableSMBWithCOB = settings.preferences.enableSMBWithCOB
+            enableSMBWithTemptarget = settings.preferences.enableSMBWithTemptarget
+            enableSMBAfterCarbs = settings.preferences.enableSMBAfterCarbs
+            allowSMBWithHighTemptarget = settings.preferences.allowSMBWithHighTemptarget
+            enableSMB_high_bg = settings.preferences.enableSMB_high_bg
+            enableSMB_high_bg_target = units == .mmolL ? settings.preferences.enableSMB_high_bg_target.asMmolL : settings
+                .preferences.enableSMB_high_bg_target
+            maxSMBBasalMinutes = settings.preferences.maxSMBBasalMinutes
+            smbDeliveryRatio = settings.preferences.smbDeliveryRatio
+            smbInterval = settings.preferences.smbInterval
+            bolusIncrement = settings.preferences.bolusIncrement
+            enableUAM = settings.preferences.enableUAM
+            maxUAMSMBBasalMinutes = settings.preferences.maxUAMSMBBasalMinutes
+        }
+
+        var isSettingUnchanged: Bool {
+            preferences.enableSMBAlways == enableSMBAlways &&
+                preferences.maxDeltaBGthreshold == maxDeltaBGthreshold &&
+                preferences.enableSMBWithCOB == enableSMBWithCOB &&
+                preferences.enableSMBWithTemptarget == enableSMBWithTemptarget &&
+                preferences.enableSMBAfterCarbs == enableSMBAfterCarbs &&
+                preferences.allowSMBWithHighTemptarget == allowSMBWithHighTemptarget &&
+                preferences.enableSMB_high_bg == enableSMB_high_bg &&
+                preferences.enableSMB_high_bg_target == enableSMB_high_bg_target &&
+                preferences.maxSMBBasalMinutes == maxSMBBasalMinutes &&
+                preferences.smbDeliveryRatio == smbDeliveryRatio &&
+                preferences.smbInterval == smbInterval &&
+                preferences.bolusIncrement == bolusIncrement &&
+                preferences.enableUAM == enableUAM &&
+                preferences.maxUAMSMBBasalMinutes == maxUAMSMBBasalMinutes
+        }
+
+        func saveIfChanged() {
+            if !isSettingUnchanged {
+                var newSettings = storage.retrieve(OpenAPS.Settings.preferences, as: Preferences.self) ?? Preferences()
+                newSettings.enableSMBAlways = enableSMBAlways
+                newSettings.maxDeltaBGthreshold = maxDeltaBGthreshold
+                newSettings.enableSMBWithCOB = enableSMBWithCOB
+                newSettings.enableSMBWithTemptarget = enableSMBWithTemptarget
+                newSettings.enableSMBAfterCarbs = enableSMBAfterCarbs
+                newSettings.allowSMBWithHighTemptarget = allowSMBWithHighTemptarget
+                newSettings.enableSMB_high_bg = enableSMB_high_bg
+                newSettings.enableSMB_high_bg_target = enableSMB_high_bg_target
+                newSettings.maxSMBBasalMinutes = maxSMBBasalMinutes
+                newSettings.smbDeliveryRatio = smbDeliveryRatio
+                newSettings.smbInterval = smbInterval
+                newSettings.bolusIncrement = bolusIncrement
+                newSettings.enableUAM = enableUAM
+                newSettings.maxUAMSMBBasalMinutes = maxUAMSMBBasalMinutes
+                newSettings.timestamp = Date()
+                storage.save(newSettings, as: OpenAPS.Settings.preferences)
+            }
+        }
+    }
+}

+ 122 - 0
FreeAPS/Sources/Modules/SMBSettings/View/SMBSettingsView.swift

@@ -0,0 +1,122 @@
+import HealthKit
+import LoopKit
+import LoopKitUI
+import SwiftUI
+import Swinject
+
+extension SMBSettings {
+    struct RootView: BaseView {
+        let resolver: Resolver
+        @StateObject var state = StateModel()
+        @State private var showHint: Bool = false
+        @State var hintDetent = PresentationDetent.large
+        @State var selectedVerboseHint: String?
+        @State var hintLabel: String?
+        @State private var decimalPlaceholder: Decimal = 0.0
+        @State private var booleanPlaceholder: Bool = false
+
+        @Environment(\.colorScheme) var colorScheme
+        @EnvironmentObject var appIcons: Icons
+
+        private var color: LinearGradient {
+            colorScheme == .dark ? LinearGradient(
+                gradient: Gradient(colors: [
+                    Color.bgDarkBlue,
+                    Color.bgDarkerDarkBlue
+                ]),
+                startPoint: .top,
+                endPoint: .bottom
+            )
+                :
+                LinearGradient(
+                    gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
+                    startPoint: .top,
+                    endPoint: .bottom
+                )
+        }
+
+        private var formatter: NumberFormatter {
+            let formatter = NumberFormatter()
+            formatter.numberStyle = .decimal
+            return formatter
+        }
+
+        var body: some View {
+            List {
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.enableSMBAlways,
+                    showHint: $showHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = NSLocalizedString("Enable SMB Always", comment: "Enable SMB Always")
+                        }
+                    ),
+                    type: .boolean,
+                    label: NSLocalizedString("Enable SMB Always", comment: "Enable SMB Always"),
+                    shortHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                    verboseHint: "Enable SMB always bla bla bla",
+                    headerText: "Super-Micro-Bolus",
+                    footerText: nil
+                )
+
+                if state.enableSMBAlways {
+                    SettingInputSection(
+                        decimalValue: $state.maxDeltaBGthreshold,
+                        booleanValue: $booleanPlaceholder,
+                        showHint: $showHint,
+                        selectedVerboseHint: Binding(
+                            get: { selectedVerboseHint },
+                            set: {
+                                selectedVerboseHint = $0
+                                hintLabel = NSLocalizedString("Max Delta-BG Threshold SMB", comment: "Max Delta-BG Threshold")
+                            }
+                        ),
+                        type: .decimal,
+                        label: NSLocalizedString("Max Delta-BG Threshold SMB", comment: "Max Delta-BG Threshold"),
+                        shortHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                        verboseHint: "Max Delta BG bla bla bla",
+                        headerText: nil,
+                        footerText: nil
+                    )
+
+                    SettingInputSection(
+                        decimalValue: $decimalPlaceholder,
+                        booleanValue: $state.enableSMBWithCOB,
+                        showHint: $showHint,
+                        selectedVerboseHint: Binding(
+                            get: { selectedVerboseHint },
+                            set: {
+                                selectedVerboseHint = $0
+                                hintLabel = NSLocalizedString("Enable SMB With COB", comment: "Enable SMB With COB")
+                            }
+                        ),
+                        type: .boolean,
+                        label: NSLocalizedString("Enable SMB With COB", comment: "Enable SMB With COB"),
+                        shortHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                        verboseHint: "Enable SMB for COB bla bla bla bla",
+                        headerText: nil,
+                        footerText: nil
+                    )
+                }
+            }
+            .sheet(isPresented: $showHint) {
+                SettingInputHintView(
+                    hintDetent: $hintDetent,
+                    showHint: $showHint,
+                    hintLabel: hintLabel ?? "",
+                    hintText: selectedVerboseHint ?? "",
+                    sheetTitle: "Hint"
+                )
+            }
+            .scrollContentBackground(.hidden).background(color)
+            .navigationTitle("SMB Settings")
+            .navigationBarTitleDisplayMode(.automatic)
+//            .onDisappear {
+//                state.saveIfChanged()
+//            }
+        }
+    }
+}

+ 10 - 2
FreeAPS/Sources/Modules/Settings/View/Subviews/FeatureSettingsView.swift

@@ -37,8 +37,8 @@ struct FeatureSettingsView: BaseView {
                 header: Text("Oref Algorithm"),
                 header: Text("Oref Algorithm"),
                 content: {
                 content: {
                     Text("Preferences (to be omitted").navigationLink(to: .preferencesEditor, from: self)
                     Text("Preferences (to be omitted").navigationLink(to: .preferencesEditor, from: self)
-                    Text("Autosens Settings")
-                    Text("Super-Micro-Bolus (SMB) Settings")
+                    Text("Autosens Settings").navigationLink(to: .preferencesEditor, from: self)
+                    Text("Super-Micro-Bolus (SMB) Settings").navigationLink(to: .smbSettings, from: self)
                     Text("Dynamic Settings").navigationLink(to: .dynamicISF, from: self)
                     Text("Dynamic Settings").navigationLink(to: .dynamicISF, from: self)
                 }
                 }
             ).listRowBackground(Color.chart)
             ).listRowBackground(Color.chart)
@@ -55,6 +55,14 @@ struct FeatureSettingsView: BaseView {
                 }
                 }
             )
             )
             .listRowBackground(Color.chart)
             .listRowBackground(Color.chart)
+
+            Section(
+                header: Text("Data-Driven Settings Tuning"),
+                content: {
+                    Text("Autotune").navigationLink(to: .autotuneConfig, from: self)
+                }
+            )
+            .listRowBackground(Color.chart)
         }
         }
         .scrollContentBackground(.hidden).background(color)
         .scrollContentBackground(.hidden).background(color)
         .navigationTitle("Feature Settings")
         .navigationTitle("Feature Settings")

+ 0 - 8
FreeAPS/Sources/Modules/Settings/View/Subviews/TherapySettingsView.swift

@@ -43,14 +43,6 @@ struct TherapySettingsView: BaseView {
                 }
                 }
             )
             )
             .listRowBackground(Color.chart)
             .listRowBackground(Color.chart)
-
-            Section(
-                header: Text("Data-Driven Settings Tuning"),
-                content: {
-                    Text("Autotune").navigationLink(to: .autotuneConfig, from: self)
-                }
-            )
-            .listRowBackground(Color.chart)
         }
         }
         .scrollContentBackground(.hidden).background(color)
         .scrollContentBackground(.hidden).background(color)
         .navigationTitle("Therapy Settings")
         .navigationTitle("Therapy Settings")

+ 3 - 0
FreeAPS/Sources/Router/Screen.swift

@@ -40,6 +40,7 @@ enum Screen: Identifiable, Hashable {
     case featureSettings
     case featureSettings
     case notificationSettings
     case notificationSettings
     case serviceSettings
     case serviceSettings
+    case smbSettings
 
 
     var id: Int { String(reflecting: self).hashValue }
     var id: Int { String(reflecting: self).hashValue }
 }
 }
@@ -123,6 +124,8 @@ extension Screen {
             NotificationsView(resolver: resolver, state: Settings.StateModel())
             NotificationsView(resolver: resolver, state: Settings.StateModel())
         case .serviceSettings:
         case .serviceSettings:
             ServicesView(resolver: resolver, state: Settings.StateModel())
             ServicesView(resolver: resolver, state: Settings.StateModel())
+        case .smbSettings:
+            SMBSettings.RootView(resolver: resolver)
         }
         }
     }
     }
 
 

+ 38 - 0
FreeAPS/Sources/Views/SettingInputHintView.swift

@@ -0,0 +1,38 @@
+import SwiftUI
+
+struct SettingInputHintView: View {
+    @Binding var hintDetent: PresentationDetent
+    @Binding var showHint: Bool
+    var hintLabel: String
+    var hintText: String
+    var sheetTitle: String
+
+    var body: some View {
+        NavigationStack {
+            List {
+                DefinitionRow(
+                    term: hintLabel,
+                    definition: hintText
+                )
+            }
+            .padding(.trailing, 10)
+            .navigationBarTitle(sheetTitle, displayMode: .inline)
+
+            Spacer()
+
+            Button {
+                showHint.toggle()
+            } label: {
+                Text("Got it!")
+                    .frame(maxWidth: .infinity, alignment: .center)
+            }
+            .buttonStyle(.bordered)
+            .padding(.top)
+        }
+        .padding()
+        .presentationDetents(
+            [.fraction(0.9), .large],
+            selection: $hintDetent
+        )
+    }
+}

+ 79 - 0
FreeAPS/Sources/Views/SettingInputSection.swift

@@ -0,0 +1,79 @@
+import SwiftUI
+
+struct SettingInputSection: View {
+    enum InputType {
+        case decimal
+        case boolean
+    }
+
+    @Binding var decimalValue: Decimal
+    @Binding var booleanValue: Bool
+    @Binding var showHint: Bool
+    @Binding var selectedVerboseHint: String?
+
+    var type: InputType
+    var label: String
+    var shortHint: String
+    var verboseHint: String
+    var headerText: String?
+    var footerText: String?
+
+    var body: some View {
+        Section(
+            content: {
+                VStack {
+                    if type == .decimal {
+                        HStack {
+                            Text(label)
+
+                            TextFieldWithToolBar(
+                                text: Binding(
+                                    get: { decimalValue },
+                                    set: { decimalValue = $0 }
+                                ),
+                                placeholder: decimalValue.description,
+                                numberFormatter: NumberFormatter()
+                            )
+
+                        }.padding(.top)
+                    } else if type == .boolean {
+                        HStack {
+                            Toggle(isOn: $booleanValue) {
+                                Text(label)
+                            }
+                        }
+                    }
+
+                    HStack(alignment: .top) {
+                        Text(shortHint)
+                            .font(.footnote)
+                            .foregroundColor(.secondary)
+                            .lineLimit(nil)
+                        Spacer()
+                        Button(
+                            action: {
+                                showHint.toggle()
+                                selectedVerboseHint = showHint ? verboseHint : nil
+                            },
+                            label: {
+                                HStack {
+                                    Image(systemName: "questionmark.circle")
+                                }
+                            }
+                        )
+                    }.padding(type == .boolean ? .vertical : .bottom)
+                }
+            },
+            header: {
+                if let headerText = headerText {
+                    Text(headerText)
+                }
+            },
+            footer: {
+                if let footerText = footerText {
+                    Text(footerText)
+                }
+            }
+        ).listRowBackground(Color.chart)
+    }
+}