Jelajahi Sumber

Add DIA review view, adjust some namings, minor refactor

Deniz Cengiz 1 tahun lalu
induk
melakukan
7e1c5a1b7c

+ 4 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -456,6 +456,7 @@
 		DD6B7CB42C7B71F700B75029 /* ForecastDisplayType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CB32C7B71F700B75029 /* ForecastDisplayType.swift */; };
 		DD6B7CB62C7B748B00B75029 /* TotalInsulinDisplayType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CB52C7B748B00B75029 /* TotalInsulinDisplayType.swift */; };
 		DD6B7CB92C7BAC6900B75029 /* NightscoutImportResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CB82C7BAC6900B75029 /* NightscoutImportResultView.swift */; };
+		DD6B7CBB2C7FBBFA00B75029 /* ReviewInsulinActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */; };
 		DD88C8E22C50420800F2D558 /* DefinitionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD88C8E12C50420800F2D558 /* DefinitionRow.swift */; };
 		DDD163122C4C689900CD525A /* OverrideStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163112C4C689900CD525A /* OverrideStateModel.swift */; };
 		DDD163142C4C68D300CD525A /* OverrideProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163132C4C68D300CD525A /* OverrideProvider.swift */; };
@@ -1096,6 +1097,7 @@
 		DD6B7CB32C7B71F700B75029 /* ForecastDisplayType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastDisplayType.swift; sourceTree = "<group>"; };
 		DD6B7CB52C7B748B00B75029 /* TotalInsulinDisplayType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalInsulinDisplayType.swift; sourceTree = "<group>"; };
 		DD6B7CB82C7BAC6900B75029 /* NightscoutImportResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutImportResultView.swift; sourceTree = "<group>"; };
+		DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewInsulinActionView.swift; sourceTree = "<group>"; };
 		DD88C8E12C50420800F2D558 /* DefinitionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefinitionRow.swift; sourceTree = "<group>"; };
 		DDD163112C4C689900CD525A /* OverrideStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideStateModel.swift; sourceTree = "<group>"; };
 		DDD163132C4C68D300CD525A /* OverrideProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProvider.swift; sourceTree = "<group>"; };
@@ -2639,6 +2641,7 @@
 			isa = PBXGroup;
 			children = (
 				DD6B7CB82C7BAC6900B75029 /* NightscoutImportResultView.swift */,
+				DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */,
 			);
 			path = ProfileImport;
 			sourceTree = "<group>";
@@ -3344,6 +3347,7 @@
 				45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */,
 				CE7CA3532A064973004BE681 /* tempPresetIntent.swift in Sources */,
 				D6DEC113821A7F1056C4AA1E /* NightscoutConfigDataFlow.swift in Sources */,
+				DD6B7CBB2C7FBBFA00B75029 /* ReviewInsulinActionView.swift in Sources */,
 				38E98A3025F52FF700C0CED0 /* Config.swift in Sources */,
 				BDB899882C564509006F3298 /* ForeCastChart.swift in Sources */,
 				110AEDE32C5193D200615CC9 /* BolusIntent.swift in Sources */,

+ 1 - 1
FreeAPS/Sources/Modules/AlgorithmAdvancedSettings/AlgorithmAdvancedSettingsProvider.swift

