Bläddra i källkod

Config editor

Ivan Valkou 5 år sedan
förälder
incheckning
38091a6ea4

+ 40 - 4
FreeAPS.xcodeproj/project.pbxproj

@@ -84,7 +84,12 @@
 		388E597225AD9CF10019842D /* json in Resources */ = {isa = PBXBuildFile; fileRef = 388E597125AD9CF10019842D /* json */; };
 		388E5A5C25B6F0770019842D /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E5A5B25B6F0770019842D /* JSON.swift */; };
 		388E5A6025B6F2310019842D /* Autosens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E5A5F25B6F2310019842D /* Autosens.swift */; };
-		3895E4C625B9E00D00214B37 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3895E4C525B9E00D00214B37 /* Profile.swift */; };
+		3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3895E4C525B9E00D00214B37 /* Preferences.swift */; };
+		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
+		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
+		72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */; };
+		E102DE9C3E9C8AEDCB3C61BB /* ConfigEditorBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E492D5B2EEF2119977EA2CE4 /* ConfigEditorBuilder.swift */; };
+		E39E418C56A5A46B61D960EE /* ConfigEditorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D5B4F8B4194BB7E260EF251 /* ConfigEditorViewModel.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -166,7 +171,12 @@
 		388E597125AD9CF10019842D /* json */ = {isa = PBXFileReference; lastKnownFileType = folder; path = json; sourceTree = "<group>"; };
 		388E5A5B25B6F0770019842D /* JSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = "<group>"; };
 		388E5A5F25B6F2310019842D /* Autosens.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Autosens.swift; sourceTree = "<group>"; };
-		3895E4C525B9E00D00214B37 /* Profile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profile.swift; sourceTree = "<group>"; };
+		3895E4C525B9E00D00214B37 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
+		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
+		44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = "<group>"; };
+		5D5B4F8B4194BB7E260EF251 /* ConfigEditorViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorViewModel.swift; sourceTree = "<group>"; };
+		920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorRootView.swift; sourceTree = "<group>"; };
+		E492D5B2EEF2119977EA2CE4 /* ConfigEditorBuilder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorBuilder.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -182,6 +192,18 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		0610F7D6D2EC00E3BA1569F0 /* ConfigEditor */ = {
+			isa = PBXGroup;
+			children = (
+				E492D5B2EEF2119977EA2CE4 /* ConfigEditorBuilder.swift */,
+				3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */,
+				44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */,
+				5D5B4F8B4194BB7E260EF251 /* ConfigEditorViewModel.swift */,
+				4E8C7B59F8065047ECE20965 /* View */,
+			);
+			path = ConfigEditor;
+			sourceTree = "<group>";
+		};
 		3811DE0325C9D31700A708ED /* Modules */ = {
 			isa = PBXGroup;
 			children = (
@@ -193,6 +215,7 @@
 				3811DE6325C9D62600A708ED /* Onboarding */,
 				3811DE8125C9D6DD00A708ED /* RequestPermissions */,
 				3811DE3825C9D4A100A708ED /* Settings */,
+				0610F7D6D2EC00E3BA1569F0 /* ConfigEditor */,
 			);
 			path = Modules;
 			sourceTree = "<group>";
@@ -537,7 +560,7 @@
 			children = (
 				3811DE8E25C9D80400A708ED /* User.swift */,
 				388E5A5F25B6F2310019842D /* Autosens.swift */,
-				3895E4C525B9E00D00214B37 /* Profile.swift */,
+				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";
@@ -555,6 +578,14 @@
 			path = Helpers;
 			sourceTree = "<group>";
 		};
+		4E8C7B59F8065047ECE20965 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -665,7 +696,7 @@
 				3811DEB225C9D88300A708ED /* KeychainItemAccessibility.swift in Sources */,
 				3811DE6B25C9D62600A708ED /* OnboardingProvider.swift in Sources */,
 				3811DEC225C9D99900A708ED /* SecurityContainer.swift in Sources */,
-				3895E4C625B9E00D00214B37 /* Profile.swift in Sources */,
+				3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */,
 				3811DE6E25C9D62600A708ED /* OnboardingViewModel.swift in Sources */,
 				3811DE6D25C9D62600A708ED /* OnboardingRootView.swift in Sources */,
 				3811DE3025C9D49500A708ED /* HomeViewModel.swift in Sources */,
@@ -728,6 +759,11 @@
 				3811DE6A25C9D62600A708ED /* OnboardingBuilder.swift in Sources */,
 				3811DEC425C9D99900A708ED /* NetworkContainer.swift in Sources */,
 				3811DE4325C9D4A100A708ED /* SettingsProvider.swift in Sources */,
+				E102DE9C3E9C8AEDCB3C61BB /* ConfigEditorBuilder.swift in Sources */,
+				45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */,
+				72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */,
+				E39E418C56A5A46B61D960EE /* ConfigEditorViewModel.swift in Sources */,
+				45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 48 - 40
FreeAPS/Sources/Models/Profile.swift

@@ -1,11 +1,11 @@
 import Foundation
 
-struct Profile: JSON {
-    var maxIOB: Double
-    var maxDailySafetyMultiplier: Double
-    var currentBasalSafetyMultiplier: Double
-    var autosensMax: Double
-    var autosensMin: Double
+struct Preferences: JSON {
+    var maxIOB: Decimal
+    var maxDailySafetyMultiplier: Decimal
+    var currentBasalSafetyMultiplier: Decimal
+    var autosensMax: Decimal
+    var autosensMin: Decimal
     var rewindResetsAutosens: Bool
     var highTemptargetRaisesSensitivity: Bool
     var lowTemptargetLowersSensitivity: Bool
@@ -13,16 +13,16 @@ struct Profile: JSON {
     var resistanceLowersTarget: Bool
     var advTargetAdjustments: Bool
     var exerciseMode: Bool
-    var halfBasalExerciseTarget: Double
-    var maxCOB: Double
+    var halfBasalExerciseTarget: Decimal
+    var maxCOB: Decimal
     var wideBGTargetRange: Bool
     var skipNeutralTemps: Bool
     var unsuspendIfNoTemp: Bool
-    var bolusSnoozeDIADivisor: Double
-    var min5mCarbimpact: Double
-    var autotuneISFAdjustmentFraction: Double
-    var remainingCarbsFraction: Double
-    var remainingCarbsCap: Double
+    var bolusSnoozeDIADivisor: Decimal
+    var min5mCarbimpact: Decimal
+    var autotuneISFAdjustmentFraction: Decimal
+    var remainingCarbsFraction: Decimal
+    var remainingCarbsCap: Decimal
     var enableUAM: Bool
     var a52RiskEnable: Bool
     var enableSMBWithCOB: Bool
@@ -30,25 +30,25 @@ struct Profile: JSON {
     var enableSMBAlways: Bool
     var enableSMBAfterCarbs: Bool
     var allowSMBWithHighTemptarget: Bool
-    var maxSMBBasalMinutes: Double
-    var maxUAMSMBBasalMinutes: Double
-    var smbInterval: Double
-    var bolusIncrement: Double
+    var maxSMBBasalMinutes: Decimal
+    var maxUAMSMBBasalMinutes: Decimal
+    var smbInterval: Decimal
+    var bolusIncrement: Decimal
     var curve: InsulinCurve
     var useCustomPeakTime: Bool
-    var insulinPeakTime: Double
-    var carbsReqThreshold: Double
+    var insulinPeakTime: Decimal
+    var carbsReqThreshold: Decimal
     var offlineHotspot: Bool // unused, for compatibility
-    var noisyCGMTargetMultiplier: Double
+    var noisyCGMTargetMultiplier: Decimal
     var suspendZerosIOB: Bool
     var enableEnliteBgproxy: Bool // unused, for compatibility
 
     init(
-        maxIOB: Double = 0,
-        maxDailySafetyMultiplier: Double = 3,
-        currentBasalSafetyMultiplier: Double = 4,
-        autosensMax: Double = 1.2,
-        autosensMin: Double = 0.7,
+        maxIOB: Decimal = 0,
+        maxDailySafetyMultiplier: Decimal = 3,
+        currentBasalSafetyMultiplier: Decimal = 4,
+        autosensMax: Decimal = 1.2,
+        autosensMin: Decimal = 0.7,
         rewindResetsAutosens: Bool = true,
         highTemptargetRaisesSensitivity: Bool = false,
         lowTemptargetLowersSensitivity: Bool = false,
@@ -56,16 +56,16 @@ struct Profile: JSON {
         resistanceLowersTarget: Bool = false,
         advTargetAdjustments: Bool = false,
         exerciseMode: Bool = false,
-        halfBasalExerciseTarget: Double = 160,
-        maxCOB: Double = 120,
+        halfBasalExerciseTarget: Decimal = 160,
+        maxCOB: Decimal = 120,
         wideBGTargetRange: Bool = false,
         skipNeutralTemps: Bool = false,
         unsuspendIfNoTemp: Bool = false,
-        bolusSnoozeDIADivisor: Double = 2,
-        min5mCarbimpact: Double = 8,
-        autotuneISFAdjustmentFraction: Double = 1.0,
-        remainingCarbsFraction: Double = 1.0,
-        remainingCarbsCap: Double = 90,
+        bolusSnoozeDIADivisor: Decimal = 2,
+        min5mCarbimpact: Decimal = 8,
+        autotuneISFAdjustmentFraction: Decimal = 1.0,
+        remainingCarbsFraction: Decimal = 1.0,
+        remainingCarbsCap: Decimal = 90,
         enableUAM: Bool = false,
         a52RiskEnable: Bool = false,
         enableSMBWithCOB: Bool = false,
@@ -73,16 +73,16 @@ struct Profile: JSON {
         enableSMBAlways: Bool = false,
         enableSMBAfterCarbs: Bool = false,
         allowSMBWithHighTemptarget: Bool = false,
-        maxSMBBasalMinutes: Double = 30,
-        maxUAMSMBBasalMinutes: Double = 30,
-        smbInterval: Double = 3,
-        bolusIncrement: Double = 0.1,
+        maxSMBBasalMinutes: Decimal = 30,
+        maxUAMSMBBasalMinutes: Decimal = 30,
+        smbInterval: Decimal = 3,
+        bolusIncrement: Decimal = 0.1,
         curve: InsulinCurve = .rapidActing,
         useCustomPeakTime: Bool = false,
-        insulinPeakTime: Double = 75,
-        carbsReqThreshold: Double = 1,
+        insulinPeakTime: Decimal = 75,
+        carbsReqThreshold: Decimal = 1,
         offlineHotspot: Bool = false, // unused, for compatibility
-        noisyCGMTargetMultiplier: Double = 1.3,
+        noisyCGMTargetMultiplier: Decimal = 1.3,
         suspendZerosIOB: Bool = true,
         enableEnliteBgproxy: Bool = false // unused, for compatibility
     ) {
@@ -130,7 +130,7 @@ struct Profile: JSON {
     }
 }
 
-extension Profile {
+extension Preferences {
     private enum CodingKeys: String, CodingKey {
         case maxIOB = "max_iob"
         case maxDailySafetyMultiplier = "max_daily_safety_multiplier"
@@ -181,3 +181,11 @@ enum InsulinCurve: String, Codable {
     case ultraRapid = "ultra-rapid"
     case bilinear
 }
+
+extension Preferences {
+    var prettyPrinted: String {
+        let encoder = JSONEncoder()
+        encoder.outputFormatting = .prettyPrinted
+        return String(data: try! encoder.encode(self), encoding: .utf8)!
+    }
+}

+ 3 - 0
FreeAPS/Sources/Modules/ConfigEditor/ConfigEditorBuilder.swift

@@ -0,0 +1,3 @@
+extension ConfigEditor {
+    final class Builder: BaseModuleBuilder<RootView, ViewModel<Provider>, Provider> {}
+}

+ 5 - 0
FreeAPS/Sources/Modules/ConfigEditor/ConfigEditorDataFlow.swift

@@ -0,0 +1,5 @@
+enum ConfigEditor {
+    enum Config {}
+}
+
+protocol ConfigEditorProvider: Provider {}

+ 3 - 0
FreeAPS/Sources/Modules/ConfigEditor/ConfigEditorProvider.swift

@@ -0,0 +1,3 @@
+extension ConfigEditor {
+    final class Provider: BaseProvider, ConfigEditorProvider {}
+}

+ 16 - 0
FreeAPS/Sources/Modules/ConfigEditor/ConfigEditorViewModel.swift

@@ -0,0 +1,16 @@
+import SwiftUI
+
+extension ConfigEditor {
+    class ViewModel<Provider>: BaseViewModel<Provider>, ObservableObject where Provider: ConfigEditorProvider {
+        @Published var configText = ""
+
+        override func subscribe() {
+            let prefs = Preferences()
+            configText = prefs.prettyPrinted
+        }
+
+        func save() {
+            // TODO:
+        }
+    }
+}

+ 22 - 0
FreeAPS/Sources/Modules/ConfigEditor/View/ConfigEditorRootView.swift

@@ -0,0 +1,22 @@
+import SwiftUI
+
+extension ConfigEditor {
+    struct RootView: BaseView {
+        @EnvironmentObject var viewModel: ViewModel<Provider>
+
+        var body: some View {
+            TextEditor(text: $viewModel.configText)
+                .font(.system(.subheadline, design: .monospaced))
+                .allowsTightening(true)
+                .autocapitalization(.none)
+                .disableAutocorrection(true)
+                .toolbar { ToolbarItem(placement: .principal) { Text("preferences.json") } }
+                .navigationBarItems(
+                    leading: Button("Close", action: viewModel.hideModal),
+                    trailing: Button("Save", action: viewModel.save)
+                )
+                .navigationBarTitleDisplayMode(.inline)
+                .padding()
+        }
+    }
+}

+ 5 - 1
FreeAPS/Sources/Modules/Settings/SettingsViewModel.swift

@@ -1,5 +1,9 @@
 import SwiftUI
 
 extension Settings {
-    class ViewModel<Provider>: BaseViewModel<Provider>, ObservableObject where Provider: SettingsProvider {}
+    class ViewModel<Provider>: BaseViewModel<Provider>, ObservableObject where Provider: SettingsProvider {
+        func openProfileEditor() {
+            router.modalScreen.send(.configEditor)
+        }
+    }
 }

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

@@ -7,6 +7,12 @@ extension Settings {
         var body: some View {
             VStack {
                 Text("Settings screen")
+                Button(action: viewModel.openProfileEditor) {
+                    Text("Open Editor")
+                        .frame(maxWidth: .infinity)
+                        .foregroundColor(.white)
+                        .buttonBackground()
+                }
                 Spacer()
             }
             .padding()

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

@@ -8,6 +8,7 @@ enum Screen: Identifiable {
     case authorizedRoot
     case login
     case requestPermissions
+    case configEditor
 
     var id: Int { String(reflecting: self).hashValue }
 }
@@ -27,6 +28,8 @@ extension Screen {
             return Login.Builder(resolver: resolver).buildView().asAny()
         case .requestPermissions:
             return RequestPermissions.Builder(resolver: resolver).buildView().asAny()
+        case .configEditor:
+            return ConfigEditor.Builder(resolver: resolver).buildView().asAny()
         }
     }
 
@@ -48,6 +51,7 @@ extension Screen {
                 text: Text("Settings")
             )
         case .authorizedRoot,
+             .configEditor,
              .login,
              .onboarding,
              .requestPermissions: