GlucoseTargetsView.swift 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import Charts
  2. import Foundation
  3. import SwiftUI
  4. struct GlucoseTargetsView: ChartContent {
  5. let startMarker: Date
  6. let endMarker: Date
  7. let units: GlucoseUnits
  8. let bgTargets: BGTargets
  9. var body: some ChartContent {
  10. drawGlucoseTargets()
  11. }
  12. private func drawGlucoseTargets() -> some ChartContent {
  13. var targetProfiles: [TargetProfile] = []
  14. let targets = bgTargets.targets
  15. for (index, target) in targets.enumerated() {
  16. let startTime = max(TimeInterval(target.offset * 60), startMarker.timeIntervalSinceReferenceDate)
  17. let endTime: TimeInterval = {
  18. if index + 1 < targets.count {
  19. return min(TimeInterval(targets[index + 1].offset * 60), endMarker.timeIntervalSinceReferenceDate)
  20. } else {
  21. return endMarker.timeIntervalSinceReferenceDate
  22. }
  23. }()
  24. if startTime < endTime { // Ensure valid range
  25. targetProfiles.append(
  26. TargetProfile(
  27. value: units == .mgdL ? target.low : target.low.asMmolL,
  28. startTime: startTime,
  29. endTime: endTime
  30. )
  31. )
  32. }
  33. }
  34. // Draw Target Lines
  35. return ForEach(targetProfiles, id: \.self) { profile in
  36. // Horizontal Line for Target Range
  37. LineMark(
  38. x: .value("Time", Date(timeIntervalSince1970: profile.startTime)),
  39. y: .value("Value", profile.value)
  40. ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
  41. LineMark(
  42. x: .value("Time", Date(timeIntervalSince1970: profile.endTime)),
  43. y: .value("Value", profile.value)
  44. ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
  45. // Vertical Transition Line to the Next Profile (if exists)
  46. if let nextProfile = targetProfiles.first(where: { $0.startTime == profile.endTime }) {
  47. LineMark(
  48. x: .value("Time", Date(timeIntervalSince1970: profile.endTime)),
  49. y: .value("Value", profile.value)
  50. ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
  51. LineMark(
  52. x: .value("Time", Date(timeIntervalSince1970: profile.endTime)),
  53. y: .value("Value", nextProfile.value)
  54. ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
  55. }
  56. }
  57. }
  58. }
  59. struct TargetProfile: Hashable {
  60. let value: Decimal
  61. let startTime: TimeInterval
  62. let endTime: TimeInterval
  63. }
  64. private extension Date {
  65. var startOfDay: Date {
  66. Calendar.current.startOfDay(for: self)
  67. }
  68. }