Ivan Valkou пре 5 година
родитељ
комит
beb73568d5

+ 11 - 3
FreeAPS/Sources/APS/APSManager.swift

@@ -8,7 +8,7 @@ import Swinject
 protocol APSManager {
     func heartbeat(date: Date, force: Bool)
     func autotune() -> AnyPublisher<Autotune?, Never>
-    func enactBolus(amount: Double)
+    func enactBolus(amount: Double, isSMB: Bool)
     var pumpManager: PumpManagerUI? { get set }
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
     var pumpName: CurrentValueSubject<String, Never> { get }
@@ -18,6 +18,7 @@ protocol APSManager {
     func enactTempBasal(rate: Double, duration: TimeInterval)
     func makeProfiles() -> AnyPublisher<Bool, Never>
     func determineBasal() -> AnyPublisher<Bool, Never>
+    func roundBolus(amount: Decimal) -> Decimal
 }
 
 final class BaseAPSManager: APSManager, Injectable {
@@ -218,7 +219,12 @@ final class BaseAPSManager: APSManager, Injectable {
             .eraseToAnyPublisher()
     }
 
-    func enactBolus(amount: Double) {
+    func roundBolus(amount: Decimal) -> Decimal {
+        guard let pump = pumpManager, verifyStatus() else { return amount }
+        return Decimal(pump.roundToSupportedBolusVolume(units: Double(amount)))
+    }
+
+    func enactBolus(amount: Double, isSMB: Bool) {
         guard let pump = pumpManager, verifyStatus() else { return }
 
         let roundedAmout = pump.roundToSupportedBolusVolume(units: amount)
@@ -226,7 +232,9 @@ final class BaseAPSManager: APSManager, Injectable {
             switch result {
             case .success:
                 debug(.apsManager, "Bolus succeeded")
-                _ = self.determineBasal()
+                if !isSMB {
+                    self.determineBasal().sink { _ in }.store(in: &self.lifetime)
+                }
             case let .failure(error):
                 debug(.apsManager, "Bolus failed with error: \(error.localizedDescription)")
             }

+ 1 - 1
FreeAPS/Sources/Modules/AddCarbs/AddCarbsViewModel.swift

@@ -18,7 +18,7 @@ extension AddCarbs {
             carbsStorage.storeCarbs([
                 CarbsEntry(createdAt: date, carbs: carbs, enteredBy: CarbsEntry.manual)
             ])
-            showModal(for: .bolus)
+            showModal(for: .bolus(waitForDuggestion: true))
         }
     }
 }

+ 13 - 1
FreeAPS/Sources/Modules/Bolus/BolusBuilder.swift

@@ -1,3 +1,15 @@
+import Swinject
+
 extension Bolus {
-    final class Builder: BaseModuleBuilder<RootView, ViewModel<Provider>, Provider> {}
+    final class Builder: BaseModuleBuilder<RootView, ViewModel<Provider>, Provider> {
+        private let waitForSuggestion: Bool
+        init(resolver: Resolver, waitForSuggestion: Bool) {
+            self.waitForSuggestion = waitForSuggestion
+            super.init(resolver: resolver)
+        }
+
+        override func buildViewModel() -> Bolus.ViewModel<Bolus.Provider> {
+            ViewModel(provider: Provider(resolver: resolver), resolver: resolver, waitForSuggestion: waitForSuggestion)
+        }
+    }
 }

+ 3 - 1
FreeAPS/Sources/Modules/Bolus/BolusDataFlow.swift

@@ -2,4 +2,6 @@ enum Bolus {
     enum Config {}
 }
 
-protocol BolusProvider: Provider {}
+protocol BolusProvider: Provider {
+    var suggestion: Suggestion? { get }
+}

+ 5 - 1
FreeAPS/Sources/Modules/Bolus/BolusProvider.swift

@@ -1,3 +1,7 @@
 extension Bolus {
-    final class Provider: BaseProvider, BolusProvider {}
+    final class Provider: BaseProvider, BolusProvider {
+        var suggestion: Suggestion? {
+            storage.retrieve(OpenAPS.Enact.suggested, as: Suggestion.self)
+        }
+    }
 }

+ 43 - 3
FreeAPS/Sources/Modules/Bolus/BolusViewModel.swift

@@ -1,21 +1,61 @@
 import SwiftUI
+import Swinject
 
 extension Bolus {
     class ViewModel<Provider>: BaseViewModel<Provider>, ObservableObject where Provider: BolusProvider {
         @Injected() var unlockmanager: UnlockManager!
         @Injected() var apsManager: APSManager!
+        @Injected() var broadcaster: Broadcaster!
+        @Injected() var settingsManager: SettingsManager!
         @Published var amount: Decimal = 0
+        @Published var inslinRecommended: Decimal = 0
+        @Published var inslinRequired: Decimal = 0
+        @Published var waitForSuggestion: Bool
+        let waitForSuggestionInitial: Bool
 
-        override func subscribe() {}
+        init(provider: Provider, resolver: Resolver, waitForSuggestion: Bool) {
+            self.waitForSuggestion = waitForSuggestion
+            waitForSuggestionInitial = waitForSuggestion
+            super.init(provider: provider, resolver: resolver)
+        }
+
+        required init(provider _: Provider, resolver _: Resolver) {
+            error(.default, "init(provider:resolver:) has not been implemented")
+        }
+
+        override func subscribe() {
+            setupInsulinRequired()
+            broadcaster.register(SuggestionObserver.self, observer: self)
+        }
 
         func add() {
-            guard amount > 0 else { return }
+            guard amount > 0 else {
+                showModal(for: nil)
+                return
+            }
             unlockmanager.unlock()
                 .sink { _ in } receiveValue: {
-                    self.apsManager.enactBolus(amount: Double(self.amount))
+                    self.apsManager.enactBolus(amount: Double(self.amount), isSMB: false)
                     self.showModal(for: nil)
                 }
                 .store(in: &lifetime)
         }
+
+        func setupInsulinRequired() {
+            DispatchQueue.main.async {
+                self.inslinRequired = self.provider.suggestion?.insulinReq ?? 0
+                self.inslinRecommended = self.apsManager
+                    .roundBolus(amount: max(self.inslinRequired * (self.settingsManager.settings.insulinReqFraction ?? 0.7), 0))
+            }
+        }
+    }
+}
+
+extension Bolus.ViewModel: SuggestionObserver {
+    func suggestionDidUpdate(_: Suggestion) {
+        DispatchQueue.main.async {
+            self.waitForSuggestion = false
+        }
+        setupInsulinRequired()
     }
 }

+ 49 - 9
FreeAPS/Sources/Modules/Bolus/View/BolusRootView.swift

@@ -13,18 +13,58 @@ extension Bolus {
 
         var body: some View {
             Form {
-                Section {
-                    HStack {
-                        Text("Amount")
-                        Spacer()
-                        DecimalTextField("0", value: $viewModel.amount, formatter: formatter, autofocus: true, cleanInput: true)
-                        Text("U").foregroundColor(.secondary)
+                Section(header: Text("Recommendation")) {
+                    if viewModel.waitForSuggestion {
+                        HStack {
+                            Text("Wait please").foregroundColor(.secondary)
+                            Spacer()
+                            ProgressView()
+                        }
+                    } else {
+                        HStack {
+                            Text("Insulin required").foregroundColor(.secondary)
+                            Spacer()
+                            Text(formatter.string(from: viewModel.inslinRequired as NSNumber)! + " U").foregroundColor(.secondary)
+                        }.contentShape(Rectangle())
+                            .onTapGesture {
+                                viewModel.amount = viewModel.inslinRecommended
+                            }
+                        HStack {
+                            Text("Insulin recommended")
+                            Spacer()
+                            Text(formatter.string(from: viewModel.inslinRecommended as NSNumber)! + " U")
+                        }.contentShape(Rectangle())
+                            .onTapGesture {
+                                viewModel.amount = viewModel.inslinRecommended
+                            }
                     }
                 }
 
-                Section {
-                    Button { viewModel.add() }
-                    label: { Text("Enact") }
+                if !viewModel.waitForSuggestion {
+                    Section(header: Text("Bolus")) {
+                        HStack {
+                            Text("Amount")
+                            Spacer()
+                            DecimalTextField(
+                                "0",
+                                value: $viewModel.amount,
+                                formatter: formatter,
+                                autofocus: true,
+                                cleanInput: true
+                            )
+                            Text("U").foregroundColor(.secondary)
+                        }
+                    }
+
+                    Section {
+                        Button { viewModel.add() }
+                        label: { Text("Enact bolus") }
+
+                        if viewModel.waitForSuggestionInitial {
+                            Button { viewModel.showModal(for: nil) }
+                            label: { Text("Continue without bolus") }
+                        }
+                    }
                 }
             }
             .navigationTitle("Enact Bolus")

+ 0 - 16
FreeAPS/Sources/Modules/Home/HomeViewModel.swift

@@ -115,22 +115,6 @@ extension Home {
             provider.heartbeatNow()
         }
 
-        func addTempTarget() {
-            showModal(for: .addTempTarget)
-        }
-
-        func manualTampBasal() {
-            showModal(for: .manualTempBasal)
-        }
-
-        func bolus() {
-            showModal(for: .bolus)
-        }
-
-        func settings() {
-            showModal(for: .settings)
-        }
-
         private func setupGlucose() {
             DispatchQueue.main.async {
                 self.glucose = self.provider.filteredGlucose(hours: self.filteredHours)

+ 1 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -207,7 +207,7 @@ extension Home {
                                     .frame(width: 24, height: 24)
                             }.foregroundColor(.loopYellow)
                             Spacer()
-                            Button { viewModel.showModal(for: .bolus) }
+                            Button { viewModel.showModal(for: .bolus(waitForDuggestion: false)) }
                             label: {
                                 Image("bolus")
                                     .renderingMode(.template)

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

@@ -19,7 +19,7 @@ enum Screen: Identifiable {
     case preferencesEditor
     case addCarbs
     case addTempTarget
-    case bolus
+    case bolus(waitForDuggestion: Bool)
     case manualTempBasal
     case autotuneConfig
     case dataTable
@@ -64,8 +64,8 @@ extension Screen {
             return AddCarbs.Builder(resolver: resolver).buildView()
         case .addTempTarget:
             return AddTempTarget.Builder(resolver: resolver).buildView()
-        case .bolus:
-            return Bolus.Builder(resolver: resolver).buildView()
+        case let .bolus(waitForSuggestion):
+            return Bolus.Builder(resolver: resolver, waitForSuggestion: waitForSuggestion).buildView()
         case .manualTempBasal:
             return ManualTempBasal.Builder(resolver: resolver).buildView()
         case .autotuneConfig:

+ 4 - 2
FreeAPS/Sources/Views/DecimalTextField.swift

@@ -62,8 +62,10 @@ struct DecimalTextField: UIViewRepresentable {
         return textfield
     }
 
-    func updateUIView(_: UITextField, context _: Context) {
-//        textField.text = formatter.string(for: value)
+    func updateUIView(_ textField: UITextField, context _: Context) {
+        if value != 0 {
+            textField.text = formatter.string(for: value)
+        }
     }
 
     func makeCoordinator() -> Coordinator {