DeviceAlertSeverity.swift 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import Foundation
  2. import LoopKit
  3. /// Coarse-grained tier the user configures for device alarms. Wraps
  4. /// `Alert.InterruptionLevel` plus its visible behavior:
  5. /// - `.critical` overrides Silence & Focus Mode (uses the critical-audio
  6. /// fallback for builds without the Critical Alerts entitlement)
  7. /// - `.timeSensitive` pierces normal banner suppression but obeys DND/silent
  8. /// - `.normal` fires only when the device isn't silenced — informational
  9. enum DeviceAlertSeverity: String, Codable, CaseIterable, Identifiable {
  10. case critical
  11. case timeSensitive
  12. case normal
  13. var id: String { rawValue }
  14. init?(level: Alert.InterruptionLevel) {
  15. switch level {
  16. case .critical: self = .critical
  17. case .timeSensitive: self = .timeSensitive
  18. case .active: self = .normal
  19. }
  20. }
  21. var displayName: String {
  22. switch self {
  23. case .critical: return String(localized: "Critical")
  24. case .timeSensitive: return String(localized: "Time-Sensitive")
  25. case .normal: return String(localized: "Normal")
  26. }
  27. }
  28. var blurb: String {
  29. switch self {
  30. case .critical:
  31. return String(localized: "Overrides Silence & Focus Mode. For situations requiring immediate attention.")
  32. case .timeSensitive:
  33. return String(localized: "Pierces banner suppression but obeys Silence & Focus Mode by default.")
  34. case .normal:
  35. return String(localized: "Default notification banner. Suppressed by Silence & Focus Mode by default.")
  36. }
  37. }
  38. var hintText: String {
  39. switch self {
  40. case .critical:
  41. return String(
  42. localized: "For situations that require prompt attention. These break through Silent Mode, Do Not Disturb, and any Focus you have enabled. Examples: a pump fault, an occlusion, or Trio not looping for too long. Heads up: if your build of Trio has Apple's Critical Alerts entitlement, iOS plays its own critical alert sound and the sound you picked for this alert category is ignored."
  43. )
  44. case .timeSensitive:
  45. return String(
  46. localized: "For things you should know about soon, but not 'act right now'. These can break through banner suppression on the lock screen, but they still obey Silent Mode and Focus by default. Examples: reservoir running low, pod or patch expiring soon, or glucose data going stale."
  47. )
  48. case .normal:
  49. return String(
  50. localized: "For everyday heads-up notifications. These behave like a standard banner — they stay quiet when your phone is silenced or a Focus is on. Examples: an algorithm error, a sensor expiration reminder, or a time-zone change being detected."
  51. )
  52. }
  53. }
  54. var defaultSoundFilename: String {
  55. switch self {
  56. case .critical: return "alarm.caf"
  57. case .timeSensitive: return "chime.caf"
  58. case .normal: return "bloop.caf"
  59. }
  60. }
  61. /// Default for the per-tier override toggle when seeded. Tier names are
  62. /// labels now — the actual `Alert.InterruptionLevel` is derived from the
  63. /// override flag at fire time (true → `.critical`, false → `.timeSensitive`).
  64. var defaultOverridesSilenceAndDND: Bool {
  65. switch self {
  66. case .critical: return true
  67. case .normal,
  68. .timeSensitive: return false
  69. }
  70. }
  71. }