PodLifeHUDView.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //
  2. // PodLifeHUDView.swift
  3. // OmniKit
  4. //
  5. // Based on OmniKitUI/Views/PodLifeHUDView.swift
  6. // Created by Pete Schwamb on 10/22/18.
  7. // Copyright © 2021 LoopKit Authors. All rights reserved.
  8. //
  9. import UIKit
  10. import LoopKitUI
  11. import MKRingProgressView
  12. public enum PodAlertState {
  13. case none
  14. case warning
  15. case fault
  16. }
  17. public class PodLifeHUDView: BaseHUDView, NibLoadable {
  18. override public var orderPriority: HUDViewOrderPriority {
  19. return 12
  20. }
  21. @IBOutlet private weak var timeLabel: UILabel! {
  22. didSet {
  23. // Setting this color in code because the nib isn't being applied correctly
  24. if #available(iOSApplicationExtension 13.0, *) {
  25. timeLabel.textColor = .label
  26. }
  27. }
  28. }
  29. @IBOutlet private weak var progressRing: RingProgressView!
  30. @IBOutlet private weak var alertLabel: UILabel! {
  31. didSet {
  32. alertLabel.alpha = 0
  33. alertLabel.textColor = UIColor.white
  34. alertLabel.layer.cornerRadius = 9
  35. alertLabel.clipsToBounds = true
  36. }
  37. }
  38. @IBOutlet private weak var backgroundRing: UIImageView! {
  39. didSet {
  40. if #available(iOSApplicationExtension 13.0, iOS 13.0, *) {
  41. backgroundRing.tintColor = .systemGray5
  42. } else {
  43. backgroundRing.tintColor = UIColor(red: 198 / 255, green: 199 / 255, blue: 201 / 255, alpha: 1)
  44. }
  45. }
  46. }
  47. private var startTime: Date?
  48. private var lifetime: TimeInterval?
  49. private var timer: Timer?
  50. public var alertState: PodAlertState = .none {
  51. didSet {
  52. updateAlertStateLabel()
  53. }
  54. }
  55. public class func instantiate() -> PodLifeHUDView {
  56. return nib().instantiate(withOwner: nil, options: nil)[0] as! PodLifeHUDView
  57. }
  58. public func setPodLifeCycle(startTime: Date, lifetime: TimeInterval) {
  59. self.startTime = startTime
  60. self.lifetime = lifetime
  61. updateProgressCircle()
  62. if timer == nil {
  63. self.timer = Timer.scheduledTimer(withTimeInterval: .seconds(10), repeats: true) { [weak self] _ in
  64. self?.updateProgressCircle()
  65. }
  66. }
  67. }
  68. override open func stateColorsDidUpdate() {
  69. super.stateColorsDidUpdate()
  70. updateProgressCircle()
  71. updateAlertStateLabel()
  72. }
  73. private var endColor: UIColor? {
  74. didSet {
  75. let primaryColor = endColor ?? UIColor(red: 198 / 255, green: 199 / 255, blue: 201 / 255, alpha: 1)
  76. self.progressRing.endColor = primaryColor
  77. self.progressRing.startColor = primaryColor
  78. }
  79. }
  80. private lazy var timeFormatter: DateComponentsFormatter = {
  81. let formatter = DateComponentsFormatter()
  82. formatter.allowedUnits = [.hour, .minute]
  83. formatter.maximumUnitCount = 1
  84. formatter.unitsStyle = .abbreviated
  85. return formatter
  86. }()
  87. private func updateAlertStateLabel() {
  88. var alertLabelAlpha: CGFloat = 1
  89. if alertState == .fault {
  90. timer = nil
  91. }
  92. switch alertState {
  93. case .fault:
  94. alertLabel.text = "!"
  95. alertLabel.backgroundColor = stateColors?.error
  96. case .warning:
  97. alertLabel.text = "!"
  98. alertLabel.backgroundColor = stateColors?.warning
  99. case .none:
  100. alertLabelAlpha = 0
  101. }
  102. alertLabel.alpha = alertLabelAlpha
  103. UIView.animate(withDuration: 0.25, animations: {
  104. self.alertLabel.alpha = alertLabelAlpha
  105. })
  106. }
  107. private func updateProgressCircle() {
  108. if let startTime = startTime, let lifetime = lifetime {
  109. let age = -startTime.timeIntervalSinceNow
  110. let progress = Double(age / lifetime)
  111. progressRing.progress = progress
  112. if progress < 0.75 {
  113. self.endColor = stateColors?.normal
  114. progressRing.shadowOpacity = 0
  115. } else if progress < 1.0 {
  116. self.endColor = stateColors?.warning
  117. progressRing.shadowOpacity = 0.5
  118. } else {
  119. self.endColor = stateColors?.error
  120. progressRing.shadowOpacity = 0.8
  121. }
  122. let remaining = (lifetime - age)
  123. // Update time label and caption
  124. if alertState == .fault {
  125. timeLabel.isHidden = true
  126. caption.text = LocalizedString("Fault", comment: "Pod life HUD view label")
  127. } else if remaining > .hours(24) {
  128. timeLabel.isHidden = true
  129. caption.text = LocalizedString("Pod Age", comment: "Label describing pod age view")
  130. } else if remaining > 0 {
  131. let remainingFlooredToHour = remaining > .hours(1) ? remaining - remaining.truncatingRemainder(dividingBy: .hours(1)) : remaining
  132. if let timeString = timeFormatter.string(from: remainingFlooredToHour) {
  133. timeLabel.isHidden = false
  134. timeLabel.text = timeString
  135. }
  136. caption.text = LocalizedString("Remaining", comment: "Label describing time remaining view")
  137. } else {
  138. timeLabel.isHidden = true
  139. caption.text = LocalizedString("Replace Pod", comment: "Label indicating pod replacement necessary")
  140. }
  141. }
  142. }
  143. func pauseUpdates() {
  144. timer?.invalidate()
  145. timer = nil
  146. }
  147. override public func awakeFromNib() {
  148. super.awakeFromNib()
  149. }
  150. }