Ivan Valkou 5 лет назад
Родитель
Сommit
d4f8d9fc9d

+ 7 - 2
FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorDataFlow.swift

@@ -1,5 +1,6 @@
+import Combine
+import Foundation
 import SwiftDate
-import SwiftUI
 
 enum BasalProfileEditor {
     enum Config {
@@ -26,4 +27,8 @@ enum BasalProfileEditor {
     }
 }
 
-protocol BasalProfileEditorProvider: Provider {}
+protocol BasalProfileEditorProvider: Provider {
+    var profile: [BasalProfileEntry] { get }
+    var supportedBasalRates: [Double]? { get }
+    func saveProfile(_ profile: [BasalProfileEntry]) -> AnyPublisher<Void, Error>
+}

+ 40 - 1
FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorProvider.swift

@@ -1,3 +1,42 @@
+import Combine
+import Foundation
+import LoopKit
+
 extension BasalProfileEditor {
-    final class Provider: BaseProvider, BasalProfileEditorProvider {}
+    final class Provider: BaseProvider, BasalProfileEditorProvider {
+        private let processQueue = DispatchQueue(label: "BasalProfileEditorProvider.processQueue")
+
+        var profile: [BasalProfileEntry] {
+            (try? storage.retrieve(OpenAPS.Settings.basalProfile, as: [BasalProfileEntry].self))
+                ?? [BasalProfileEntry](from: OpenAPS.defaults(for: OpenAPS.Settings.basalProfile))
+                ?? []
+        }
+
+        var supportedBasalRates: [Double]? {
+            deviceManager.pumpManager?.supportedBasalRates
+        }
+
+        func saveProfile(_ profile: [BasalProfileEntry]) -> AnyPublisher<Void, Error> {
+            guard let pump = deviceManager?.pumpManager else {
+                try? storage.save(profile, as: OpenAPS.Settings.basalProfile)
+                return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher()
+            }
+
+            let syncValues = profile.map {
+                RepeatingScheduleValue(startTime: TimeInterval($0.minutes * 60), value: Double($0.rate))
+            }
+
+            return Future { promise in
+                pump.syncBasalRateSchedule(items: syncValues) { result in
+                    switch result {
+                    case .success:
+                        try? self.storage.save(profile, as: OpenAPS.Settings.basalProfile)
+                        promise(.success(()))
+                    case let .failure(error):
+                        promise(.failure(error))
+                    }
+                }
+            }.eraseToAnyPublisher()
+        }
+    }
 }

+ 24 - 5
FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorViewModel.swift

@@ -5,13 +5,12 @@ extension BasalProfileEditor {
         @Injected() var devicemanager: DeviceDataManager!
         @Published var syncInProgress = false
         @Published var items: [Item] = []
-        private var maxBasal = 2
 
         var timeValues: [TimeInterval] {
             stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 }
         }
 
-        private(set) var rateValues: [Double] = stride(from: 0.05, to: 10.01, by: 0.05).map { $0 }
+        private(set) var rateValues: [Double] = []
 
         var canAdd: Bool {
             guard let lastItem = items.last else { return true }
@@ -19,8 +18,11 @@ extension BasalProfileEditor {
         }
 
         override func subscribe() {
-            if let pump = devicemanager.pumpManager {
-                rateValues = pump.supportedBasalRates
+            rateValues = provider.supportedBasalRates ?? stride(from: 0.05, to: 10.01, by: 0.05).map { $0 }
+            items = provider.profile.map { value in
+                let timeIndex = timeValues.firstIndex(of: Double(value.minutes * 60)) ?? 0
+                let rateIndex = rateValues.firstIndex(of: Double(value.rate)) ?? 0
+                return Item(rateIndex: rateIndex, selectedIndex: timeIndex)
             }
         }
 
@@ -37,7 +39,24 @@ extension BasalProfileEditor {
             items.append(newItem)
         }
 
-        func save() {}
+        func save() {
+            syncInProgress = true
+            let profile = items.enumerated().map { index, item -> BasalProfileEntry in
+                let fotmatter = DateFormatter()
+                fotmatter.timeZone = TimeZone(secondsFromGMT: 0)
+                fotmatter.dateFormat = "HH:mm:ss"
+                let date = Date(timeIntervalSince1970: self.timeValues[item.timeIndex])
+                let minutes = Int(date.timeIntervalSince1970 / 60)
+                let rate = Decimal(self.rateValues[item.rateIndex])
+                return BasalProfileEntry(i: index, start: fotmatter.string(from: date), minutes: minutes, rate: rate)
+            }
+            provider.saveProfile(profile)
+                .receive(on: DispatchQueue.main)
+                .sink { _ in
+                    self.syncInProgress = false
+                } receiveValue: {}
+                .store(in: &lifetime)
+        }
 
         func validate() {
             DispatchQueue.main.async {

+ 32 - 23
FreeAPS/Sources/Modules/BasalProfileEditor/View/BasalProfileEditorRootView.swift

@@ -21,33 +21,20 @@ extension BasalProfileEditor {
         var body: some View {
             Form {
                 Section(header: Text("Schedule")) {
-                    List {
-                        ForEach(viewModel.items.indexed(), id: \.1.id) { index, item in
-                            NavigationLink(destination: pickers(for: index)) {
-                                HStack {
-                                    Text("Rate").foregroundColor(.secondary)
-                                    Text(
-                                        "\(rateFormatter.string(from: viewModel.rateValues[item.rateIndex] as NSNumber) ?? "0") U/h"
-                                    )
-                                    Spacer()
-                                    Text("starts at").foregroundColor(.secondary)
-                                    Text(
-                                        "\(dateFormatter.string(from: Date(timeIntervalSince1970: viewModel.timeValues[item.timeIndex])))"
-                                    )
-                                }
-                            }
-                            .moveDisabled(true)
-                        }
-                        .onDelete(perform: onDelete)
-                    }
+                    list
                     addButton
                 }
                 Section {
-                    Button { viewModel.save() }
-                    label: {
-                        Text(viewModel.syncInProgress ? "Saving..." : "Save on Pump")
+                    HStack {
+                        if viewModel.syncInProgress {
+                            ProgressView().padding(.trailing, 10)
+                        }
+                        Button { viewModel.save() }
+                        label: {
+                            Text(viewModel.syncInProgress ? "Saving..." : "Save on Pump")
+                        }
+                        .disabled(viewModel.syncInProgress || viewModel.items.isEmpty)
                     }
-                    .disabled(viewModel.syncInProgress || viewModel.items.isEmpty)
                 }
             }
             .navigationTitle("Basal Profile")
@@ -101,6 +88,28 @@ extension BasalProfileEditor {
             }
         }
 
+        private var list: some View {
+            List {
+                ForEach(viewModel.items.indexed(), id: \.1.id) { index, item in
+                    NavigationLink(destination: pickers(for: index)) {
+                        HStack {
+                            Text("Rate").foregroundColor(.secondary)
+                            Text(
+                                "\(rateFormatter.string(from: viewModel.rateValues[item.rateIndex] as NSNumber) ?? "0") U/h"
+                            )
+                            Spacer()
+                            Text("starts at").foregroundColor(.secondary)
+                            Text(
+                                "\(dateFormatter.string(from: Date(timeIntervalSince1970: viewModel.timeValues[item.timeIndex])))"
+                            )
+                        }
+                    }
+                    .moveDisabled(true)
+                }
+                .onDelete(perform: onDelete)
+            }
+        }
+
         private var addButton: some View {
             guard viewModel.canAdd else {
                 return AnyView(EmptyView())

+ 2 - 0
FreeAPS/Sources/Modules/Base/BaseProvider.swift

@@ -11,6 +11,8 @@ class BaseProvider: Provider, Injectable {
     let user = CurrentValueSubject<User?, Never>(nil)
     var lifetime = Set<AnyCancellable>()
     @Injected() var authorizationManager: AuthorizationManager!
+    @Injected() var deviceManager: DeviceDataManager!
+    @Injected() var storage: FileStorage!
 
     required init(resolver: Resolver) {
         injectServices(resolver)

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

@@ -2,16 +2,7 @@ import Foundation
 
 extension ConfigEditor {
     final class Provider: BaseProvider, ConfigEditorProvider {
-        @Injected() private var storage: FileStorage!
-
         func load(file: String) -> RawJSON {
-//            if let value = try? storage.retrieve(file, as: RawJSON.self) {
-//                return value
-//            } else if let value = try? storage.retrieve(file, as: [PumpHistoryEvent].self) {
-//                return value.rawJSON
-//            } else if let value = try? storage.retrieve(file, as: [BloodGlucose].self) {
-//                return value.rawJSON
-//            }
             storage.retrieveRaw(file) ?? OpenAPS.defaults(for: file)
         }
 

+ 0 - 2
FreeAPS/Sources/Modules/PumpSettingsEditor/PumpSettingsEditorProvider.swift

@@ -5,8 +5,6 @@ import LoopKitUI
 extension PumpSettingsEditor {
     final class Provider: BaseProvider, PumpSettingsEditorProvider {
         private let processQueue = DispatchQueue(label: "PumpSettingsEditorProvider.processQueue")
-        @Injected() var deviceManager: DeviceDataManager!
-        @Injected() var storage: FileStorage!
 
         func settings() -> PumpSettings {
             (try? storage.retrieve(OpenAPS.Settings.settings, as: PumpSettings.self))

+ 9 - 4
FreeAPS/Sources/Modules/PumpSettingsEditor/View/PumpSettingsEditorRootView.swift

@@ -31,11 +31,16 @@ extension PumpSettingsEditor {
                 }
 
                 Section {
-                    Button { viewModel.save() }
-                    label: {
-                        Text(viewModel.syncInProgress ? "Saving..." : "Save on Pump")
+                    HStack {
+                        if viewModel.syncInProgress {
+                            ProgressView().padding(.trailing, 10)
+                        }
+                        Button { viewModel.save() }
+                        label: {
+                            Text(viewModel.syncInProgress ? "Saving..." : "Save on Pump")
+                        }
+                        .disabled(viewModel.syncInProgress)
                     }
-                    .disabled(viewModel.syncInProgress)
                 }
             }
             .navigationTitle("Pump Settings")