@@ -6,7 +6,7 @@ import LoopKitUI
 
 extension AlgorithmAdvancedSettings {
     final class Provider: BaseProvider, AlgorithmAdvancedSettingsProvider {
-        private let processQueue = DispatchQueue(label: "PumpSettingsEditorProvider.processQueue")
+        private let processQueue = DispatchQueue(label: "AlgorithmAdvancedSettingsProvider.processQueue")
         @Injected() private var broadcaster: Broadcaster!
 
         func settings() -> PumpSettings {

+ 1 - 1
FreeAPS/Sources/Modules/GeneralSettings/UnitsLimitsSettingsProvider.swift

@@ -10,7 +10,7 @@ protocol PumpSettingsObserver {
 
 extension UnitsLimitsSettings {
     final class Provider: BaseProvider, UnitsLimitsSettingsProvider {
-        private let processQueue = DispatchQueue(label: "PumpSettingsEditorProvider.processQueue")
+        private let processQueue = DispatchQueue(label: "UnitsLimitsSettingsProvider.processQueue")
         @Injected() private var broadcaster: Broadcaster!
 
         func settings() -> PumpSettings {

+ 58 - 0
FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigProvider.swift

@@ -1,10 +1,68 @@
 import Combine
 import Foundation
+import HealthKit
+import LoopKit
+import LoopKitUI
 
 extension NightscoutConfig {
     final class Provider: BaseProvider, NightscoutConfigProvider {
+        private let processQueue = DispatchQueue(label: "NightscoutConfigProvider.processQueue")
+        @Injected() private var broadcaster: Broadcaster!
+
         func checkConnection(url: URL, secret: String?) -> AnyPublisher<Void, Error> {
             NightscoutAPI(url: url, secret: secret).checkConnection()
         }
+
+        func getPumpSettings() -> PumpSettings {
+            storage.retrieve(OpenAPS.Settings.settings, as: PumpSettings.self)
+                ?? PumpSettings(from: OpenAPS.defaults(for: OpenAPS.Settings.settings))
+                ?? PumpSettings(insulinActionCurve: 6.0, maxBolus: 10, maxBasal: 2)
+        }
+
+        func savePumpSettings(settings: PumpSettings) -> AnyPublisher<Void, Error> {
+            func save(_ settings: PumpSettings) {
+                storage.save(settings, as: OpenAPS.Settings.settings)
+                processQueue.async {
+                    self.broadcaster.notify(PumpSettingsObserver.self, on: self.processQueue) {
+                        $0.pumpSettingsDidChange(settings)
+                    }
+                }
+            }
+
+            guard let pump = deviceManager?.pumpManager else {
+                save(settings)
+                return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher()
+            }
+            let limits = DeliveryLimits(
+                maximumBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: Double(settings.maxBasal)),
+                maximumBolus: HKQuantity(unit: .internationalUnit(), doubleValue: Double(settings.maxBolus))
+            )
+            return Future { promise in
+                self.processQueue.async {
+                    pump.syncDeliveryLimits(limits: limits) { result in
+                        switch result {
+                        case let .success(actual):
+                            // Store the limits from the pumpManager to ensure the correct values
+                            // Example: Dana pumps don't allow to set these limits, only to fetch them
+                            // This will ensure we always have the correct values stored
+                            save(PumpSettings(
+                                insulinActionCurve: settings.insulinActionCurve,
+                                maxBolus: Decimal(
+                                    actual.maximumBolus?
+                                        .doubleValue(for: .internationalUnit()) ?? Double(settings.maxBolus)
+                                ),
+                                maxBasal: Decimal(
+                                    actual.maximumBasalRate?
+                                        .doubleValue(for: .internationalUnitsPerHour) ?? Double(settings.maxBasal)
+                                )
+                            ))
+                            promise(.success(()))
+                        case let .failure(error):
+                            promise(.failure(error))
+                        }
+                    }
+                }
+            }.eraseToAnyPublisher()
+        }
     }
 }

+ 33 - 0
FreeAPS/Sources/Modules/NightscoutConfig/NightscoutConfigStateModel.swift

@@ -38,6 +38,15 @@ extension NightscoutConfig {
         @Published var isImportResultReviewPresented: Bool = false
         @Published var importErrors: [String] = []
         @Published var importStatus: ImportStatus = .finished
+        @Published var importedInsulinActionCurve: Decimal = 6
+
+        var pumpSettings: PumpSettings {
+            provider.getPumpSettings()
+        }
+
+        var isPumpSettingUnchanged: Bool {
+            pumpSettings.insulinActionCurve == importedInsulinActionCurve
+        }
 
         override func subscribe() {
             url = keychain.getValue(String.self, forKey: Config.urlKey) ?? ""
@@ -55,6 +64,8 @@ extension NightscoutConfig {
             subscribeSetting(\.localGlucosePort, on: $localPort.map(Int.init)) { localPort = Decimal($0) }
             subscribeSetting(\.uploadGlucose, on: $uploadGlucose, initial: { uploadGlucose = $0 })
 
+            importedInsulinActionCurve = pumpSettings.insulinActionCurve
+
             isConnectedToNS = nightscoutAPI != nil
         }
 
@@ -328,6 +339,28 @@ extension NightscoutConfig {
             secret = ""
             isConnectedToNS = false
         }
+
+        func saveReviewedInsulinAction() {
+            if !isPumpSettingUnchanged {
+                let settings = PumpSettings(
+                    insulinActionCurve: importedInsulinActionCurve,
+                    maxBolus: pumpSettings.maxBolus,
+                    maxBasal: pumpSettings.maxBasal
+                )
+                provider.savePumpSettings(settings: settings)
+                    .receive(on: DispatchQueue.main)
+                    .sink { _ in
+                        let settings = self.provider.getPumpSettings()
+                        self.importedInsulinActionCurve = settings.insulinActionCurve
+
+                        Task.detached(priority: .low) {
+                            debug(.nightscout, "Attempting to upload DIA to Nightscout after import review")
+                            await self.nightscoutManager.uploadProfiles()
+                        }
+                    } receiveValue: {}
+                    .store(in: &lifetime)
+            }
+        }
     }
 }
 

+ 2 - 2
FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift

@@ -72,8 +72,8 @@ extension NightscoutConfig {
                                             comment: "Nightscout Settings Import Alert"
                                         )
                                     ),
-                                    primaryButton: .destructive(
-                                        Text("Yes, Import"),
+                                    primaryButton: .default(
+                                        Text("Yes, Import!"),
                                         action: {
                                             Task {
                                                 await state.importSettings()

+ 16 - 16
FreeAPS/Sources/Modules/NightscoutConfig/View/ProfileImport/NightscoutImportResultView.swift

@@ -69,8 +69,8 @@ struct NightscoutImportResultView: BaseView {
                                     .fontWeight(.bold)
                                     .foregroundStyle(Color.green)
                             }
-                        }
-                    }.disabled(hasVisitedBasalProfileEditor)
+                        }.foregroundColor(hasVisitedBasalProfileEditor ? .secondary : .primary)
+                    }
 
                     NavigationLink(
                         destination: ISFEditor.RootView(resolver: resolver)
@@ -84,8 +84,8 @@ struct NightscoutImportResultView: BaseView {
                                     .fontWeight(.bold)
                                     .foregroundStyle(Color.green)
                             }
-                        }
-                    }.disabled(hasVisitedISFEditor)
+                        }.foregroundColor(hasVisitedISFEditor ? .secondary : .primary)
+                    }
 
                     NavigationLink(
                         destination: CarbRatioEditor.RootView(resolver: resolver)
@@ -99,11 +99,11 @@ struct NightscoutImportResultView: BaseView {
                                     .fontWeight(.bold)
                                     .foregroundStyle(Color.green)
                             }
-                        }
-                    }.disabled(hasVisitedCREditor)
+                        }.foregroundColor(hasVisitedCREditor ? .secondary : .primary)
+                    }
 
                     NavigationLink(
-                        destination: AlgorithmAdvancedSettings.RootView(resolver: resolver)
+                        destination: ReviewInsulinActionView(resolver: resolver, state: state)
                             .onDisappear { hasVisitedPumpSettingsEditor = true }
                     ) {
                         HStack {
@@ -114,8 +114,8 @@ struct NightscoutImportResultView: BaseView {
                                     .fontWeight(.bold)
                                     .foregroundStyle(Color.green)
                             }
-                        }
-                    }.disabled(hasVisitedPumpSettingsEditor)
+                        }.foregroundColor(hasVisitedPumpSettingsEditor ? .secondary : .primary)
+                    }
                 }.listRowBackground(Color.chart)
 
                 Section {
@@ -131,13 +131,13 @@ struct NightscoutImportResultView: BaseView {
                     }
                 }.listRowBackground(allViewsVisited ? Color(.systemBlue) : Color(.systemGray4))
             }
