PumpView.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import SwiftUI
  2. struct PumpView: View {
  3. @Binding var reservoir: Decimal?
  4. @Binding var battery: Battery?
  5. @Binding var name: String
  6. @Binding var expiresAtDate: Date?
  7. @Binding var timerDate: Date
  8. @State var state: Home.StateModel
  9. @Environment(\.colorScheme) var colorScheme
  10. private var reservoirFormatter: NumberFormatter {
  11. let formatter = NumberFormatter()
  12. formatter.numberStyle = .decimal
  13. formatter.maximumFractionDigits = 0
  14. return formatter
  15. }
  16. private var batteryFormatter: NumberFormatter {
  17. let formatter = NumberFormatter()
  18. formatter.numberStyle = .percent
  19. return formatter
  20. }
  21. private var numberFormatter: NumberFormatter {
  22. let formatter = NumberFormatter()
  23. formatter.numberStyle = .decimal
  24. formatter.maximumFractionDigits = 2
  25. return formatter
  26. }
  27. private var dateFormatter: DateFormatter {
  28. let dateFormatter = DateFormatter()
  29. dateFormatter.timeStyle = .short
  30. return dateFormatter
  31. }
  32. var body: some View {
  33. HStack {
  34. Text("IOB").font(.caption).foregroundColor(.secondary)
  35. Text(
  36. (numberFormatter.string(from: (state.suggestion?.iob ?? 0) as NSNumber) ?? "0") +
  37. NSLocalizedString(" U", comment: "Insulin unit")
  38. )
  39. .font(.caption).fontWeight(.bold)
  40. Spacer()
  41. Text("COB").font(.caption).foregroundColor(.secondary)
  42. Text(
  43. (numberFormatter.string(from: (state.suggestion?.cob ?? 0) as NSNumber) ?? "0") +
  44. NSLocalizedString(" g", comment: "gram of carbs")
  45. )
  46. .font(.caption).fontWeight(.bold)
  47. Spacer()
  48. LoopView(
  49. suggestion: $state.suggestion,
  50. enactedSuggestion: $state.enactedSuggestion,
  51. closedLoop: $state.closedLoop,
  52. timerDate: $state.timerDate,
  53. isLooping: $state.isLooping,
  54. lastLoopDate: $state.lastLoopDate,
  55. manualTempBasal: $state.manualTempBasal
  56. ).onTapGesture {
  57. state.isStatusPopupPresented = true
  58. }.onLongPressGesture {
  59. let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
  60. impactHeavy.impactOccurred()
  61. state.runLoop()
  62. }
  63. Spacer()
  64. if let reservoir = reservoir {
  65. HStack {
  66. Image(systemName: "drop.fill")
  67. .resizable()
  68. .aspectRatio(contentMode: .fit)
  69. .frame(maxHeight: 15)
  70. .foregroundColor(reservoirColor)
  71. if reservoir == 0xDEAD_BEEF {
  72. Text("50+ " + NSLocalizedString("U", comment: "Insulin unit")).font(.callout)
  73. .fontWeight(.bold)
  74. } else {
  75. Text(
  76. reservoirFormatter
  77. .string(from: reservoir as NSNumber)! + NSLocalizedString(" U", comment: "Insulin unit")
  78. )
  79. .font(.caption).fontWeight(.bold)
  80. }
  81. }
  82. }
  83. Spacer()
  84. if let battery = battery, battery.display ?? false, expiresAtDate == nil {
  85. HStack {
  86. Image(systemName: "battery.100")
  87. .resizable()
  88. .aspectRatio(contentMode: .fit)
  89. .frame(maxHeight: 15)
  90. .foregroundColor(batteryColor)
  91. Text("\(Int(battery.percent ?? 100)) %").font(.caption)
  92. .fontWeight(.bold)
  93. }
  94. }
  95. if let date = expiresAtDate {
  96. HStack {
  97. Image(systemName: "stopwatch.fill")
  98. .resizable()
  99. .aspectRatio(contentMode: .fit)
  100. .frame(maxHeight: 15)
  101. .foregroundColor(timerColor)
  102. Text(remainingTimeString(time: date.timeIntervalSince(timerDate))).font(.callout)
  103. .fontWeight(.bold)
  104. }
  105. }
  106. }
  107. }
  108. private func remainingTimeString(time: TimeInterval) -> String {
  109. guard time > 0 else {
  110. return NSLocalizedString("Replace pod", comment: "View/Header when pod expired")
  111. }
  112. var time = time
  113. let days = Int(time / 1.days.timeInterval)
  114. time -= days.days.timeInterval
  115. let hours = Int(time / 1.hours.timeInterval)
  116. time -= hours.hours.timeInterval
  117. let minutes = Int(time / 1.minutes.timeInterval)
  118. if days >= 1 {
  119. return "\(days)" + NSLocalizedString("d", comment: "abbreviation for days") + " \(hours)" +
  120. NSLocalizedString("h", comment: "abbreviation for hours")
  121. }
  122. if hours >= 1 {
  123. return "\(hours)" + NSLocalizedString("h", comment: "abbreviation for hours")
  124. }
  125. return "\(minutes)" + NSLocalizedString("m", comment: "abbreviation for minutes")
  126. }
  127. private var batteryColor: Color {
  128. guard let battery = battery, let percent = battery.percent else {
  129. return .gray
  130. }
  131. switch percent {
  132. case ...10:
  133. return .red
  134. case ...20:
  135. return .yellow
  136. default:
  137. return .green
  138. }
  139. }
  140. private var reservoirColor: Color {
  141. guard let reservoir = reservoir else {
  142. return .gray
  143. }
  144. switch reservoir {
  145. case ...10:
  146. return .red
  147. case ...30:
  148. return .yellow
  149. default:
  150. return .blue
  151. }
  152. }
  153. private var timerColor: Color {
  154. guard let expisesAt = expiresAtDate else {
  155. return .gray
  156. }
  157. let time = expisesAt.timeIntervalSince(timerDate)
  158. switch time {
  159. case ...8.hours.timeInterval:
  160. return .red
  161. case ...1.days.timeInterval:
  162. return .yellow
  163. default:
  164. return .green
  165. }
  166. }
  167. }
  168. struct Hairline: View {
  169. let color: Color
  170. var body: some View {
  171. Rectangle()
  172. .fill(color)
  173. .frame(width: UIScreen.main.bounds.width / 1.3, height: 1)
  174. .opacity(0.5)
  175. }
  176. }