Predictions.swift 3.9 KB

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