GlucoseChartView.swift 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import Charts
  2. import Foundation
  3. import SwiftUI
  4. // MARK: - Current Glucose View
  5. struct GlucoseChartView: View {
  6. let glucoseValues: [(date: Date, glucose: Double)]
  7. @State private var timeWindow: TimeWindow = .threeHours
  8. enum TimeWindow: Int {
  9. case threeHours = 3
  10. case sixHours = 6
  11. case twelveHours = 12
  12. case twentyFourHours = 24
  13. var next: TimeWindow {
  14. switch self {
  15. case .threeHours: return .sixHours
  16. case .sixHours: return .twelveHours
  17. case .twelveHours: return .twentyFourHours
  18. case .twentyFourHours: return .threeHours
  19. }
  20. }
  21. }
  22. // TODO: should we only change the x axis here like we do in the main chart instead of filtering the values?
  23. private var filteredValues: [(date: Date, glucose: Double)] {
  24. let cutoffDate = Date().addingTimeInterval(-Double(timeWindow.rawValue) * 3600)
  25. return glucoseValues.filter { $0.date > cutoffDate }
  26. }
  27. // TODO: replace hard coded values with actual settings and add dynamic color
  28. private func glucoseColor(_ value: Double) -> Color {
  29. if value > 180 {
  30. return .orange
  31. } else if value < 70 {
  32. return .red
  33. } else {
  34. return .green
  35. }
  36. }
  37. var body: some View {
  38. Chart {
  39. ForEach(filteredValues, id: \.date) { reading in
  40. PointMark(
  41. x: .value("Time", reading.date),
  42. y: .value("Glucose", reading.glucose)
  43. )
  44. .foregroundStyle(glucoseColor(reading.glucose))
  45. .symbolSize(15)
  46. }
  47. }
  48. .chartXAxis {
  49. AxisMarks(values: .automatic(desiredCount: 4)) { _ in
  50. AxisValueLabel(format: .dateTime.hour())
  51. }
  52. }
  53. .chartYAxis {
  54. AxisMarks(position: .leading)
  55. }
  56. .padding()
  57. .onTapGesture {
  58. withAnimation {
  59. timeWindow = timeWindow.next
  60. }
  61. }
  62. .overlay(alignment: .topTrailing) {
  63. Text("\(timeWindow.rawValue)h")
  64. .font(.caption2)
  65. .foregroundStyle(.secondary)
  66. .padding(.trailing)
  67. }
  68. }
  69. }