OverridePresetData.swift 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // LoopFollow
  2. // OverridePresetData.swift
  3. import Foundation
  4. struct OverridePresetData: Codable, Identifiable {
  5. let id: String
  6. let name: String
  7. let symbol: String?
  8. let targetRange: ClosedRange<Double>?
  9. let insulinNeedsScaleFactor: Double?
  10. let duration: TimeInterval
  11. enum CodingKeys: String, CodingKey {
  12. case name, symbol, duration
  13. case targetRange
  14. case insulinNeedsScaleFactor
  15. }
  16. init(name: String, symbol: String? = nil, targetRange: ClosedRange<Double>? = nil, insulinNeedsScaleFactor: Double? = nil, duration: TimeInterval) {
  17. id = UUID().uuidString
  18. self.name = name
  19. self.symbol = symbol
  20. self.targetRange = targetRange
  21. self.insulinNeedsScaleFactor = insulinNeedsScaleFactor
  22. self.duration = duration
  23. }
  24. init(from decoder: Decoder) throws {
  25. let container = try decoder.container(keyedBy: CodingKeys.self)
  26. name = try container.decode(String.self, forKey: .name)
  27. symbol = try container.decodeIfPresent(String.self, forKey: .symbol)
  28. duration = try container.decode(TimeInterval.self, forKey: .duration)
  29. // Handle target range which might be stored as min/max values
  30. if let targetRangeDict = try? container.decode([String: Double].self, forKey: .targetRange) {
  31. if let min = targetRangeDict["min"], let max = targetRangeDict["max"] {
  32. targetRange = min ... max
  33. } else {
  34. targetRange = nil
  35. }
  36. } else {
  37. targetRange = nil
  38. }
  39. insulinNeedsScaleFactor = try container.decodeIfPresent(Double.self, forKey: .insulinNeedsScaleFactor)
  40. id = UUID().uuidString
  41. }
  42. var durationDescription: String {
  43. if duration == 0 {
  44. return "Indefinite"
  45. } else {
  46. let hours = Int(duration / 3600)
  47. let minutes = Int((duration.truncatingRemainder(dividingBy: 3600)) / 60)
  48. if hours > 0 {
  49. return "\(hours)h \(minutes)m"
  50. } else {
  51. return "\(minutes)m"
  52. }
  53. }
  54. }
  55. }
  56. // MARK: - Codable Extensions
  57. extension ClosedRange: Codable where Bound: Codable {
  58. public init(from decoder: Decoder) throws {
  59. let container = try decoder.container(keyedBy: CodingKeys.self)
  60. let lower = try container.decode(Bound.self, forKey: .lower)
  61. let upper = try container.decode(Bound.self, forKey: .upper)
  62. self.init(uncheckedBounds: (lower: lower, upper: upper))
  63. }
  64. public func encode(to encoder: Encoder) throws {
  65. var container = encoder.container(keyedBy: CodingKeys.self)
  66. try container.encode(lowerBound, forKey: .lower)
  67. try container.encode(upperBound, forKey: .upper)
  68. }
  69. private enum CodingKeys: String, CodingKey {
  70. case lower, upper
  71. }
  72. }