Predictions.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import Charts
  2. import CoreData
  3. import SwiftUI
  4. import Swinject
  5. struct PredictionView: View {
  6. @Binding var predictions: Predictions?
  7. @Binding var units: GlucoseUnits
  8. @Binding var eventualBG: Int
  9. @Binding var target: Decimal
  10. @Binding var displayPredictions: Bool
  11. private enum Config {
  12. static let height: CGFloat = 160
  13. static let lineWidth: CGFloat = 2
  14. }
  15. var body: some View {
  16. VStack {
  17. if displayPredictions {
  18. chart()
  19. }
  20. HStack {
  21. let conversion = units == .mmolL ? 0.0555 : 1
  22. Text("Eventual Glucose")
  23. Spacer()
  24. Text(
  25. (Double(eventualBG) * conversion)
  26. .formatted(.number.grouping(.never).rounded().precision(.fractionLength(units == .mmolL ? 1 : 0)))
  27. )
  28. Text(units.rawValue).foregroundStyle(.secondary)
  29. Divider()
  30. }.font(.callout)
  31. }
  32. }
  33. func chart() -> some View {
  34. // Data Source
  35. let iob = predictions?.iob ?? [Int]()
  36. let cob = predictions?.cob ?? [Int]()
  37. let uam = predictions?.uam ?? [Int]()
  38. let zt = predictions?.zt ?? [Int]()
  39. let count = max(iob.count, cob.count, uam.count, zt.count)
  40. var now = Date.now
  41. var startIndex = 0
  42. let conversion = units == .mmolL ? 0.0555 : 1
  43. // Organize the data needed for prediction chart.
  44. var data = [ChartData]()
  45. repeat {
  46. now = now.addingTimeInterval(5.minutes.timeInterval)
  47. if startIndex < count {
  48. let addedData = ChartData(
  49. date: now,
  50. iob: startIndex < iob.count ? Double(iob[startIndex]) * conversion : 0,
  51. zt: startIndex < zt.count ? Double(zt[startIndex]) * conversion : 0,
  52. cob: startIndex < cob.count ? Double(cob[startIndex]) * conversion : 0,
  53. uam: startIndex < uam.count ? Double(uam[startIndex]) * conversion : 0,
  54. id: UUID()
  55. )
  56. data.append(addedData)
  57. }
  58. startIndex += 1
  59. } while startIndex < count
  60. // Chart
  61. return Chart(data) {
  62. // Remove 0 (empty) values
  63. if $0.iob != 0 {
  64. LineMark(
  65. x: .value("Time", $0.date),
  66. y: .value("IOB", $0.iob),
  67. series: .value("IOB", "A")
  68. )
  69. .foregroundStyle(Color(.insulin))
  70. .lineStyle(StrokeStyle(lineWidth: Config.lineWidth))
  71. }
  72. if $0.uam != 0 {
  73. LineMark(
  74. x: .value("Time", $0.date),
  75. y: .value("UAM", $0.uam),
  76. series: .value("UAM", "B")
  77. )
  78. .foregroundStyle(Color(.UAM))
  79. .lineStyle(StrokeStyle(lineWidth: Config.lineWidth))
  80. }
  81. if $0.cob != 0 {
  82. LineMark(
  83. x: .value("Time", $0.date),
  84. y: .value("COB", $0.cob),
  85. series: .value("COB", "C")
  86. )
  87. .foregroundStyle(Color(.loopYellow))
  88. .lineStyle(StrokeStyle(lineWidth: Config.lineWidth))
  89. }
  90. if $0.zt != 0 {
  91. LineMark(
  92. x: .value("Time", $0.date),
  93. y: .value("ZT", $0.zt),
  94. series: .value("ZT", "D")
  95. )
  96. .foregroundStyle(Color(.ZT))
  97. .lineStyle(StrokeStyle(lineWidth: Config.lineWidth))
  98. }
  99. }
  100. .frame(minHeight: Config.height)
  101. .chartForegroundStyleScale([
  102. "IOB": Color(.insulin),
  103. "UAM": .uam,
  104. "COB": Color(.loopYellow),
  105. "ZT": .zt
  106. ])
  107. .chartYAxisLabel(NSLocalizedString("Glucose, ", comment: "") + units.rawValue, alignment: .center)
  108. }
  109. }