GlucoseAlertConfiguration.swift 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import Foundation
  2. struct GlucoseAlertConfiguration: Codable, Equatable {
  3. var dayStart: TimeOfDay
  4. var nightStart: TimeOfDay
  5. /// Force Trio alarms on even when the CGM advertises its own.
  6. var forceTrioAlertsWhenCGMProvidesOwn: Bool
  7. init(
  8. dayStart: TimeOfDay = TimeOfDay(hour: 6, minute: 0),
  9. nightStart: TimeOfDay = TimeOfDay(hour: 22, minute: 0),
  10. forceTrioAlertsWhenCGMProvidesOwn: Bool = false
  11. ) {
  12. self.dayStart = dayStart
  13. self.nightStart = nightStart
  14. self.forceTrioAlertsWhenCGMProvidesOwn = forceTrioAlertsWhenCGMProvidesOwn
  15. }
  16. private enum CodingKeys: String, CodingKey {
  17. case dayStart
  18. case nightStart
  19. case forceTrioAlertsWhenCGMProvidesOwn
  20. }
  21. init(from decoder: Decoder) throws {
  22. let container = try decoder.container(keyedBy: CodingKeys.self)
  23. dayStart = try container.decode(TimeOfDay.self, forKey: .dayStart)
  24. nightStart = try container.decode(TimeOfDay.self, forKey: .nightStart)
  25. forceTrioAlertsWhenCGMProvidesOwn = try container.decodeIfPresent(
  26. Bool.self,
  27. forKey: .forceTrioAlertsWhenCGMProvidesOwn
  28. ) ?? false
  29. }
  30. /// Resolve whether `date` falls into the user's "night" window. Mirrors
  31. /// LoopFollow's logic: handles both same-day (06→22) and wrap-around
  32. /// (22→06) ranges. When `nightStart >= dayStart`, night is "later than
  33. /// nightStart OR earlier than dayStart"; otherwise night is the slice
  34. /// between nightStart and dayStart.
  35. func isNight(at date: Date, calendar: Calendar = .current) -> Bool {
  36. let startOfDay = calendar.startOfDay(for: date)
  37. guard
  38. let dayStartDate = calendar.date(
  39. bySettingHour: dayStart.hour,
  40. minute: dayStart.minute,
  41. second: 0,
  42. of: startOfDay
  43. ),
  44. let nightStartDate = calendar.date(
  45. bySettingHour: nightStart.hour,
  46. minute: nightStart.minute,
  47. second: 0,
  48. of: startOfDay
  49. )
  50. else { return false }
  51. if nightStartDate >= dayStartDate {
  52. return date >= nightStartDate || date < dayStartDate
  53. } else {
  54. return date >= nightStartDate && date < dayStartDate
  55. }
  56. }
  57. }