-            .toolbar(content: {
-                ToolbarItem(placement: .topBarLeading) {
-                    Button(action: { state.isImportResultReviewPresented = false }, label: {
-                        Text("Cancel")
-                    })
-                }
-            })
+//            .toolbar(content: {
+//                ToolbarItem(placement: .topBarLeading) {
+//                    Button(action: { state.isImportResultReviewPresented = false }, label: {
+//                        Text("Cancel")
+//                    })
+//                }
+//            })
             .navigationTitle("Review Import")
             .navigationBarTitleDisplayMode(.large)
             .scrollContentBackground(.hidden).background(color)

+ 74 - 0
FreeAPS/Sources/Modules/NightscoutConfig/View/ProfileImport/ReviewInsulinActionView.swift

@@ -0,0 +1,74 @@
+import Foundation
+
+import SwiftUI
+import Swinject
+
+struct ReviewInsulinActionView: BaseView {
+    var resolver: any Swinject.Resolver
+
+    @ObservedObject var state: NightscoutConfig.StateModel
+
+    @State private var shouldDisplayHint: Bool = false
+    @State private var hintDetent = PresentationDetent.large
+    @State private var selectedVerboseHint: String?
+    @State private var hintLabel: String?
+    @State private var decimalPlaceholder: Decimal = 0.0
+    @State private var booleanPlaceholder: Bool = false
+
+    @Environment(\.colorScheme) var colorScheme
+    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
+            )
+    }
+
+    var body: some View {
+        List {
+            SettingInputSection(
+                decimalValue: $state.importedInsulinActionCurve,
+                booleanValue: $booleanPlaceholder,
+                shouldDisplayHint: $shouldDisplayHint,
+                selectedVerboseHint: Binding(
+                    get: { selectedVerboseHint },
+                    set: {
+                        selectedVerboseHint = $0
+                        hintLabel = "Duration of Insulin Action"
+                    }
+                ),
+                units: state.units,
+                type: .decimal("dia"),
+                label: "Duration of Insulin Action",
+                miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                verboseHint: "Duration of Insulin Action… bla bla bla",
+                headerText: "Review imported DIA"
+            )
+        }
+        .sheet(isPresented: $shouldDisplayHint) {
+            SettingInputHintView(
+                hintDetent: $hintDetent,
+                shouldDisplayHint: $shouldDisplayHint,
+                hintLabel: hintLabel ?? "",
+                hintText: selectedVerboseHint ?? "",
+                sheetTitle: "Help"
+            )
+        }
+        .scrollContentBackground(.hidden).background(color)
+        .onAppear(perform: configureView)
+        .navigationTitle("DIA")
+        .navigationBarTitleDisplayMode(.automatic)
+        .onDisappear {
+            state.saveReviewedInsulinAction()
+        }
+    }
+}

+ 2 - 2
Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -1,5 +1,5 @@
 {
-  "originHash" : "59ac7eba66375d6eb406e758cb0b9964f4b3b0ae45c5665596f00384c32262b9",
+  "originHash" : "f5c836c216c4ca7d356e3777e58d6d4f9502b03f3974891349eb775f4c4cf750",
   "pins" : [
     {
       "identity" : "cryptoswift",
@@ -49,7 +49,7 @@
     {
       "identity" : "swiftcharts",
       "kind" : "remoteSourceControl",
-      "location" : "https://github.com/ivanschuetz/SwiftCharts.git",
+      "location" : "https://github.com/ivanschuetz/SwiftCharts",
       "state" : {
         "branch" : "master",
         "revision" : "c354c1945bb35a1f01b665b22474f6db28cba4a2"