Przeglądaj źródła

Implement general app settings parser for mmol/L to mg/dL

Deniz Cengiz 1 rok temu
rodzic
commit
3f65a4b451

+ 9 - 0
FreeAPS/Sources/APS/APSManager.swift

@@ -131,6 +131,15 @@ final class BaseAPSManager: APSManager, Injectable {
     }
 
     private func subscribe() {
+        if settingsManager.settings.units == .mmolL {
+            let wasParsed = storage.parseOnFileSettingsToMgdL()
+            if wasParsed {
+                Task {
+                    try await makeProfiles()
+                }
+            }
+        }
+
         deviceDataManager.recommendsLoop
             .receive(on: processQueue)
             .sink { [weak self] in

+ 2 - 2
FreeAPS/Sources/Models/BGTargets.swift

@@ -1,8 +1,8 @@
 import Foundation
 
 struct BGTargets: JSON {
-    let units: GlucoseUnits
-    let userPreferredUnits: GlucoseUnits
+    var units: GlucoseUnits
+    var userPreferredUnits: GlucoseUnits
     var targets: [BGTargetEntry]
 }
 

+ 3 - 3
FreeAPS/Sources/Models/InsulinSensitivities.swift

@@ -1,9 +1,9 @@
 import Foundation
 
 struct InsulinSensitivities: JSON {
-    let units: GlucoseUnits
-    let userPreferredUnits: GlucoseUnits
-    let sensitivities: [InsulinSensitivityEntry]
+    var units: GlucoseUnits
+    var userPreferredUnits: GlucoseUnits
+    var sensitivities: [InsulinSensitivityEntry]
 }
 
 extension InsulinSensitivities {

+ 7 - 1
FreeAPS/Sources/Modules/ISFEditor/ISFEditorProvider.swift

@@ -1,3 +1,5 @@
+import Foundation
+
 extension ISFEditor {
     final class Provider: BaseProvider, ISFEditorProvider {
         var profile: InsulinSensitivities {
@@ -12,7 +14,11 @@ extension ISFEditor {
             // migrate existing mmol/L Trio users from mmol/L settings to pure mg/dl settings
             if retrievedSensitivities.units == .mmolL || retrievedSensitivities.userPreferredUnits == .mmolL {
                 let convertedSensitivities = retrievedSensitivities.sensitivities.map { isf in
-                    InsulinSensitivityEntry(sensitivity: isf.sensitivity.asMgdL, offset: isf.offset, start: isf.start)
+                    InsulinSensitivityEntry(
+                        sensitivity: storage.parseSettingIfMmolL(value: isf.sensitivity),
+                        offset: isf.offset,
+                        start: isf.start
+                    )
                 }
                 retrievedSensitivities = InsulinSensitivities(
                     units: .mgdL,

+ 0 - 23
FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift

@@ -160,29 +160,6 @@ extension NightscoutConfig {
                 if state.importStatus == .running {
                     CustomProgressView(text: "Importing Profile...")
                 }
-                //            .alert(isPresented: $importedHasRun) {
-                //                Alert(
-                //                    title: Text(
-                //                        (fetchedErrors.first?.error ?? "")
-                //                            .count < 4 ? "Settings imported" : "Import Error"
-                //                    ),
-                //                    message: Text(
-                //                        (fetchedErrors.first?.error ?? "").count < 4 ?
-                //                            NSLocalizedString(
-                //                                "\nNow please verify all of your new settings thoroughly: \n\n • DIA (Pump settings)\n • Basal Rates\n • Insulin Sensitivities\n • Carb Ratios\n • Target Glucose\n\n in Trio Settings -> Configuration.\n\nBad or invalid profile settings could have disastrous effects.",
-                //                                comment: "Imported Profiles Alert"
-                //                            ) :
-                //                            NSLocalizedString(
-                //                                fetchedErrors.first?.error ?? "",
-                //                                comment: "Import Error"
-                //                            )
-                //                    ),
-                //                    primaryButton: .destructive(
-                //                        Text("OK")
-                //                    ),
-                //                    secondaryButton: .cancel()
-                //                )
-                //            }
             }
             .fullScreenCover(isPresented: $state.isImportResultReviewPresented, content: {
                 NightscoutImportResultView(resolver: resolver, state: state)

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

@@ -221,6 +221,13 @@ extension Settings {
 //                        .navigationLink(to: .configEditor(file: OpenAPS.Settings.bgTargets), from: self)
 //                    Text("Sensitivities")
 //                        .navigationLink(to: .configEditor(file: OpenAPS.Settings.insulinSensitivities), from: self)
+//                    Text("Profile")
+//                        .navigationLink(to: .configEditor(file: OpenAPS.Settings.profile), from: self)
+//                    Text("Preferences")
+//                        .navigationLink(
+//                            to: .configEditor(file: OpenAPS.Settings.preferences),
+//                            from: self
+//                        )
 //                }.listRowBackground(Color.chart)
 
                 // TODO: remove this more or less entirely; add build-time flag to enable Middleware; add settings export feature

+ 8 - 1
FreeAPS/Sources/Modules/TargetsEditor/TargetsEditorProvider.swift

@@ -1,3 +1,5 @@
+import Foundation
+
 extension TargetsEditor {
     final class Provider: BaseProvider, TargetsEditorProvider {
         var profile: BGTargets {
@@ -8,7 +10,12 @@ extension TargetsEditor {
             // migrate existing mmol/L Trio users from mmol/L settings to pure mg/dl settings
             if retrievedTargets.units == .mmolL || retrievedTargets.userPreferredUnits == .mmolL {
                 let convertedTargets = retrievedTargets.targets.map { target in
-                    BGTargetEntry(low: target.low.asMgdL, high: target.high.asMgdL, start: target.start, offset: target.offset)
+                    BGTargetEntry(
+                        low: storage.parseSettingIfMmolL(value: target.low),
+                        high: storage.parseSettingIfMmolL(value: target.high),
+                        start: target.start,
+                        offset: target.offset
+                    )
                 }
                 retrievedTargets = BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: convertedTargets)
                 saveProfile(retrievedTargets)

+ 112 - 1
FreeAPS/Sources/Services/Storage/FileStorage.swift

@@ -14,8 +14,8 @@ protocol FileStorage {
     func remove(_ name: String)
     func rename(_ name: String, to newName: String)
     func transaction(_ exec: (FileStorage) -> Void)
-
     func urlFor(file: String) -> URL?
+    func parseOnFileSettingsToMgdL() -> Bool
 }
 
 final class BaseFileStorage: FileStorage {
@@ -150,3 +150,114 @@ final class BaseFileStorage: FileStorage {
         try? Disk.url(for: file, in: .documents)
     }
 }
+
+extension FileStorage {
+    private func correctUnitParsingOffsets(_ parsedValue: Decimal) -> Decimal {
+        Int(parsedValue) % 2 == 0 ? parsedValue : parsedValue + 1
+    }
+
+    func parseSettingIfMmolL(value: Decimal, threshold: Decimal = 39) -> Decimal {
+        value < threshold ? correctUnitParsingOffsets(value.asMgdL) : value
+    }
+
+    /// Parses mmol/L settings stored on file to mg/dL if necessary and updates the preferences, settings,  insulin sensitivities, and glucose targets.
+    /// - Returns: A boolean indicating whether any settings were parsed and updated.
+    func parseOnFileSettingsToMgdL() -> Bool {
+        debug(.businessLogic, "Check for mmol/L settings stored on file.")
+        var wasParsed = false
+
+        // Retrieve and parse preferences (Preferences struct)
+        if var preferences = retrieve(OpenAPS.Settings.preferences, as: Preferences.self) {
+            let initialThreshold = preferences.threshold_setting
+            let initialSMBTarget = preferences.enableSMB_high_bg_target
+            let initialExerciseTarget = preferences.halfBasalExerciseTarget
+
+            preferences.threshold_setting = parseSettingIfMmolL(value: preferences.threshold_setting)
+            preferences.enableSMB_high_bg_target = parseSettingIfMmolL(value: preferences.enableSMB_high_bg_target)
+            preferences.halfBasalExerciseTarget = parseSettingIfMmolL(value: preferences.halfBasalExerciseTarget)
+
+            if preferences.threshold_setting != initialThreshold ||
+                preferences.enableSMB_high_bg_target != initialSMBTarget ||
+                preferences.halfBasalExerciseTarget != initialExerciseTarget
+            {
+                debug(.businessLogic, "Preferences found in mmol/L. Parsing to mg/dL.")
+                save(preferences, as: OpenAPS.Settings.preferences)
+                wasParsed = true
+            } else {
+                debug(.businessLogic, "Preferences stored in mg/dL; no parsing required.")
+            }
+        }
+
+        // Retrieve and parse settings (FreeAPSSettings struct)
+        if var settings = retrieve(OpenAPS.Settings.settings, as: FreeAPSSettings.self) {
+            let initialHigh = settings.high
+            let initialLow = settings.low
+            let initialHighGlucose = settings.highGlucose
+            let initialLowGlucose = settings.lowGlucose
+
+            settings.high = parseSettingIfMmolL(value: settings.high)
+            settings.low = parseSettingIfMmolL(value: settings.low)
+            settings.highGlucose = parseSettingIfMmolL(value: settings.highGlucose)
+            settings.lowGlucose = parseSettingIfMmolL(value: settings.lowGlucose)
+
+            if settings.high != initialHigh ||
+                settings.low != initialLow ||
+                settings.highGlucose != initialHighGlucose ||
+                settings.lowGlucose != initialLowGlucose
+            {
+                debug(.businessLogic, "FreeAPSSettings found in mmol/L. Parsing to mg/dL.")
+                save(settings, as: OpenAPS.Settings.settings)
+                wasParsed = true
+            } else {
+                debug(.businessLogic, "FreeAPSSettings stored in mg/dL; no parsing required.")
+            }
+        }
+
+        // Retrieve and parse insulin sensitivities
+        if var sensitivities = retrieve(OpenAPS.Settings.insulinSensitivities, as: InsulinSensitivities.self),
+           sensitivities.units == .mmolL || sensitivities.userPreferredUnits == .mmolL
+        {
+            debug(.businessLogic, "Insulin sensitivities found in mmol/L. Parsing to mg/dL.")
+
+            sensitivities.sensitivities = sensitivities.sensitivities.map { isf in
+                InsulinSensitivityEntry(
+                    sensitivity: parseSettingIfMmolL(value: isf.sensitivity),
+                    offset: isf.offset,
+                    start: isf.start
+                )
+            }
+            sensitivities.units = .mgdL
+            sensitivities.userPreferredUnits = .mgdL
+
+            save(sensitivities, as: OpenAPS.Settings.insulinSensitivities)
+            wasParsed = true
+        } else {
+            debug(.businessLogic, "Insulin sensitivities stored in mg/dL; no parsing required.")
+        }
+
+        // Retrieve and parse glucose targets
+        if var glucoseTargets = retrieve(OpenAPS.Settings.bgTargets, as: BGTargets.self),
+           glucoseTargets.units == .mmolL || glucoseTargets.userPreferredUnits == .mmolL
+        {
+            debug(.businessLogic, "Glucose target profile found in mmol/L. Parsing to mg/dL.")
+
+            glucoseTargets.targets = glucoseTargets.targets.map { target in
+                BGTargetEntry(
+                    low: parseSettingIfMmolL(value: target.low),
+                    high: parseSettingIfMmolL(value: target.high),
+                    start: target.start,
+                    offset: target.offset
+                )
+            }
+            glucoseTargets.units = .mgdL
+            glucoseTargets.userPreferredUnits = .mgdL
+
+            save(glucoseTargets, as: OpenAPS.Settings.bgTargets)
+            wasParsed = true
+        } else {
+            debug(.businessLogic, "Glucose target profile stored in mg/dL; no parsing required.")
+        }
+
+        return wasParsed
+    }
+}