TempTargets.swift 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import Charts
  2. import Foundation
  3. import SwiftUI
  4. struct ChartTempTarget: Hashable {
  5. let amount: Decimal
  6. let start: Date
  7. let end: Date
  8. }
  9. extension MainChartView {
  10. func drawTempTargets() -> some ChartContent {
  11. ForEach(chartTempTargets, id: \.self) { target in
  12. let targetLimited = min(max(target.amount, 0), upperLimit)
  13. RuleMark(
  14. xStart: .value("Start", target.start),
  15. xEnd: .value("End", target.end),
  16. y: .value("Value", targetLimited)
  17. )
  18. .foregroundStyle(Color.purple.opacity(0.75)).lineStyle(.init(lineWidth: 8))
  19. }
  20. }
  21. // Calculations for temp target bar mark
  22. func calculateTempTargets() async {
  23. // Perform calculations off the main thread
  24. let calculatedTTs = await Task.detached { () -> [ChartTempTarget] in
  25. var groupedPackages: [[TempTarget]] = []
  26. var currentPackage: [TempTarget] = []
  27. var calculatedTTs: [ChartTempTarget] = []
  28. for target in await tempTargets {
  29. if target.duration > 0 {
  30. if !currentPackage.isEmpty {
  31. groupedPackages.append(currentPackage)
  32. currentPackage = []
  33. }
  34. currentPackage.append(target)
  35. } else if let lastNonZeroTempTarget = currentPackage.last(where: { $0.duration > 0 }) {
  36. // Ensure this cancel target is within the valid time range
  37. if target.createdAt >= lastNonZeroTempTarget.createdAt,
  38. target.createdAt <= lastNonZeroTempTarget.createdAt
  39. .addingTimeInterval(TimeInterval(lastNonZeroTempTarget.duration * 60))
  40. {
  41. currentPackage.append(target)
  42. }
  43. }
  44. }
  45. // Append the last group, if any
  46. if !currentPackage.isEmpty {
  47. groupedPackages.append(currentPackage)
  48. }
  49. for package in groupedPackages {
  50. guard let firstNonZeroTarget = package.first(where: { $0.duration > 0 }) else { continue }
  51. var end = firstNonZeroTarget.createdAt.addingTimeInterval(TimeInterval(firstNonZeroTarget.duration * 60))
  52. let earliestCancelTarget = package.filter({ $0.duration == 0 }).min(by: { $0.createdAt < $1.createdAt })
  53. if let earliestCancelTarget = earliestCancelTarget {
  54. end = min(earliestCancelTarget.createdAt, end)
  55. }
  56. if let targetTop = firstNonZeroTarget.targetTop {
  57. let adjustedTarget = await units == .mgdL ? targetTop : targetTop.asMmolL
  58. calculatedTTs
  59. .append(ChartTempTarget(amount: adjustedTarget, start: firstNonZeroTarget.createdAt, end: end))
  60. }
  61. }
  62. return calculatedTTs
  63. }.value
  64. // Update chartTempTargets on the main thread
  65. await MainActor.run {
  66. self.chartTempTargets = calculatedTTs
  67. }
  68. }
  69. }