|
|
@@ -7,6 +7,7 @@ extension Bolus {
|
|
|
let waitForSuggestion: Bool
|
|
|
let manualBolus: Bool
|
|
|
@StateObject var state = StateModel()
|
|
|
+
|
|
|
@State private var isAddInsulinAlertPresented = false
|
|
|
@State private var presentInfo = false
|
|
|
@State private var displayError = false
|
|
|
@@ -20,6 +21,12 @@ extension Bolus {
|
|
|
return formatter
|
|
|
}
|
|
|
|
|
|
+ private var fractionDigits: Int {
|
|
|
+ if state.units == .mmolL {
|
|
|
+ return 1
|
|
|
+ } else { return 0 }
|
|
|
+ }
|
|
|
+
|
|
|
var body: some View {
|
|
|
Form {
|
|
|
Section {
|
|
|
@@ -70,13 +77,11 @@ extension Bolus {
|
|
|
}
|
|
|
}
|
|
|
header: { Text("Bolus") }
|
|
|
-
|
|
|
Section {
|
|
|
Button { state.add() }
|
|
|
label: { Text("Enact bolus") }
|
|
|
.disabled(state.amount <= 0)
|
|
|
}
|
|
|
-
|
|
|
Section {
|
|
|
if waitForSuggestion {
|
|
|
Button { state.showModal(for: nil) }
|
|
|
@@ -87,17 +92,39 @@ extension Bolus {
|
|
|
.disabled(state.amount <= 0)
|
|
|
}
|
|
|
}
|
|
|
+ .alert(isPresented: $isAddInsulinAlertPresented) {
|
|
|
+ Alert(
|
|
|
+ title: Text("Are you sure?"),
|
|
|
+ message: Text(
|
|
|
+ "Add " + formatter
|
|
|
+ .string(from: state.amount as NSNumber)! + NSLocalizedString(" U", comment: "Insulin unit") +
|
|
|
+ NSLocalizedString(" without bolusing", comment: "Add insulin without bolusing alert")
|
|
|
+ ),
|
|
|
+ primaryButton: .destructive(
|
|
|
+ Text("Add"),
|
|
|
+ action: {
|
|
|
+ state.addWithoutBolus()
|
|
|
+ isAddInsulinAlertPresented = false
|
|
|
+ }
|
|
|
+ ),
|
|
|
+ secondaryButton: .cancel()
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- .alert(isPresented: $isAddInsulinAlertPresented) {
|
|
|
- let amount = formatter
|
|
|
- .string(from: state.amount as NSNumber)! + NSLocalizedString(" U", comment: "Insulin unit")
|
|
|
- return Alert(
|
|
|
- title: Text("Are you sure?"),
|
|
|
- message: Text("Add \(amount) without bolusing"),
|
|
|
+ .alert(isPresented: $displayError) {
|
|
|
+ Alert(
|
|
|
+ title: Text("Warning!"),
|
|
|
+ message: Text("\n" + alertString() + NSLocalizedString(
|
|
|
+ "\n\nTap 'Add' to continue with selected amount.",
|
|
|
+ comment: "Alert text to confirm bolus amount to add"
|
|
|
+ )),
|
|
|
primaryButton: .destructive(
|
|
|
Text("Add"),
|
|
|
- action: { state.addWithoutBolus() }
|
|
|
+ action: {
|
|
|
+ state.amount = state.insulinRecommended
|
|
|
+ displayError = false
|
|
|
+ }
|
|
|
),
|
|
|
secondaryButton: .cancel()
|
|
|
)
|
|
|
@@ -141,15 +168,13 @@ extension Bolus {
|
|
|
HStack {
|
|
|
Text("Eventual Glucose").foregroundColor(.secondary)
|
|
|
let evg = state.units == .mmolL ? Decimal(state.evBG).asMmolL : Decimal(state.evBG)
|
|
|
- let fractionDigit = state.units == .mmolL ? 1 : 0
|
|
|
- Text(evg.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigit))))
|
|
|
+ Text(evg.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))))
|
|
|
Text(state.units.rawValue).foregroundColor(.secondary)
|
|
|
}
|
|
|
HStack {
|
|
|
Text("Target Glucose").foregroundColor(.secondary)
|
|
|
let target = state.units == .mmolL ? state.target.asMmolL : state.target
|
|
|
- let fractionDigit = state.units == .mmolL ? 1 : 0
|
|
|
- Text(target.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigit))))
|
|
|
+ Text(target.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))))
|
|
|
Text(state.units.rawValue).foregroundColor(.secondary)
|
|
|
}
|
|
|
HStack {
|
|
|
@@ -198,15 +223,14 @@ extension Bolus {
|
|
|
}
|
|
|
}
|
|
|
// Warning
|
|
|
- VStack {
|
|
|
- Divider()
|
|
|
- if state.error, state.insulinRecommended > 0 {
|
|
|
- Text("Warning!").font(.callout).foregroundColor(.orange).bold()
|
|
|
- Text(NSLocalizedString(state.errorString, comment: "")).font(.caption)
|
|
|
+ if state.error, state.insulinRecommended > 0 {
|
|
|
+ VStack(spacing: 5) {
|
|
|
Divider()
|
|
|
- }
|
|
|
- }.padding(.horizontal, 10)
|
|
|
- // Footer. Warning string .
|
|
|
+ Text("Warning!").font(.callout).bold().foregroundColor(.orange)
|
|
|
+ Text(alertString()).font(.footnote)
|
|
|
+ Divider()
|
|
|
+ }.padding(.horizontal, 10)
|
|
|
+ }
|
|
|
if !(state.error && state.insulinRecommended > 0) {
|
|
|
VStack {
|
|
|
Text(
|
|
|
@@ -224,12 +248,80 @@ extension Bolus {
|
|
|
.background(
|
|
|
RoundedRectangle(cornerRadius: 8, style: .continuous)
|
|
|
.fill(Color(colorScheme == .dark ? UIColor.systemGray4 : UIColor.systemGray4))
|
|
|
+ // .fill(Color(.systemGray).gradient) // A more prominent pop-up, but harder to read
|
|
|
)
|
|
|
}
|
|
|
+
|
|
|
+ // Localize the Oref0 error/warning strings
|
|
|
+ private func alertString() -> String {
|
|
|
+ switch state.errorString {
|
|
|
+ case 1:
|
|
|
+ return NSLocalizedString(
|
|
|
+ "Predicted Glucose, ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) + state.minGuardBG
|
|
|
+ .formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) + " " + state.units
|
|
|
+ .rawValue + ", " +
|
|
|
+ NSLocalizedString(
|
|
|
+ "is predicted below threshold ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) + state
|
|
|
+ .threshold.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) + "!"
|
|
|
+ case 2:
|
|
|
+ return NSLocalizedString(
|
|
|
+ "Predicted Glucose, ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) + state.minGuardBG
|
|
|
+ .formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) + " " + state.units
|
|
|
+ .rawValue + ", " +
|
|
|
+ NSLocalizedString(
|
|
|
+ "is below Threshold of ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) + state
|
|
|
+ .threshold.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits)))
|
|
|
+ case 3:
|
|
|
+ return NSLocalizedString(
|
|
|
+ "Eventual Glucose > Target Glucose, but glucose is climbing slower than expected. Expected: ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) +
|
|
|
+ state.expectedDelta
|
|
|
+ .formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) +
|
|
|
+ NSLocalizedString(". Climbing: ", comment: "Bolus pop-up / Alert string. Make translatons concise!") + state
|
|
|
+ .minDelta.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits)))
|
|
|
+ case 4:
|
|
|
+ return NSLocalizedString(
|
|
|
+ "Eventual Glucose > Target Glucose, but glucose is falling slower than expected. Expected: ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) +
|
|
|
+ state.expectedDelta
|
|
|
+ .formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) +
|
|
|
+ NSLocalizedString(". Falling: ", comment: "Bolus pop-up / Alert string. Make translations concise!") + state
|
|
|
+ .minDelta.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits)))
|
|
|
+ case 5:
|
|
|
+ return NSLocalizedString(
|
|
|
+ "Eventual Glucose > Target Glucose, but glucose is changing faster than expected. Expected: ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) +
|
|
|
+ state.expectedDelta
|
|
|
+ .formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) +
|
|
|
+ NSLocalizedString(". Changing: ", comment: "Bolus pop-up / Alert string. Make translations concise!") + state
|
|
|
+ .minDelta.formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits)))
|
|
|
+ case 6:
|
|
|
+ return NSLocalizedString(
|
|
|
+ "Minimum predicted Glucose is ",
|
|
|
+ comment: "Bolus pop-up / Alert string. Make translations concise!"
|
|
|
+ ) + state
|
|
|
+ .minPredBG
|
|
|
+ .formatted(.number.grouping(.never).rounded().precision(.fractionLength(fractionDigits))) + " " + state
|
|
|
+ .units
|
|
|
+ .rawValue
|
|
|
+ default:
|
|
|
+ return "Ignore Warning..."
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// fix iOS 15 bug
|
|
|
struct ActivityIndicator: UIViewRepresentable {
|
|
|
@Binding var isAnimating: Bool
|
|
|
let style: UIActivityIndicatorView.Style
|