PushMessage.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import Foundation
  2. struct PushMessage: Codable, Sendable {
  3. var user: String
  4. var commandType: TrioRemoteControl.CommandType
  5. var bolusAmount: Decimal?
  6. var target: Int?
  7. var duration: Int?
  8. var carbs: Int?
  9. var protein: Int?
  10. var fat: Int?
  11. var sharedSecret: String
  12. var timestamp: TimeInterval
  13. var overrideName: String?
  14. var scheduledTime: TimeInterval?
  15. var returnNotification: ReturnNotificationInfo?
  16. struct ReturnNotificationInfo: Codable, Sendable {
  17. let productionEnvironment: Bool
  18. let deviceToken: String
  19. let bundleId: String
  20. let teamId: String
  21. let keyId: String
  22. let apnsKey: String
  23. enum CodingKeys: String, CodingKey {
  24. case productionEnvironment = "production_environment"
  25. case deviceToken = "device_token"
  26. case bundleId = "bundle_id"
  27. case teamId = "team_id"
  28. case keyId = "key_id"
  29. case apnsKey = "apns_key"
  30. }
  31. }
  32. enum CodingKeys: String, CodingKey {
  33. case aps
  34. case user
  35. case commandType = "command_type"
  36. case bolusAmount = "bolus_amount"
  37. case target
  38. case duration
  39. case carbs
  40. case protein
  41. case fat
  42. case sharedSecret = "shared_secret"
  43. case timestamp
  44. case overrideName
  45. case scheduledTime = "scheduled_time"
  46. case returnNotification = "return_notification"
  47. }
  48. func encode(to encoder: Encoder) throws {
  49. var container = encoder.container(keyedBy: CodingKeys.self)
  50. try container.encode(user, forKey: .user)
  51. try container.encode(commandType, forKey: .commandType)
  52. try container.encodeIfPresent(bolusAmount, forKey: .bolusAmount)
  53. try container.encodeIfPresent(target, forKey: .target)
  54. try container.encodeIfPresent(duration, forKey: .duration)
  55. try container.encodeIfPresent(carbs, forKey: .carbs)
  56. try container.encodeIfPresent(protein, forKey: .protein)
  57. try container.encodeIfPresent(fat, forKey: .fat)
  58. try container.encode(sharedSecret, forKey: .sharedSecret)
  59. try container.encode(timestamp, forKey: .timestamp)
  60. try container.encodeIfPresent(overrideName, forKey: .overrideName)
  61. try container.encodeIfPresent(scheduledTime, forKey: .scheduledTime)
  62. try container.encodeIfPresent(returnNotification, forKey: .returnNotification)
  63. }
  64. init(from decoder: Decoder) throws {
  65. let container = try decoder.container(keyedBy: CodingKeys.self)
  66. user = try container.decode(String.self, forKey: .user)
  67. commandType = try container.decode(TrioRemoteControl.CommandType.self, forKey: .commandType)
  68. bolusAmount = try container.decodeIfPresent(Decimal.self, forKey: .bolusAmount)
  69. target = try container.decodeIfPresent(Int.self, forKey: .target)
  70. duration = try container.decodeIfPresent(Int.self, forKey: .duration)
  71. carbs = try container.decodeIfPresent(Int.self, forKey: .carbs)
  72. protein = try container.decodeIfPresent(Int.self, forKey: .protein)
  73. fat = try container.decodeIfPresent(Int.self, forKey: .fat)
  74. sharedSecret = try container.decode(String.self, forKey: .sharedSecret)
  75. timestamp = try container.decode(TimeInterval.self, forKey: .timestamp)
  76. overrideName = try container.decodeIfPresent(String.self, forKey: .overrideName)
  77. scheduledTime = try container.decodeIfPresent(TimeInterval.self, forKey: .scheduledTime)
  78. returnNotification = try container.decodeIfPresent(ReturnNotificationInfo.self, forKey: .returnNotification)
  79. }
  80. init(
  81. user: String,
  82. commandType: TrioRemoteControl.CommandType,
  83. bolusAmount: Decimal? = nil,
  84. target: Int? = nil,
  85. duration: Int? = nil,
  86. carbs: Int? = nil,
  87. protein: Int? = nil,
  88. fat: Int? = nil,
  89. sharedSecret: String,
  90. timestamp: TimeInterval,
  91. overrideName: String? = nil,
  92. scheduledTime: TimeInterval? = nil,
  93. returnNotification: ReturnNotificationInfo? = nil
  94. ) {
  95. self.user = user
  96. self.commandType = commandType
  97. self.bolusAmount = bolusAmount
  98. self.target = target
  99. self.duration = duration
  100. self.carbs = carbs
  101. self.protein = protein
  102. self.fat = fat
  103. self.sharedSecret = sharedSecret
  104. self.timestamp = timestamp
  105. self.overrideName = overrideName
  106. self.scheduledTime = scheduledTime
  107. self.returnNotification = returnNotification
  108. }
  109. func humanReadableDescription() -> String {
  110. var description = "User: \(user). Command Type: \(commandType.description). "
  111. if let override = overrideName {
  112. description += "Override Name: \(override). "
  113. }
  114. switch commandType {
  115. case .bolus:
  116. if let amount = bolusAmount {
  117. description += "Bolus Amount: \(amount) units."
  118. } else {
  119. description += "Bolus Amount: unknown."
  120. }
  121. case .tempTarget:
  122. let targetDesc = target != nil ? "\(target!) mg/dL" : "unknown target"
  123. let durationDesc = duration != nil ? "\(duration!) minutes" : "unknown duration"
  124. description += "Temp Target: \(targetDesc), Duration: \(durationDesc)."
  125. case .cancelTempTarget:
  126. description += "Cancel Temp Target command."
  127. case .meal:
  128. let carbsDesc = carbs != nil ? "\(carbs!)g carbs" : "unknown carbs"
  129. let fatDesc = fat != nil ? "\(fat!)g fat" : "unknown fat"
  130. let proteinDesc = protein != nil ? "\(protein!)g protein" : "unknown protein"
  131. description += "Meal with \(carbsDesc), \(fatDesc), \(proteinDesc)."
  132. case .startOverride:
  133. if let override = overrideName {
  134. description += "Start Override: \(override)."
  135. } else {
  136. description += "Start Override: unknown override name."
  137. }
  138. case .cancelOverride:
  139. description += "Cancel Override command."
  140. }
  141. if let scheduledTime = scheduledTime {
  142. let date = Date(timeIntervalSince1970: scheduledTime)
  143. let formatter = DateFormatter()
  144. formatter.dateStyle = .short
  145. formatter.timeStyle = .short
  146. let dateString = formatter.string(from: date)
  147. description += " Scheduled for: \(dateString)."
  148. }
  149. return description
  150. }
  151. }