CurrentGlucoseView.swift 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import SwiftUI
  2. struct CurrentGlucoseView: View {
  3. @Binding var recentGlucose: BloodGlucose?
  4. @Binding var timerDate: Date
  5. @Binding var delta: Int?
  6. @Binding var units: GlucoseUnits
  7. @Binding var alarm: GlucoseAlarm?
  8. @Binding var lowGlucose: Decimal
  9. @Binding var highGlucose: Decimal
  10. @Binding var cgmAvailable: Bool
  11. private var glucoseFormatter: NumberFormatter {
  12. let formatter = NumberFormatter()
  13. formatter.numberStyle = .decimal
  14. formatter.maximumFractionDigits = 0
  15. if units == .mmolL {
  16. formatter.minimumFractionDigits = 1
  17. formatter.maximumFractionDigits = 1
  18. }
  19. formatter.roundingMode = .halfUp
  20. return formatter
  21. }
  22. private var deltaFormatter: NumberFormatter {
  23. let formatter = NumberFormatter()
  24. formatter.numberStyle = .decimal
  25. formatter.maximumFractionDigits = 1
  26. formatter.positivePrefix = " +"
  27. formatter.negativePrefix = " -"
  28. return formatter
  29. }
  30. private var timaAgoFormatter: NumberFormatter {
  31. let formatter = NumberFormatter()
  32. formatter.numberStyle = .decimal
  33. formatter.maximumFractionDigits = 0
  34. formatter.negativePrefix = ""
  35. return formatter
  36. }
  37. private var dateFormatter: DateFormatter {
  38. let formatter = DateFormatter()
  39. formatter.timeStyle = .short
  40. return formatter
  41. }
  42. var body: some View {
  43. if cgmAvailable {
  44. VStack(alignment: .center) {
  45. HStack {
  46. Text(
  47. (recentGlucose?.glucose ?? 100) == 400 ? "HIGH" : recentGlucose?.glucose
  48. .map {
  49. glucoseFormatter
  50. .string(from: Double(units == .mmolL ? $0.asMmolL : Decimal($0)) as NSNumber)! }
  51. ?? "--"
  52. )
  53. .font(.title).fontWeight(.bold)
  54. .foregroundColor(alarm == nil ? colorOfGlucose : .loopRed)
  55. image
  56. }
  57. HStack {
  58. let minutesAgo = -1 * (recentGlucose?.dateString.timeIntervalSinceNow ?? 0) / 60
  59. let text = timaAgoFormatter.string(for: Double(minutesAgo)) ?? ""
  60. Text(
  61. minutesAgo <= 1 ? "< 1 " + NSLocalizedString("min", comment: "Short form for minutes") : (
  62. text + " " +
  63. NSLocalizedString("min", comment: "Short form for minutes") + " "
  64. )
  65. )
  66. .font(.caption2).foregroundColor(.secondary)
  67. Text(
  68. delta
  69. .map {
  70. deltaFormatter.string(from: Double(units == .mmolL ? $0.asMmolL : Decimal($0)) as NSNumber)!
  71. } ?? "--"
  72. )
  73. .font(.caption2).foregroundColor(.secondary)
  74. }.frame(alignment: .top)
  75. }
  76. } else {
  77. VStack(alignment: .center, spacing: 12) {
  78. HStack
  79. {
  80. // no cgm defined so display a generic CGM
  81. Image(systemName: "sensor.tag.radiowaves.forward.fill").font(.body).imageScale(.large)
  82. }
  83. HStack {
  84. Text("Add CGM").font(.caption).bold()
  85. }
  86. }.frame(alignment: .top)
  87. }
  88. }
  89. var image: Image {
  90. guard let direction = recentGlucose?.direction else {
  91. return Image(systemName: "arrow.left.and.right")
  92. }
  93. switch direction {
  94. case .doubleUp,
  95. .singleUp,
  96. .tripleUp:
  97. return Image(systemName: "arrow.up")
  98. case .fortyFiveUp:
  99. return Image(systemName: "arrow.up.right")
  100. case .flat:
  101. return Image(systemName: "arrow.forward")
  102. case .fortyFiveDown:
  103. return Image(systemName: "arrow.down.forward")
  104. case .doubleDown,
  105. .singleDown,
  106. .tripleDown:
  107. return Image(systemName: "arrow.down")
  108. case .none,
  109. .notComputable,
  110. .rateOutOfRange:
  111. return Image(systemName: "arrow.left.and.right")
  112. }
  113. }
  114. var colorOfGlucose: Color {
  115. let whichGlucose = recentGlucose?.glucose ?? 0
  116. guard lowGlucose < highGlucose else { return .primary }
  117. switch whichGlucose {
  118. case 0 ..< Int(lowGlucose):
  119. return .loopRed
  120. case Int(lowGlucose) ..< Int(highGlucose):
  121. return .loopGreen
  122. case Int(highGlucose)...:
  123. return .loopYellow
  124. default:
  125. return .loopYellow
  126. }
  127. }
  128. }