GlucoseTherapySettingInformationView.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. //
  2. // GlucoseTherapySettingInformationView.swift
  3. // LoopKitUI
  4. //
  5. // Created by Rick Pasetto on 11/16/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import HealthKit
  9. import SwiftUI
  10. import LoopKit
  11. public struct GlucoseTherapySettingInformationView: View {
  12. var text: AnyView?
  13. let onExit: (() -> Void)?
  14. let mode: SettingsPresentationMode
  15. let therapySetting: TherapySetting
  16. let preferredUnit: HKUnit
  17. let appName: String
  18. @Environment(\.presentationMode) var presentationMode
  19. public init(
  20. therapySetting: TherapySetting,
  21. preferredUnit: HKUnit? = nil,
  22. onExit: (() -> Void)?,
  23. mode: SettingsPresentationMode = .acceptanceFlow,
  24. appName: String,
  25. text: AnyView? = nil
  26. ){
  27. self.therapySetting = therapySetting
  28. self.preferredUnit = preferredUnit ?? .milligramsPerDeciliter
  29. self.onExit = onExit
  30. self.mode = mode
  31. self.appName = appName
  32. self.text = text
  33. }
  34. public var body: some View {
  35. InformationView(
  36. title: Text(self.therapySetting.title),
  37. informationalContent: {
  38. illustration
  39. bodyText
  40. },
  41. onExit: onExit ?? { self.presentationMode.wrappedValue.dismiss() },
  42. mode: mode
  43. )
  44. }
  45. private var illustration: some View {
  46. Image(frameworkImage: illustrationImageName)
  47. .renderingMode(.original)
  48. .resizable()
  49. .aspectRatio(contentMode: ContentMode.fit)
  50. }
  51. private var bodyText: some View {
  52. VStack(alignment: .leading, spacing: 25) {
  53. text ?? AnyView(Text(therapySetting.descriptiveText(appName: appName)))
  54. Text(therapySetting.guardrailInformationText)
  55. }
  56. .accentColor(.secondary)
  57. .foregroundColor(.accentColor)
  58. .fixedSize(horizontal: false, vertical: true)
  59. }
  60. private var illustrationImageName: String {
  61. return "\(therapySetting) \(preferredUnit.description.replacingOccurrences(of: "/", with: ""))"
  62. }
  63. }
  64. fileprivate extension TherapySetting {
  65. // TODO: pass in preferredUnit instead of having both units.
  66. var guardrailInformationText: String {
  67. switch self {
  68. case .glucoseTargetRange:
  69. return lowHighText(for: Guardrail.correctionRange)
  70. case .preMealCorrectionRangeOverride:
  71. return lowHighText(lowerBoundString: LocalizedString("your Glucose Safety Limit", comment: "Lower bound pre-meal information text"),
  72. upperBoundString: Guardrail.premealCorrectionRangeMaximum.bothUnitsString)
  73. case .workoutCorrectionRangeOverride:
  74. return lowHighText(
  75. lowerBoundString: String(format: LocalizedString("%1$@ or your Glucose Safety Limit, whichever is higher", comment: "Lower bound workout information text format (1: app name)"), Guardrail.unconstrainedWorkoutCorrectionRange.absoluteBounds.lowerBound.bothUnitsString),
  76. upperBoundString: Guardrail.unconstrainedWorkoutCorrectionRange.absoluteBounds.upperBound.bothUnitsString)
  77. case .suspendThreshold:
  78. return lowHighText(for: Guardrail.suspendThreshold)
  79. case .basalRate, .deliveryLimits, .insulinModel, .carbRatio, .insulinSensitivity, .none:
  80. fatalError("Unexpected")
  81. }
  82. }
  83. func lowHighText(for guardrail: Guardrail<HKQuantity>) -> String {
  84. return lowHighText(lowerBoundString: guardrail.absoluteBounds.lowerBound.bothUnitsString,
  85. upperBoundString: guardrail.absoluteBounds.upperBound.bothUnitsString)
  86. }
  87. func lowHighText(lowerBoundString: String, upperBoundString: String) -> String {
  88. return String(format: LocalizedString("It can be set as low as %1$@. It can be set as high as %2$@.",
  89. comment: "Guardrail info text format"), lowerBoundString, upperBoundString)
  90. }
  91. }