LiveActivityAttributes+Helper.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import Foundation
  2. extension UserDefaults {
  3. private enum Keys {
  4. static let liveActivityOrder = "liveActivityOrder"
  5. }
  6. func loadLiveActivityOrderFromUserDefaults() -> [LiveActivityAttributes.LiveActivityItem]? {
  7. if let itemStrings = stringArray(forKey: Keys.liveActivityOrder) {
  8. return itemStrings.map { string in
  9. if string == "" {
  10. return .empty
  11. } else {
  12. return LiveActivityAttributes.LiveActivityItem(rawValue: string) ?? .empty
  13. }
  14. }
  15. }
  16. return nil
  17. }
  18. }
  19. extension LiveActivityAttributes.ContentState {
  20. static func formatGlucose(_ value: Int, units: GlucoseUnits, forceSign: Bool) -> String {
  21. let formatter = NumberFormatter()
  22. formatter.numberStyle = .decimal
  23. formatter.maximumFractionDigits = 0
  24. if units == .mmolL {
  25. formatter.minimumFractionDigits = 1
  26. formatter.maximumFractionDigits = 1
  27. }
  28. if forceSign {
  29. formatter.positivePrefix = formatter.plusSign
  30. }
  31. formatter.roundingMode = .halfUp
  32. return formatter
  33. .string(from: units == .mmolL ? value.asMmolL as NSNumber : NSNumber(value: value))!
  34. }
  35. static func calculateChange(chart: [GlucoseData], units: GlucoseUnits) -> String {
  36. guard chart.count > 2 else { return "" }
  37. let formatter = NumberFormatter()
  38. formatter.numberStyle = .decimal
  39. formatter.maximumFractionDigits = 1
  40. formatter.positivePrefix = " +"
  41. formatter.negativePrefix = " -"
  42. var lastGlucose = Decimal(chart.first?.glucose ?? 0)
  43. var secondLastGlucose = Decimal(chart.dropFirst().first?.glucose ?? 0)
  44. if units == .mmolL {
  45. lastGlucose = lastGlucose.asMmolL
  46. secondLastGlucose = secondLastGlucose.asMmolL
  47. formatter.minimumFractionDigits = 1
  48. formatter.maximumFractionDigits = 1
  49. }
  50. let delta = lastGlucose - secondLastGlucose
  51. return formatter.string(from: delta as NSNumber) ?? "--"
  52. }
  53. init(
  54. new bg: GlucoseData,
  55. prev _: GlucoseData?,
  56. units: GlucoseUnits,
  57. chart: [GlucoseData],
  58. settings: TrioSettings,
  59. determination: DeterminationData?,
  60. iob: Decimal?,
  61. override: OverrideData?,
  62. tempTarget: TempTargetData?,
  63. widgetItems: [LiveActivityAttributes.LiveActivityItem]?
  64. ) {
  65. let glucose = bg.glucose
  66. let formattedBG = Self.formatGlucose(Int(glucose), units: units, forceSign: false)
  67. var rotationDegrees = 0.0
  68. switch bg.direction {
  69. case .doubleUp,
  70. .singleUp,
  71. .tripleUp:
  72. rotationDegrees = -90
  73. case .fortyFiveUp:
  74. rotationDegrees = -45
  75. case .flat:
  76. rotationDegrees = 0
  77. case .fortyFiveDown:
  78. rotationDegrees = 45
  79. case .doubleDown,
  80. .singleDown,
  81. .tripleDown:
  82. rotationDegrees = 90
  83. case nil,
  84. .notComputable,
  85. .rateOutOfRange:
  86. rotationDegrees = 0
  87. default:
  88. rotationDegrees = 0
  89. }
  90. let trendString = bg.direction?.symbol as? String
  91. let change = Self.calculateChange(chart: chart, units: units)
  92. let detailedState = LiveActivityAttributes.ContentAdditionalState(
  93. chart: chart.map { LiveActivityAttributes.ChartItem(value: Decimal($0.glucose), date: $0.date) },
  94. rotationDegrees: rotationDegrees,
  95. cob: Decimal(determination?.cob ?? 0),
  96. iob: iob ?? 0 as Decimal,
  97. tdd: determination?.tdd ?? 0 as Decimal,
  98. isOverrideActive: override?.isActive ?? false,
  99. overrideName: override?.overrideName ?? "Override",
  100. overrideDate: override?.date ?? Date(),
  101. overrideDuration: override?.duration ?? 0,
  102. overrideTarget: override?.target ?? 0,
  103. isTempTargetActive: tempTarget?.isActive ?? false,
  104. tempTargetName: tempTarget?.tempTargetName ?? "Temp Target",
  105. tempTargetDate: tempTarget?.date ?? Date(),
  106. tempTargetDuration: tempTarget?.duration ?? 0,
  107. tempTargetTarget: tempTarget?.target ?? 0,
  108. widgetItems: widgetItems ?? [] // set empty array here to silence compiler; this can never be nil
  109. )
  110. self.init(
  111. unit: settings.units.rawValue,
  112. bg: formattedBG,
  113. direction: trendString,
  114. change: change,
  115. date: determination?.date ?? nil,
  116. highGlucose: settings.high,
  117. lowGlucose: settings.low,
  118. target: determination?.target ?? 100 as Decimal,
  119. glucoseColorScheme: settings.glucoseColorScheme.rawValue,
  120. useDetailedViewIOS: settings.lockScreenView == .detailed,
  121. useDetailedViewWatchOS: settings.smartStackView == .detailed,
  122. detailedViewState: detailedState,
  123. isInitialState: false
  124. )
  125. }
  126. }