SelectionPopoverView.swift 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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: isSmoothingEnabled ? 90 : 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. Image(systemName: "sparkles")
  75. Text(smoothedGlucoseToDisplay.description) + Text(" \(units.rawValue)")
  76. }.font(.body)
  77. }
  78. if let selectedIOBValue, let iob = selectedIOBValue.iob {
  79. HStack {
  80. Image(systemName: "syringe.fill").frame(width: 15)
  81. Text(Formatter.decimalFormatterWithTwoFractionDigits.string(from: iob) ?? "")
  82. .bold()
  83. + Text(String(localized: " U", comment: "Insulin unit"))
  84. }
  85. .foregroundStyle(Color.insulin).font(.body)
  86. }
  87. if let selectedCOBValue {
  88. HStack {
  89. Image(systemName: "fork.knife").frame(width: 15)
  90. Text(Formatter.integerFormatter.string(from: selectedCOBValue.cob as NSNumber) ?? "")
  91. .bold()
  92. + Text(String(localized: " g", comment: "gram of carbs"))
  93. }
  94. .foregroundStyle(Color.orange).font(.body)
  95. }
  96. }
  97. .padding(.horizontal)
  98. .padding(.vertical, 2)
  99. .background {
  100. RoundedRectangle(cornerRadius: 4)
  101. .fill(Color.chart.opacity(0.85))
  102. .shadow(color: Color.secondary, radius: 2)
  103. .overlay(
  104. RoundedRectangle(cornerRadius: 4)
  105. .stroke(Color.secondary, lineWidth: 2)
  106. )
  107. }
  108. }
  109. }