Просмотр исходного кода

remove unused code, add arrows for navigation in treatments view, refactoring

polscm32 aka Marvout 1 год назад
Родитель
Сommit
7a98aca260

+ 20 - 45
FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift

@@ -335,31 +335,6 @@ extension Bolus {
             }
         }
 
-        private func savePumpInsulin(amount _: Decimal) {
-            backgroundContext.perform {
-                // create pump event
-                let newPumpEvent = PumpEventStored(context: self.backgroundContext)
-                newPumpEvent.timestamp = Date()
-                newPumpEvent.type = PumpEvent.bolus.rawValue
-
-                // create bolus entry and specify relationship to pump event
-                let newBolusEntry = BolusStored(context: self.backgroundContext)
-                newBolusEntry.pumpEvent = newPumpEvent
-                newBolusEntry.amount = self.amount as NSDecimalNumber
-                newBolusEntry.isExternal = false
-                newBolusEntry.isSMB = false
-
-                do {
-                    guard self.backgroundContext.hasChanges else { return }
-                    try self.backgroundContext.save()
-                } catch let error as NSError {
-                    debugPrint(
-                        "\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save Bolus with error: \(error.userInfo)"
-                    )
-                }
-            }
-        }
-
         // MARK: - EXTERNAL INSULIN
 
         @MainActor func addExternalInsulin() async {
@@ -747,41 +722,41 @@ extension Bolus.StateModel {
         return (minForecast, maxForecast)
     }
 
-    @MainActor func updateForecasts(with forecastData: Determination? = nil) async {
+    @MainActor  func updateForecasts(with forecastData: Determination? = nil) async {
         if let forecastData = forecastData {
             simulatedDetermination = forecastData
-            predictionsForChart = simulatedDetermination?.predictions
         } else {
-            // Run simulateDetermineBasal on a background thread
-            let result = await Task.detached { [self] in
+            simulatedDetermination = await Task.detached { [self] in
                 await apsManager.simulateDetermineBasal(carbs: carbs, iob: amount)
             }.value
-
-            simulatedDetermination = result
-            predictionsForChart = result?.predictions
         }
 
-        let iob: [Int] = predictionsForChart?.iob ?? []
-        let zt: [Int] = predictionsForChart?.zt ?? []
-        let cob: [Int] = predictionsForChart?.cob ?? []
-        let uam: [Int] = predictionsForChart?.uam ?? []
+        predictionsForChart = simulatedDetermination?.predictions
 
-        // Filter out the empty arrays and find the maximum length of the remaining arrays
-        let nonEmptyArrays: [[Int]] = [iob, zt, cob, uam].filter { !$0.isEmpty }
-        guard !nonEmptyArrays.isEmpty, let maxCount = nonEmptyArrays.map(\.count).max(), maxCount > 0 else {
+        let nonEmptyArrays = [
+            predictionsForChart?.iob,
+            predictionsForChart?.zt,
+            predictionsForChart?.cob,
+            predictionsForChart?.uam
+        ]
+        .compactMap { $0 }
+        .filter { !$0.isEmpty }
+
+        guard !nonEmptyArrays.isEmpty else {
             minForecast = []
             maxForecast = []
             return
         }
 
-        minForecast = (0 ..< maxCount).map { index -> Int in
-            let valuesAtCurrentIndex = nonEmptyArrays.compactMap { $0.indices.contains(index) ? $0[index] : nil }
-            return valuesAtCurrentIndex.min() ?? 0
+        let maxCount = min(36, nonEmptyArrays.map(\.count).max() ?? 0)
+        guard maxCount > 0 else { return }
+
+        minForecast = (0 ..< maxCount).map { index in
+            nonEmptyArrays.compactMap { $0.indices.contains(index) ? $0[index] : nil }.min() ?? 0
         }
 
-        maxForecast = (0 ..< maxCount).map { index -> Int in
-            let valuesAtCurrentIndex = nonEmptyArrays.compactMap { $0.indices.contains(index) ? $0[index] : nil }
-            return valuesAtCurrentIndex.max() ?? 0
+        maxForecast = (0 ..< maxCount).map { index in
+            nonEmptyArrays.compactMap { $0.indices.contains(index) ? $0[index] : nil }.max() ?? 0
         }
     }
 }

+ 58 - 19
FreeAPS/Sources/Modules/Bolus/View/BolusRootView.swift

@@ -10,6 +10,7 @@ extension Bolus {
             case carbs
             case fat
             case protein
+            case bolus
         }
 
         @FocusState private var focusedField: FocusedField?
@@ -95,7 +96,14 @@ extension Bolus {
             HStack {
                 Text("Fat").foregroundColor(.orange)
                 Spacer()
-                TextFieldWithToolBar(text: $state.fat, placeholder: "0", keyboardType: .numberPad, numberFormatter: mealFormatter)
+                TextFieldWithToolBar(
+                    text: $state.fat,
+                    placeholder: "0",
+                    keyboardType: .numberPad,
+                    numberFormatter: mealFormatter,
+                    previousTextField: { focusOnPreviousTextField(index: 2) },
+                    nextTextField: { focusOnNextTextField(index: 2) }
+                ).focused($focusedField, equals: .fat)
                 Text("g").foregroundColor(.secondary)
             }
             HStack {
@@ -105,8 +113,10 @@ extension Bolus {
                     text: $state.protein,
                     placeholder: "0",
                     keyboardType: .numberPad,
-                    numberFormatter: mealFormatter
-                )
+                    numberFormatter: mealFormatter,
+                    previousTextField: { focusOnPreviousTextField(index: 3) },
+                    nextTextField: { focusOnNextTextField(index: 3) }
+                ).focused($focusedField, equals: .protein)
                 Text("g").foregroundColor(.secondary)
             }
         }
@@ -119,15 +129,43 @@ extension Bolus {
                     text: $state.carbs,
                     placeholder: "0",
                     keyboardType: .numberPad,
-                    numberFormatter: mealFormatter
-                )
-                .onChange(of: state.carbs) { _ in
-                    handleDebouncedInput()
-                }
+                    numberFormatter: mealFormatter,
+                    previousTextField: { focusOnPreviousTextField(index: 1) },
+                    nextTextField: { focusOnNextTextField(index: 1) }
+                ).focused($focusedField, equals: .carbs)
+                    .onChange(of: state.carbs) { _ in
+                        handleDebouncedInput()
+                    }
                 Text("g").foregroundColor(.secondary)
             }
         }
 
+        func focusOnPreviousTextField(index: Int) {
+            switch index {
+            case 2:
+                focusedField = .carbs
+            case 3:
+                focusedField = .fat
+            case 4:
+                focusedField = .protein
+            default:
+                break
+            }
+        }
+
+        func focusOnNextTextField(index: Int) {
+            switch index {
+            case 1:
+                focusedField = .fat
+            case 2:
+                focusedField = .protein
+            case 3:
+                focusedField = .bolus
+            default:
+                break
+            }
+        }
+
         var body: some View {
             ZStack(alignment: .center) {
                 VStack {
@@ -232,21 +270,22 @@ extension Bolus {
                                     placeholder: "0",
                                     textColor: colorScheme == .dark ? .white : .blue,
                                     maxLength: 5,
-                                    numberFormatter: formatter
-                                ).onChange(of: state.amount) { _ in
-                                    Task {
-                                        await state.updateForecasts()
+                                    numberFormatter: formatter,
+                                    previousTextField: { focusOnPreviousTextField(index: 4) },
+                                    nextTextField: { focusOnNextTextField(index: 4) }
+                                ).focused($focusedField, equals: .bolus)
+                                    .onChange(of: state.amount) { _ in
+                                        Task {
+                                            await state.updateForecasts()
+                                        }
                                     }
-                                }
                                 Text(" U").foregroundColor(.secondary)
                             }
 
-                            if state.amount > 0 {
-                                HStack {
-                                    Text("External insulin")
-                                    Spacer()
-                                    Toggle("", isOn: $state.externalInsulin).toggleStyle(Checkbox())
-                                }
+                            HStack {
+                                Text("External insulin")
+                                Spacer()
+                                Toggle("", isOn: $state.externalInsulin).toggleStyle(Checkbox())
                             }
                         }.listRowBackground(Color.chart)
 

+ 3 - 2
FreeAPS/Sources/Modules/Bolus/View/ForeCastChart.swift

@@ -21,8 +21,9 @@ struct ForeCastChart: View {
                 .padding(.vertical, 3)
             HStack {
                 Spacer()
-                Text("evBG").font(.footnote).foregroundStyle(.primary)
-                Image(systemName: "arrow.right").font(.footnote).foregroundStyle(.secondary)
+                Image(systemName: "arrow.right.circle")
+                    .font(.system(size: 16, weight: .bold))
+//                Image(systemName: "arrow.right").font(.footnote).foregroundStyle(.secondary)
 
                 if let eventualBG = state.simulatedDetermination?.eventualBG {
                     HStack {

+ 9 - 15
FreeAPS/Sources/Modules/Home/HomeStateModel.swift

@@ -979,12 +979,12 @@ extension Home.StateModel {
     }
 
     // Update forecast data and UI on the main thread
-    @MainActor func updateForecastData() async {
+    @MainActor  func updateForecastData() async {
         // Preprocess forecast data on a background thread
         let forecastData = await preprocessForecastData()
 
-        var allForecastValues: [[ForecastValue]] = []
-        var preprocessedData: [(id: UUID, forecast: Forecast, forecastValue: ForecastValue)] = []
+        var allForecastValues = [[ForecastValue]]()
+        var preprocessedData = [(id: UUID, forecast: Forecast, forecastValue: ForecastValue)]()
 
         // Use a task group to fetch forecast values concurrently
         await withTaskGroup(of: (UUID, Forecast?, [ForecastValue]).self) { group in
@@ -999,10 +999,7 @@ extension Home.StateModel {
                 guard let forecast = forecast, !forecastValues.isEmpty else { continue }
 
                 allForecastValues.append(forecastValues)
-
-                for forecastValue in forecastValues {
-                    preprocessedData.append((id: id, forecast: forecast, forecastValue: forecastValue))
-                }
+                preprocessedData.append(contentsOf: forecastValues.map { (id: id, forecast: forecast, forecastValue: $0) })
             }
         }
 
@@ -1016,18 +1013,15 @@ extension Home.StateModel {
         }
 
         let maxCount = min(36, allForecastValues.map(\.count).max() ?? 0)
+        guard maxCount > 0 else { return }
 
         // Calculate min and max forecast values
-        minForecast = (0 ..< maxCount).map { index -> Int in
-            let valuesAtCurrentIndex = allForecastValues
-                .compactMap { $0.indices.contains(index) ? Int($0[index].value) : nil }
-            return valuesAtCurrentIndex.min() ?? 0
+        minForecast = (0 ..< maxCount).map { index in
+            allForecastValues.compactMap { $0.indices.contains(index) ? Int($0[index].value) : nil }.min() ?? 0
         }
 
-        maxForecast = (0 ..< maxCount).map { index -> Int in
-            let valuesAtCurrentIndex = allForecastValues
-                .compactMap { $0.indices.contains(index) ? Int($0[index].value) : nil }
-            return valuesAtCurrentIndex.max() ?? 0
+        maxForecast = (0 ..< maxCount).map { index in
+            allForecastValues.compactMap { $0.indices.contains(index) ? Int($0[index].value) : nil }.max() ?? 0
         }
     }
 }

+ 28 - 2
FreeAPS/Sources/Views/TextFieldWithToolBar.swift

@@ -15,6 +15,8 @@ public struct TextFieldWithToolBar: UIViewRepresentable {
     var textFieldDidBeginEditing: (() -> Void)?
     var numberFormatter: NumberFormatter
     var allowDecimalSeparator: Bool
+    var previousTextField: (() -> Void)?
+    var nextTextField: (() -> Void)?
 
     public init(
         text: Binding<Decimal>,
@@ -29,7 +31,9 @@ public struct TextFieldWithToolBar: UIViewRepresentable {
         isDismissible: Bool = true,
         textFieldDidBeginEditing: (() -> Void)? = nil,
         numberFormatter: NumberFormatter,
-        allowDecimalSeparator: Bool = true
+        allowDecimalSeparator: Bool = true,
+        previousTextField: (() -> Void)? = nil,
+        nextTextField: (() -> Void)? = nil
     ) {
         _text = text
         self.placeholder = placeholder
@@ -45,6 +49,8 @@ public struct TextFieldWithToolBar: UIViewRepresentable {
         self.numberFormatter = numberFormatter
         self.numberFormatter.numberStyle = .decimal
         self.allowDecimalSeparator = allowDecimalSeparator
+        self.previousTextField = previousTextField
+        self.nextTextField = nextTextField
     }
 
     public func makeUIView(context: Context) -> UITextField {
@@ -77,8 +83,20 @@ public struct TextFieldWithToolBar: UIViewRepresentable {
             target: context.coordinator,
             action: #selector(Coordinator.clearText)
         )
+        let previousButton = UIBarButtonItem(
+            image: UIImage(systemName: "chevron.up"),
+            style: .plain,
+            target: context.coordinator,
+            action: #selector(Coordinator.previousTextField)
+        )
+        let nextButton = UIBarButtonItem(
+            image: UIImage(systemName: "chevron.down"),
+            style: .plain,
+            target: context.coordinator,
+            action: #selector(Coordinator.nextTextField)
+        )
 
-        toolbar.items = [clearButton, flexibleSpace, doneButton]
+        toolbar.items = [clearButton, previousButton, nextButton, flexibleSpace, doneButton]
         toolbar.sizeToFit()
         return toolbar
     }
@@ -136,6 +154,14 @@ public struct TextFieldWithToolBar: UIViewRepresentable {
             }
         }
 
+        @objc fileprivate func previousTextField() {
+            parent.previousTextField?()
+        }
+
+        @objc fileprivate func nextTextField() {
+            parent.nextTextField?()
+        }
+
         // Helper method to calculate the number of decimal places in a string
         fileprivate func calculateDecimalPlaces(in string: String) -> Int {
             guard let decimalSeparator = decimalFormatter.decimalSeparator else { return 0 }