SelectionPopoverView.swift 4.0 KB

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