| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- import Charts
- import Foundation
- import SwiftUI
- struct GlucoseTargetsView: ChartContent {
- let startMarker: Date
- let endMarker: Date
- let units: GlucoseUnits
- let bgTargets: BGTargets
- var body: some ChartContent {
- drawGlucoseTargets()
- }
- /**
- Draws glucose target ranges on the chart
- - Returns: A ChartContent containing line marks representing target glucose ranges
- The function:
- - Creates target profiles for two consecutive days
- - Converts values between mg/dL and mmol/L based on user settings
- - Draws green lines to visualize the target ranges
- */
- private func drawGlucoseTargets() -> some ChartContent {
- // Array to store target profiles for visualization
- var targetProfiles: [TargetProfile] = []
- let targets = bgTargets.targets
- // Generate profiles for today and tomorrow, because otherwise the targets would be cut off at midnight
- // TODO: maybe theres a better solution than introducing a second for loop?
- let days = [0, 1]
- for dayOffset in days {
- // Calculate base date for current day offset
- // it should be the start of the day of the startMarker
- let baseDate = Calendar.current.startOfDay(for: startMarker)
- .addingTimeInterval(TimeInterval(dayOffset * 24 * 60 * 60))
- for (index, target) in targets.enumerated() {
- // Calculate start time by adding target offset
- let startTime = baseDate.addingTimeInterval(TimeInterval(target.offset * 60))
- // Calculate end time - either next target or end of day
- let endTime: Date = {
- if index + 1 < targets.count {
- return baseDate.addingTimeInterval(TimeInterval(targets[index + 1].offset * 60))
- } else {
- return baseDate.addingTimeInterval(24 * 60 * 60)
- }
- }()
- // append target profile to array
- targetProfiles.append(
- TargetProfile(
- value: units == .mgdL ? target.low : target.low.asMmolL,
- startTime: startTime.timeIntervalSinceReferenceDate,
- endTime: endTime.timeIntervalSinceReferenceDate
- )
- )
- }
- }
- // Draw target lines for each profile
- return ForEach(targetProfiles, id: \.self) { profile in
- LineMark(
- x: .value("Time", Date(timeIntervalSinceReferenceDate: profile.startTime)),
- y: .value("Target", profile.value)
- )
- .lineStyle(.init(lineWidth: 0.5))
- .foregroundStyle(Color.green.opacity(0.8))
- LineMark(
- x: .value("Time", Date(timeIntervalSinceReferenceDate: profile.endTime)),
- y: .value("Target", profile.value)
- )
- .lineStyle(.init(lineWidth: 0.5))
- .foregroundStyle(Color.green.opacity(0.8))
- }
- }
- }
- struct TargetProfile: Hashable {
- let value: Decimal
- let startTime: TimeInterval
- let endTime: TimeInterval
- }
- private extension Date {
- var startOfDay: Date {
- Calendar.current.startOfDay(for: self)
- }
- }
|