Kaynağa Gözat

Add FPU settings.
Hard coded limits:
Time Cap: 8 - 12 hours (Default 8 hours)
Adjustment factor: 0.3 - 1.2 (Default 0.8)
Interval for future carb equivalents: 10 - 90 min (Default 60 min)

Jon Mårtensson 3 yıl önce
ebeveyn
işleme
bfdabc75dd

+ 32 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -21,6 +21,10 @@
 		19854F492961C3E500941627 /* DurationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19854F482961C3E500941627 /* DurationButton.swift */; };
 		19854F492961C3E500941627 /* DurationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19854F482961C3E500941627 /* DurationButton.swift */; };
 		199561C1275E61A50077B976 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 199561C0275E61A50077B976 /* HealthKit.framework */; };
 		199561C1275E61A50077B976 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 199561C0275E61A50077B976 /* HealthKit.framework */; };
 		19B0EF2128F6D66200069496 /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B0EF2028F6D66200069496 /* Statistics.swift */; };
 		19B0EF2128F6D66200069496 /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B0EF2028F6D66200069496 /* Statistics.swift */; };
+		19D466A329AA2B80004D5F33 /* FPUConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A229AA2B80004D5F33 /* FPUConfigDataFlow.swift */; };
+		19D466A529AA2BD4004D5F33 /* FPUConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A429AA2BD4004D5F33 /* FPUConfigProvider.swift */; };
+		19D466A729AA2C22004D5F33 /* FPUConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A629AA2C22004D5F33 /* FPUConfigStateModel.swift */; };
+		19D466AA29AA3099004D5F33 /* FPUConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A929AA3099004D5F33 /* FPUConfigRootView.swift */; };
 		1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */; };
 		1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */; };
 		1D845DF2E3324130E1D95E67 /* DataTableProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60744C3E9BB3652895C908CC /* DataTableProvider.swift */; };
 		1D845DF2E3324130E1D95E67 /* DataTableProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60744C3E9BB3652895C908CC /* DataTableProvider.swift */; };
 		23888883D4EA091C88480FF2 /* BolusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19984D62EFC0035A9E9644D /* BolusProvider.swift */; };
 		23888883D4EA091C88480FF2 /* BolusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19984D62EFC0035A9E9644D /* BolusProvider.swift */; };
