CarbRatioScheduleEditor.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. //
  2. // CarbRatioScheduleEditor.swift
  3. // LoopKitUI
  4. //
  5. // Created by Michael Pangburn on 4/20/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. import HealthKit
  10. import LoopKit
  11. fileprivate extension HKUnit {
  12. static let storedCarbRatioScheduleUnit = HKUnit.gram()
  13. static let realCarbRatioScheduleUnit = HKUnit.gramsPerUnit
  14. }
  15. public struct CarbRatioScheduleEditor: View {
  16. private var schedule: DailyQuantitySchedule<Double>?
  17. private var mode: SettingsPresentationMode
  18. private var save: (CarbRatioSchedule) -> Void
  19. @Environment(\.appName) private var appName
  20. public init(
  21. schedule: CarbRatioSchedule?,
  22. onSave save: @escaping (CarbRatioSchedule) -> Void,
  23. mode: SettingsPresentationMode = .settings
  24. ) {
  25. // CarbRatioSchedule stores only the gram unit.
  26. // For consistency across display & computation, convert to "real" g/U units.
  27. self.schedule = schedule.map { schedule in
  28. DailyQuantitySchedule(
  29. unit: .realCarbRatioScheduleUnit,
  30. dailyItems: schedule.items
  31. )!
  32. }
  33. self.mode = mode
  34. self.save = save
  35. }
  36. public init(
  37. viewModel: TherapySettingsViewModel,
  38. didSave: (() -> Void)? = nil
  39. ) {
  40. self.init(
  41. schedule: viewModel.therapySettings.carbRatioSchedule,
  42. onSave: { [weak viewModel] in
  43. viewModel?.saveCarbRatioSchedule(carbRatioSchedule: $0)
  44. didSave?()
  45. },
  46. mode: viewModel.mode
  47. )
  48. }
  49. public var body: some View {
  50. QuantityScheduleEditor(
  51. title: Text(TherapySetting.carbRatio.title),
  52. description: description,
  53. schedule: schedule,
  54. unit: .realCarbRatioScheduleUnit,
  55. guardrail: .carbRatio,
  56. selectableValueStride: HKQuantity(unit: .realCarbRatioScheduleUnit, doubleValue: 0.01),
  57. quantitySelectionMode: .fractional,
  58. defaultFirstScheduleItemValue: Guardrail.carbRatio.startingSuggestion ?? Guardrail.carbRatio.recommendedBounds.upperBound,
  59. confirmationAlertContent: confirmationAlertContent,
  60. guardrailWarning: CarbRatioGuardrailWarning.init(crossedThresholds:),
  61. onSave: {
  62. // Convert back to the expected gram-unit-only schedule.
  63. self.save(DailyQuantitySchedule(unit: .storedCarbRatioScheduleUnit, dailyItems: $0.items)!)
  64. },
  65. mode: mode,
  66. settingType: .carbRatio
  67. )
  68. }
  69. private var description: Text {
  70. Text(TherapySetting.carbRatio.descriptiveText(appName: appName))
  71. }
  72. private var confirmationAlertContent: AlertContent {
  73. AlertContent(
  74. title: Text(LocalizedString("Save Carb Ratios?", comment: "Alert title for confirming carb ratios outside the recommended range")),
  75. message: Text(TherapySetting.carbRatio.guardrailSaveWarningCaption)
  76. )
  77. }
  78. }
  79. private struct CarbRatioGuardrailWarning: View {
  80. var crossedThresholds: [SafetyClassification.Threshold]
  81. var body: some View {
  82. assert(!crossedThresholds.isEmpty)
  83. return GuardrailWarning(
  84. title: crossedThresholds.count == 1 ? singularWarningTitle(for: crossedThresholds.first!) : multipleWarningTitle,
  85. thresholds: crossedThresholds
  86. )
  87. }
  88. private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text {
  89. switch threshold {
  90. case .minimum, .belowRecommended:
  91. return Text(LocalizedString("Low Carb Ratio", comment: "Title text for the low carb ratio warning"))
  92. case .aboveRecommended, .maximum:
  93. return Text(LocalizedString("High Carb Ratio", comment: "Title text for the high carb ratio warning"))
  94. }
  95. }
  96. private var multipleWarningTitle: Text {
  97. Text(LocalizedString("Carb Ratios", comment: "Title text for multi-value carb ratio warning"))
  98. }
  99. }