IobChart.swift 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import Charts
  2. import Foundation
  3. import SwiftUI
  4. extension MainChartView {
  5. var iobChart: some View {
  6. VStack {
  7. Chart {
  8. drawIOB()
  9. if #available(iOS 17, *) {
  10. if let selectedIOBValue {
  11. PointMark(
  12. x: .value("Time", selectedIOBValue.deliverAt ?? now, unit: .minute),
  13. y: .value("Value", Int(truncating: selectedIOBValue.iob ?? 0))
  14. )
  15. .symbolSize(CGSize(width: 15, height: 15))
  16. .foregroundStyle(Color.darkerBlue.opacity(0.8))
  17. PointMark(
  18. x: .value("Time", selectedIOBValue.deliverAt ?? now, unit: .minute),
  19. y: .value("Value", Int(truncating: selectedIOBValue.iob ?? 0))
  20. )
  21. .symbolSize(CGSize(width: 6, height: 6))
  22. .foregroundStyle(Color.primary)
  23. }
  24. }
  25. }
  26. .offset(y: deviceOffset)
  27. .frame(minHeight: geo.size.height * 0.12)
  28. .frame(width: fullWidth(viewWidth: screenSize.width))
  29. .chartXScale(domain: startMarker ... endMarker)
  30. .backport.chartXSelection(value: $selection)
  31. .chartXAxis { basalChartXAxis }
  32. .chartXAxis(.hidden)
  33. .chartYAxis { cobChartYAxis }
  34. .chartYScale(domain: state.minValueIobChart ... state.maxValueIobChart)
  35. .chartYAxis(.hidden)
  36. }
  37. }
  38. var deviceOffset: CGFloat {
  39. switch UIDevice.current.userInterfaceIdiom {
  40. case .phone:
  41. // Use the native screen height in pixels to calculate the offset for different devices
  42. // The offset is based on the empirically determined offset for the iPhone 16 Pro simulator (2622 pixels in height, offset = 11)
  43. // The offset for other devices is calculated proportionally to the iPhone 16 Pro:
  44. // Offset for another device = (Height of the other device / Height of iPhone 16 Pro) * 11
  45. let screenHeight = UIScreen.main.nativeBounds.height
  46. if screenHeight == 2622 {
  47. return 11 // iPhone 16 Pro
  48. } else if screenHeight == 2868 {
  49. return 12.1 // iPhone 16 Pro Max
  50. } else if screenHeight == 2556 {
  51. return 10.7 // iPhone 15 Pro
  52. } else if screenHeight == 2796 {
  53. return 11.7 // iPhone 15 Pro Max / 15 Plus / 16 Plus
  54. } else if screenHeight == 2340 {
  55. return 9.8 // iPhone 12 Mini
  56. } else {
  57. return 11 // Default for other phones
  58. }
  59. default:
  60. return 11
  61. }
  62. }
  63. func drawIOB() -> some ChartContent {
  64. ForEach(state.enactedAndNonEnactedDeterminations) { iob in
  65. let rawAmount = iob.iob?.doubleValue ?? 0
  66. let amount: Double = rawAmount > 0 ? rawAmount : rawAmount * 2 // weigh negative iob with factor 2
  67. let date: Date = iob.deliverAt ?? Date()
  68. LineMark(x: .value("Time", date), y: .value("Amount", amount))
  69. .foregroundStyle(Color.darkerBlue)
  70. AreaMark(x: .value("Time", date), y: .value("Amount", amount))
  71. .foregroundStyle(
  72. LinearGradient(
  73. gradient: Gradient(
  74. colors: [
  75. Color.darkerBlue.opacity(0.8),
  76. Color.darkerBlue.opacity(0.01)
  77. ]
  78. ),
  79. startPoint: .top,
  80. endPoint: .bottom
  81. )
  82. )
  83. }
  84. }
  85. }