@@ -487,6 +491,10 @@
 		19B0EF2028F6D66200069496 /* Statistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = "<group>"; };
 		19B0EF2028F6D66200069496 /* Statistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = "<group>"; };
 		19C166682756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		19C166682756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		19C166692756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
 		19C166692756EFBD00ED12E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
+		19D466A229AA2B80004D5F33 /* FPUConfigDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigDataFlow.swift; sourceTree = "<group>"; };
+		19D466A429AA2BD4004D5F33 /* FPUConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigProvider.swift; sourceTree = "<group>"; };
+		19D466A629AA2C22004D5F33 /* FPUConfigStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigStateModel.swift; sourceTree = "<group>"; };
+		19D466A929AA3099004D5F33 /* FPUConfigRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigRootView.swift; sourceTree = "<group>"; };
 		1CAE81192B118804DCD23034 /* SnoozeProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeProvider.swift; sourceTree = "<group>"; };
 		1CAE81192B118804DCD23034 /* SnoozeProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeProvider.swift; sourceTree = "<group>"; };
 		212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsProvider.swift; sourceTree = "<group>"; };
 		212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsProvider.swift; sourceTree = "<group>"; };
 		223EC0494F55A91E3EA69EF4 /* BolusStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusStateModel.swift; sourceTree = "<group>"; };
 		223EC0494F55A91E3EA69EF4 /* BolusStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusStateModel.swift; sourceTree = "<group>"; };
@@ -927,6 +935,25 @@
 			path = Main;
 			path = Main;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		19D466A129AA2B0A004D5F33 /* FPUConfig */ = {
+			isa = PBXGroup;
+			children = (
+				19D466A229AA2B80004D5F33 /* FPUConfigDataFlow.swift */,
+				19D466A429AA2BD4004D5F33 /* FPUConfigProvider.swift */,
+				19D466A629AA2C22004D5F33 /* FPUConfigStateModel.swift */,
+				19D466A829AA306E004D5F33 /* View */,
+			);
+			path = FPUConfig;
+			sourceTree = "<group>";
+		};
+		19D466A829AA306E004D5F33 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				19D466A929AA3099004D5F33 /* FPUConfigRootView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		29B478DF61BF8D270F7D8954 /* Snooze */ = {
 		29B478DF61BF8D270F7D8954 /* Snooze */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -949,6 +976,7 @@
 		3811DE0325C9D31700A708ED /* Modules */ = {
 		3811DE0325C9D31700A708ED /* Modules */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				19D466A129AA2B0A004D5F33 /* FPUConfig */,
 				F90692CD274B99850037068D /* HealthKit */,
 				F90692CD274B99850037068D /* HealthKit */,
 				6DC5D590658EF8B8DF94F9F5 /* AddCarbs */,
 				6DC5D590658EF8B8DF94F9F5 /* AddCarbs */,
 				A9A4C88374496B3C89058A89 /* AddTempTarget */,
 				A9A4C88374496B3C89058A89 /* AddTempTarget */,
@@ -2233,6 +2261,7 @@
 				38E44537274E411700EC9A94 /* Disk+Helpers.swift in Sources */,
 				38E44537274E411700EC9A94 /* Disk+Helpers.swift in Sources */,
 				388E5A6025B6F2310019842D /* Autosens.swift in Sources */,
 				388E5A6025B6F2310019842D /* Autosens.swift in Sources */,
 				3811DE8F25C9D80400A708ED /* User.swift in Sources */,
 				3811DE8F25C9D80400A708ED /* User.swift in Sources */,
+				19D466A329AA2B80004D5F33 /* FPUConfigDataFlow.swift in Sources */,
 				3811DEB225C9D88300A708ED /* KeychainItemAccessibility.swift in Sources */,
 				3811DEB225C9D88300A708ED /* KeychainItemAccessibility.swift in Sources */,
 				385CEAC425F2F154002D6D5B /* AnnouncementsStorage.swift in Sources */,
 				385CEAC425F2F154002D6D5B /* AnnouncementsStorage.swift in Sources */,
 				38AEE73D25F0200C0013F05B /* FreeAPSSettings.swift in Sources */,
 				38AEE73D25F0200C0013F05B /* FreeAPSSettings.swift in Sources */,
@@ -2271,6 +2300,7 @@
 				38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */,
 				38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */,
 				3811DEB125C9D88300A708ED /* Keychain.swift in Sources */,
 				3811DEB125C9D88300A708ED /* Keychain.swift in Sources */,
 				382C133725F13A1E00715CE1 /* InsulinSensitivities.swift in Sources */,
 				382C133725F13A1E00715CE1 /* InsulinSensitivities.swift in Sources */,
+				19D466A529AA2BD4004D5F33 /* FPUConfigProvider.swift in Sources */,
 				383948D625CD4D8900E91849 /* FileStorage.swift in Sources */,
 				383948D625CD4D8900E91849 /* FileStorage.swift in Sources */,
 				3811DE4125C9D4A100A708ED /* SettingsRootView.swift in Sources */,
 				3811DE4125C9D4A100A708ED /* SettingsRootView.swift in Sources */,
 				38192E04261B82FA0094D973 /* ReachabilityManager.swift in Sources */,
 				38192E04261B82FA0094D973 /* ReachabilityManager.swift in Sources */,
@@ -2289,6 +2319,7 @@
 				3811DF0225CA9FEA00A708ED /* Credentials.swift in Sources */,
 				3811DF0225CA9FEA00A708ED /* Credentials.swift in Sources */,
 				389A572026079BAA00BC102F /* Interpolation.swift in Sources */,
 				389A572026079BAA00BC102F /* Interpolation.swift in Sources */,
 				38B4F3C625E5017E00E76A18 /* NotificationCenter.swift in Sources */,
 				38B4F3C625E5017E00E76A18 /* NotificationCenter.swift in Sources */,
+				19D466A729AA2C22004D5F33 /* FPUConfigStateModel.swift in Sources */,
 				38E44528274E401C00EC9A94 /* Protected.swift in Sources */,
 				38E44528274E401C00EC9A94 /* Protected.swift in Sources */,
 				3811DEB625C9D88300A708ED /* UnlockManager.swift in Sources */,
 				3811DEB625C9D88300A708ED /* UnlockManager.swift in Sources */,
 				E00EEC0827368630002FF094 /* NetworkAssembly.swift in Sources */,
 				E00EEC0827368630002FF094 /* NetworkAssembly.swift in Sources */,
@@ -2375,6 +2406,7 @@
 				AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */,
 				AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */,
 				53F2382465BF74DB1A967C8B /* PumpConfigProvider.swift in Sources */,
 				53F2382465BF74DB1A967C8B /* PumpConfigProvider.swift in Sources */,
 				5D16287A969E64D18CE40E44 /* PumpConfigStateModel.swift in Sources */,
 				5D16287A969E64D18CE40E44 /* PumpConfigStateModel.swift in Sources */,
+				19D466AA29AA3099004D5F33 /* FPUConfigRootView.swift in Sources */,
 				E974172296125A5AE99E634C /* PumpConfigRootView.swift in Sources */,
 				E974172296125A5AE99E634C /* PumpConfigRootView.swift in Sources */,
 				448B6FCB252BD4796E2960C0 /* PumpSettingsEditorDataFlow.swift in Sources */,
 				448B6FCB252BD4796E2960C0 /* PumpSettingsEditorDataFlow.swift in Sources */,
 				38E44536274E411700EC9A94 /* Disk.swift in Sources */,
 				38E44536274E411700EC9A94 /* Disk.swift in Sources */,

+ 5 - 1
FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json

@@ -21,5 +21,9 @@
     "carbsRequiredThreshold": 10,
     "carbsRequiredThreshold": 10,
     "useAppleHealth": false,
     "useAppleHealth": false,
     "animatedBackground": false,
     "animatedBackground": false,
-    "displayStatistics": false
+    "displayStatistics": false,
+    "useFPUconversion": false
+    "individualAdjustmentFactor": 0.8,
+    "timeCap": 8,
+    "minuteInterval": 60
 }
 }

