| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- //
- // ManualTempBasalEntryView.swift
- // OmniKit
- //
- // Created by Pete Schwamb on 5/14/22.
- // Copyright © 2022 LoopKit Authors. All rights reserved.
- //
- import SwiftUI
- import LoopKitUI
- import LoopKit
- import HealthKit
- import OmniKit
- struct ManualTempBasalEntryView: View {
- @Environment(\.guidanceColors) var guidanceColors
- var enactBasal: ((Double,TimeInterval,@escaping (PumpManagerError?)->Void) -> Void)?
- var didCancel: (() -> Void)?
- @State private var rateEntered: Double = 0.0
- @State private var durationEntered: TimeInterval = .hours(0.5)
- @State private var showPicker: Bool = false
- @State private var error: PumpManagerError?
- @State private var enacting: Bool = false
- @State private var showingErrorAlert: Bool = false
- @State private var showingMissingConfigAlert: Bool = false
- var allowedRates: [Double]
- init(enactBasal: ((Double,TimeInterval,@escaping (PumpManagerError?)->Void) -> Void)? = nil, didCancel: (() -> Void)? = nil, allowedRates: [Double]) {
- self.enactBasal = enactBasal
- self.didCancel = didCancel
- self.allowedRates = allowedRates
- // This is to handle users migrating from OmnipodPumpManagerState with no max temp basal set
- if allowedRates.count <= 1 {
- _showingMissingConfigAlert = State(initialValue: true)
- }
- }
- private static let rateFormatter: QuantityFormatter = {
- let quantityFormatter = QuantityFormatter()
- quantityFormatter.setPreferredNumberFormatter(for: .internationalUnitsPerHour)
- quantityFormatter.numberFormatter.minimumFractionDigits = 2
- return quantityFormatter
- }()
- private var rateUnitsLabel: some View {
- Text(QuantityFormatter().string(from: .internationalUnitsPerHour))
- .foregroundColor(Color(.secondaryLabel))
- }
- private static let durationFormatter: QuantityFormatter = {
- let quantityFormatter = QuantityFormatter()
- quantityFormatter.setPreferredNumberFormatter(for: .hour())
- quantityFormatter.numberFormatter.minimumFractionDigits = 1
- quantityFormatter.numberFormatter.maximumFractionDigits = 1
- quantityFormatter.unitStyle = .long
- return quantityFormatter
- }()
- private var durationUnitsLabel: some View {
- Text(QuantityFormatter().string(from: .hour()))
- .foregroundColor(Color(.secondaryLabel))
- }
- func formatRate(_ rate: Double) -> String {
- let unit = HKUnit.internationalUnitsPerHour
- return ManualTempBasalEntryView.rateFormatter.string(from: HKQuantity(unit: unit, doubleValue: rate), for: unit) ?? ""
- }
- func formatDuration(_ duration: TimeInterval) -> String {
- let unit = HKUnit.hour()
- return ManualTempBasalEntryView.durationFormatter.string(from: HKQuantity(unit: unit, doubleValue: duration.hours), for: unit) ?? ""
- }
- var body: some View {
- NavigationView {
- VStack {
- List {
- HStack {
- Text(LocalizedString("Rate", comment: "Label text for basal rate summary"))
- Spacer()
- Text(String(format: LocalizedString("%1$@ for %2$@", comment: "Summary string for temporary basal rate configuration page"), formatRate(rateEntered), formatDuration(durationEntered)))
- }
- HStack {
- ResizeablePicker(selection: $rateEntered,
- data: allowedRates,
- formatter: { formatRate($0) })
- ResizeablePicker(selection: $durationEntered,
- data: Pod.supportedTempBasalDurations,
- formatter: { formatDuration($0) })
- }
- .frame(maxHeight: 162.0)
- .alert(isPresented: $showingMissingConfigAlert, content: { missingConfigAlert })
- Section {
- Text(LocalizedString("Your insulin delivery will not be automatically adjusted until the temporary basal rate finishes or is canceled.", comment: "Description text on manual temp basal action sheet"))
- .font(.footnote)
- .foregroundColor(.secondary)
- .fixedSize(horizontal: false, vertical: true)
- }
- }
- Button(action: {
- enacting = true
- enactBasal?(rateEntered, durationEntered) { (error) in
- if let error = error {
- self.error = error
- showingErrorAlert = true
- }
- enacting = false
- }
- }) {
- HStack {
- if enacting {
- ProgressView()
- } else {
- Text(LocalizedString("Set Temporary Basal", comment: "Button text for setting manual temporary basal rate"))
- }
- }
- }
- .buttonStyle(ActionButtonStyle(.primary))
- .padding()
- }
- .navigationTitle(LocalizedString("Temporary Basal", comment: "Navigation Title for ManualTempBasalEntryView"))
- .navigationBarItems(trailing: cancelButton)
- .alert(isPresented: $showingErrorAlert, content: { errorAlert })
- .disabled(enacting)
- }
- }
- var errorAlert: SwiftUI.Alert {
- let errorMessage = errorMessage(error: error!)
- return SwiftUI.Alert(
- title: Text(LocalizedString("Temporary Basal Failed", comment: "Alert title for a failure to set temporary basal")),
- message: errorMessage)
- }
- func errorMessage(error: PumpManagerError) -> Text {
- if let recovery = error.recoverySuggestion {
- return Text(String(format: LocalizedString("Unable to set a temporary basal rate: %1$@\n\n%2$@", comment: "Alert format string for a failure to set temporary basal with recovery suggestion. (1: error description) (2: recovery text)"), error.localizedDescription, recovery))
- } else {
- return Text(String(format: LocalizedString("Unable to set a temporary basal rate: %1$@", comment: "Alert format string for a failure to set temporary basal. (1: error description)"), error.localizedDescription))
- }
- }
- var missingConfigAlert: SwiftUI.Alert {
- return SwiftUI.Alert(
- title: Text(LocalizedString("Missing Config", comment: "Alert title for missing temp basal configuration")),
- message: Text(LocalizedString("This Pump has not been configured with a maximum basal rate because it was added before manual temp basal was a feature. Please go to Pump Settings in the settings CONFIGURATION section to set a new Max Basal.", comment: "Alert format string for missing temp basal configuration."))
- )
- }
- var cancelButton: some View {
- Button(LocalizedString("Cancel", comment: "Cancel button text in navigation bar on insert cannula screen")) {
- didCancel?()
- }
- .accessibility(identifier: "button_cancel")
- }
- }
|