SelectionPopoverView.swift 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import Charts
  2. import Foundation
  3. import SwiftUI
  4. struct SelectionPopoverView: ChartContent {
  5. let selectedGlucose: GlucoseStored
  6. let selectedIOBValue: OrefDetermination?
  7. let selectedCOBValue: OrefDetermination?
  8. let units: GlucoseUnits
  9. let highGlucose: Decimal
  10. let lowGlucose: Decimal
  11. let currentGlucoseTarget: Decimal
  12. let glucoseColorScheme: GlucoseColorScheme
  13. let isSmoothingEnabled: Bool
  14. private var glucoseToDisplay: Decimal {
  15. units == .mgdL ? Decimal(selectedGlucose.glucose) : Decimal(selectedGlucose.glucose).asMmolL
  16. }
  17. private var pointMarkColor: Color {
  18. let hardCodedLow = Decimal(55)
  19. let hardCodedHigh = Decimal(220)
  20. let isDynamicColorScheme = glucoseColorScheme == .dynamicColor
  21. return Trio.getDynamicGlucoseColor(
  22. glucoseValue: Decimal(selectedGlucose.glucose),
  23. highGlucoseColorValue: isDynamicColorScheme ? hardCodedHigh : highGlucose,
  24. lowGlucoseColorValue: isDynamicColorScheme ? hardCodedLow : lowGlucose,
  25. targetGlucose: currentGlucoseTarget,
  26. glucoseColorScheme: glucoseColorScheme
  27. )
  28. }
  29. var body: some ChartContent {
  30. RuleMark(x: .value("Selection", selectedGlucose.date ?? Date.now, unit: .minute))
  31. .foregroundStyle(Color.tabBar)
  32. .offset(yStart: 70)
  33. .lineStyle(.init(lineWidth: 2))
  34. .annotation(
  35. position: .top,
  36. alignment: .center,
  37. overflowResolution: .init(x: .fit(to: .chart), y: .disabled)
  38. ) {
  39. selectionPopover
  40. }
  41. PointMark(
  42. x: .value("Time", selectedGlucose.date ?? Date.now, unit: .minute),
  43. y: .value("Value", glucoseToDisplay)
  44. )
  45. .zIndex(-1)
  46. .symbolSize(CGSize(width: 15, height: 15))
  47. .foregroundStyle(pointMarkColor)
  48. PointMark(
  49. x: .value("Time", selectedGlucose.date ?? Date.now, unit: .minute),
  50. y: .value("Value", glucoseToDisplay)
  51. )
  52. .zIndex(-1)
  53. .symbolSize(CGSize(width: 6, height: 6))
  54. .foregroundStyle(Color.primary)
  55. }
  56. @ViewBuilder var selectionPopover: some View {
  57. VStack(alignment: .leading) {
  58. HStack {
  59. Image(systemName: "clock")
  60. Text(selectedGlucose.date?.formatted(.dateTime.hour().minute(.twoDigits)) ?? "")
  61. .font(.body).bold()
  62. }
  63. .font(.body).padding(.bottom, 2)
  64. HStack {
  65. Text("CGM: ") + Text(glucoseToDisplay.description).bold() + Text(" \(units.rawValue)")
  66. }
  67. .foregroundStyle(pointMarkColor)
  68. .font(.body)
  69. if isSmoothingEnabled, let smoothedGlucose = selectedGlucose.smoothedGlucose {
  70. var smoothedGlucoseToDisplay: Decimal {
  71. units == .mgdL ? smoothedGlucose.decimalValue : smoothedGlucose.decimalValue.asMmolL
  72. }
  73. HStack {
  74. Text("Smoothed: ") + Text(smoothedGlucoseToDisplay.description) + Text(" \(units.rawValue)")
  75. }
  76. }
  77. if let selectedIOBValue, let iob = selectedIOBValue.iob {
  78. HStack {
  79. Image(systemName: "syringe.fill").frame(width: 15)
  80. Text(Formatter.bolusFormatter.string(from: iob) ?? "")
  81. .bold()
  82. + Text(String(localized: " U", comment: "Insulin unit"))
  83. }
  84. .foregroundStyle(Color.insulin).font(.body)
  85. }
  86. if let selectedCOBValue {
  87. HStack {
  88. Image(systemName: "fork.knife").frame(width: 15)
  89. Text(Formatter.integerFormatter.string(from: selectedCOBValue.cob as NSNumber) ?? "")
  90. .bold()
  91. + Text(String(localized: " g", comment: "gram of carbs"))
  92. }
  93. .foregroundStyle(Color.orange).font(.body)
  94. }
  95. }
  96. .padding(.horizontal)
  97. .padding(.vertical, 2)
  98. .background {
  99. RoundedRectangle(cornerRadius: 4)
  100. .fill(Color.chart.opacity(0.85))
  101. .shadow(color: Color.secondary, radius: 2)
  102. .overlay(
  103. RoundedRectangle(cornerRadius: 4)
  104. .stroke(Color.secondary, lineWidth: 2)
  105. )
  106. }
  107. }
  108. }