+ 20 - 0
FreeAPS/Sources/Models/FreeAPSSettings.swift

@@ -25,6 +25,10 @@ struct FreeAPSSettings: JSON, Equatable {
     var carbsRequiredThreshold: Decimal = 10
     var carbsRequiredThreshold: Decimal = 10
     var animatedBackground: Bool = false
     var animatedBackground: Bool = false
     var displayStatistics: Bool = false
     var displayStatistics: Bool = false
+    var useFPUconversion: Bool = false
+    var individualAdjustmentFactor: Decimal = 0.8
+    var timeCap: Decimal = 8
+    var minuteInterval: Int = 60
 }
 }
 
 
 extension FreeAPSSettings: Decodable {
 extension FreeAPSSettings: Decodable {
@@ -97,6 +101,22 @@ extension FreeAPSSettings: Decodable {
             settings.glucoseBadge = glucoseBadge
             settings.glucoseBadge = glucoseBadge
         }
         }
 
 
+        if let useFPUconversion = try? container.decode(Bool.self, forKey: .useFPUconversion) {
+            settings.useFPUconversion = useFPUconversion
+        }
+
+        if let individualAdjustmentFactor = try? container.decode(Decimal.self, forKey: .individualAdjustmentFactor) {
+            settings.individualAdjustmentFactor = individualAdjustmentFactor
+        }
+
+        if let timeCap = try? container.decode(Decimal.self, forKey: .timeCap) {
+            settings.timeCap = timeCap
+        }
+
+        if let minuteInterval = try? container.decode(Int.self, forKey: .minuteInterval) {
+            settings.minuteInterval = minuteInterval
+        }
+
         if let glucoseNotificationsAlways = try? container.decode(Bool.self, forKey: .glucoseNotificationsAlways) {
         if let glucoseNotificationsAlways = try? container.decode(Bool.self, forKey: .glucoseNotificationsAlways) {
             settings.glucoseNotificationsAlways = glucoseNotificationsAlways
             settings.glucoseNotificationsAlways = glucoseNotificationsAlways
         }
         }

+ 12 - 2
FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift

@@ -4,14 +4,17 @@ extension AddCarbs {
     final class StateModel: BaseStateModel<Provider> {
     final class StateModel: BaseStateModel<Provider> {
         @Injected() var carbsStorage: CarbsStorage!
         @Injected() var carbsStorage: CarbsStorage!
         @Injected() var apsManager: APSManager!
         @Injected() var apsManager: APSManager!
+        @Injected() var settings: SettingsManager!
         @Published var carbs: Decimal = 0
         @Published var carbs: Decimal = 0
         @Published var date = Date()
         @Published var date = Date()
         @Published var protein: Decimal = 0
         @Published var protein: Decimal = 0
         @Published var fat: Decimal = 0
         @Published var fat: Decimal = 0
         @Published var carbsRequired: Decimal?
         @Published var carbsRequired: Decimal?
+        @Published var useFPU: Bool = false
 
 
         override func subscribe() {
         override func subscribe() {
             carbsRequired = provider.suggestion?.carbsReq
             carbsRequired = provider.suggestion?.carbsReq
+            useFPU = settingsManager.settings.useFPUconversion
         }
         }
 
 
         func add() {
         func add() {
@@ -23,15 +26,22 @@ extension AddCarbs {
             // Convert fat and protein to carb equivalents and store as future carbs
             // Convert fat and protein to carb equivalents and store as future carbs
             let fpucarb = (0.4 * protein) + (0.9 * fat)
             let fpucarb = (0.4 * protein) + (0.9 * fat)
             let fpus = ((fat * 9.0) + (protein * 4.0)) / 100.0
             let fpus = ((fat * 9.0) + (protein * 4.0)) / 100.0
+            // Default is 1 hour (60 minutes)
+            let timeInterval = 60 * settings.settings.minuteInterval
+            // Deffault is 8 hours
+            let timeCap = settings.settings.timeCap
             var counter: Decimal = (fpus * 2) - 1.0
             var counter: Decimal = (fpus * 2) - 1.0
+            counter = min(timeCap, counter)
             var roundedCounter: Decimal = 0
             var roundedCounter: Decimal = 0
             NSDecimalRound(&roundedCounter, &counter, 0, .up)
             NSDecimalRound(&roundedCounter, &counter, 0, .up)
             let carbequiv = fpucarb / roundedCounter
             let carbequiv = fpucarb / roundedCounter
-            while counter > 0 {
+
+            while counter > 0, counter <= timeCap {
                 let newdate = 1.0 + trunc(Double(truncating: counter as NSNumber))
                 let newdate = 1.0 + trunc(Double(truncating: counter as NSNumber))
                 carbsStorage.storeCarbs([
                 carbsStorage.storeCarbs([
                     CarbsEntry(
                     CarbsEntry(
-                        id: UUID(), createdAt: date + (newdate * 3600), carbs: carbequiv, enteredBy: CarbsEntry.manual
+                        id: UUID(), createdAt: date + (newdate * Double(timeInterval)), carbs: carbequiv,
+                        enteredBy: CarbsEntry.manual
                     )
                     )
                 ])
                 ])
                 counter -= 1
                 counter -= 1

+ 28 - 25
FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift

@@ -32,32 +32,35 @@ extension AddCarbs {
                             DecimalTextField("0", value: $state.carbs, formatter: formatter, autofocus: true, cleanInput: true)
                             DecimalTextField("0", value: $state.carbs, formatter: formatter, autofocus: true, cleanInput: true)
                             Text("grams").foregroundColor(.secondary)
                             Text("grams").foregroundColor(.secondary)
                         }.padding(.vertical)
                         }.padding(.vertical)
-                        // Adding Protein and Fat. Test
-                        HStack {
-                            Text("Protein").foregroundColor(.loopRed).fontWeight(.thin)
-                            Spacer()
-                            DecimalTextField(
-                                "0",
-                                value: $state.protein,
-                                formatter: formatter,
-                                autofocus: false,
-                                cleanInput: true
-                            ).foregroundColor(.loopRed)
-                            Text("grams").foregroundColor(.secondary)
-                        }
-                        HStack {
-                            Text("Fat").foregroundColor(.loopYellow).fontWeight(.thin)
-                            Spacer()
-                            DecimalTextField(
-                                "0",
-                                value: $state.fat,
-                                formatter: formatter,
-                                autofocus: false,
-                                cleanInput: true
-                            )
-                            Text("grams").foregroundColor(.secondary)
-                        }
 
 
+                        // MARK: Adding Protein and Fat. Test
+
+                        if state.useFPU {
+                            HStack {
+                                Text("Protein").foregroundColor(.loopRed).fontWeight(.thin)
+                                Spacer()
+                                DecimalTextField(
+                                    "0",
+                                    value: $state.protein,
+                                    formatter: formatter,
+                                    autofocus: false,
+                                    cleanInput: true
+                                ).foregroundColor(.loopRed)
+                                Text("grams").foregroundColor(.secondary)
+                            }
+                            HStack {
+                                Text("Fat").foregroundColor(.loopYellow).fontWeight(.thin)
+                                Spacer()
+                                DecimalTextField(
+                                    "0",
+                                    value: $state.fat,
+                                    formatter: formatter,
+                                    autofocus: false,
+                                    cleanInput: true
+                                )
+                                Text("grams").foregroundColor(.secondary)
+                            }
+                        }
                         DatePicker("Date", selection: $state.date)
                         DatePicker("Date", selection: $state.date)
                     }
                     }
                 }
                 }

+ 5 - 0
FreeAPS/Sources/Modules/FPUConfig/FPUConfigDataFlow.swift

@@ -0,0 +1,5 @@
+enum FPUConfig {
+    enum Config {}
+}
+
+protocol FPUConfigProvider {}

+ 3 - 0
FreeAPS/Sources/Modules/FPUConfig/FPUConfigProvider.swift

@@ -0,0 +1,3 @@
+extension FPUConfig {
+    final class Provider: BaseProvider, FPUConfigProvider {}
+}

+ 36 - 0
FreeAPS/Sources/Modules/FPUConfig/FPUConfigStateModel.swift

@@ -0,0 +1,36 @@
+import SwiftUI
+
+extension FPUConfig {
+    final class StateModel: BaseStateModel<Provider> {
+        @Published var useFPUconversion = false
+        @Published var individualAdjustmentFactor: Decimal = 0
+        @Published var timeCap: Decimal = 0
+        @Published var minuteInterval: Decimal = 0
+
+        override func subscribe() {
+            subscribeSetting(\.useFPUconversion, on: $useFPUconversion) { useFPUconversion = $0 }
+            subscribeSetting(\.timeCap, on: $timeCap) { timeCap = $0 }
+
+            subscribeSetting(\.timeCap, on: $timeCap, initial: {
+                let value = max(min($0, 12), 8)
+                timeCap = value
+            }, map: {
+                $0
+            })
+
+            subscribeSetting(\.minuteInterval, on: $minuteInterval.map(Int.init), initial: {
+                let value = max(min($0, 90), 10)
+                minuteInterval = Decimal(value)
+            }, map: {
+                $0
+            })
+
+            subscribeSetting(\.individualAdjustmentFactor, on: $individualAdjustmentFactor, initial: {
+                let value = max(min($0, 1.2), 0.3)
+                individualAdjustmentFactor = value
+            }, map: {
+                $0
+            })
+        }
+    }
+}

+ 52 - 0
FreeAPS/Sources/Modules/FPUConfig/View/FPUConfigRootView.swift

@@ -0,0 +1,52 @@
+import SwiftUI
+import Swinject
+
+extension FPUConfig {
+    struct RootView: BaseView {
+        let resolver: Resolver
+        @StateObject var state = StateModel()
+
+        private var conversionFormatter: NumberFormatter {
+            let formatter = NumberFormatter()
+            formatter.numberStyle = .decimal
+            formatter.maximumFractionDigits = 1
+
+            return formatter
+        }
+
+        private var intFormater: NumberFormatter {
+            let formatter = NumberFormatter()
+            formatter.allowsFloats = false
+            return formatter
+        }
+
+        var body: some View {
+            Form {
+                Section(header: Text("Convert Fat and Protein")) {
+                    Toggle("Enable", isOn: $state.useFPUconversion)
+                }
+
+                Section(header: Text("Optional conversion settings")) {
+                    HStack {
+                        Text("Maximum Time Cap In Hours")
+                        Spacer()
+                        DecimalTextField("8", value: $state.timeCap, formatter: intFormater)
+                    }
+                    HStack {
+                        Text("Interval In Minutes")
+                        Spacer()
+                        DecimalTextField("60", value: $state.minuteInterval, formatter: intFormater)
+                    }
+                    HStack {
+                        Text("Override with a factor of ")
+                        Spacer()
+                        DecimalTextField("0.8", value: $state.individualAdjustmentFactor, formatter: conversionFormatter)
+                    }
+                }
+            }
+            .onAppear(perform: configureView)
+            .navigationBarTitle("Fat and Protein")
+            .navigationBarTitleDisplayMode(.automatic)
+        }
+    }
+}

+ 0 - 3
FreeAPS/Sources/Modules/Settings/SettingsStateModel.swift

@@ -11,11 +11,8 @@ extension Settings {
         @Published var animatedBackground = false
         @Published var animatedBackground = false
 
 
         private(set) var buildNumber = ""
         private(set) var buildNumber = ""
-
         private(set) var versionNumber = ""
         private(set) var versionNumber = ""
-
         private(set) var branch = ""
         private(set) var branch = ""
-
         private(set) var copyrightNotice = ""
         private(set) var copyrightNotice = ""
 
 
         override func subscribe() {
         override func subscribe() {

+ 1 - 0
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -29,6 +29,7 @@ extension Settings {
                         Text("Apple Health").navigationLink(to: .healthkit, from: self)
                         Text("Apple Health").navigationLink(to: .healthkit, from: self)
                     }
                     }
                     Text("Notifications").navigationLink(to: .notificationsConfig, from: self)
                     Text("Notifications").navigationLink(to: .notificationsConfig, from: self)
+                    Text("Fat And Protein Conversion").navigationLink(to: .fpuConfig, from: self)
                 }
                 }
 
 
                 Section(header: Text("Configuration")) {
                 Section(header: Text("Configuration")) {

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

@@ -25,6 +25,7 @@ enum Screen: Identifiable, Hashable {
     case libreConfig
     case libreConfig
     case calibrations
     case calibrations
     case notificationsConfig
     case notificationsConfig
+    case fpuConfig
     case snooze
     case snooze
 
 
     var id: Int { String(reflecting: self).hashValue }
     var id: Int { String(reflecting: self).hashValue }
@@ -82,6 +83,8 @@ extension Screen {
             Calibrations.RootView(resolver: resolver)
             Calibrations.RootView(resolver: resolver)
         case .notificationsConfig:
         case .notificationsConfig:
             NotificationsConfig.RootView(resolver: resolver)
             NotificationsConfig.RootView(resolver: resolver)
+        case .fpuConfig:
+            FPUConfig.RootView(resolver: resolver)
         case .snooze:
         case .snooze:
             Snooze.RootView(resolver: resolver)
             Snooze.RootView(resolver: resolver)
         }
         }