G7SettingsView.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. //
  2. // G7SettingsView.swift
  3. // CGMBLEKitUI
  4. //
  5. // Created by Pete Schwamb on 9/25/22.
  6. // Copyright © 2022 LoopKit Authors. All rights reserved.
  7. //
  8. import Foundation
  9. import SwiftUI
  10. import G7SensorKit
  11. import LoopKitUI
  12. struct G7SettingsView: View {
  13. private var sessionLengthFormatter: DateComponentsFormatter = {
  14. let formatter = DateComponentsFormatter()
  15. formatter.allowedUnits = [.day, .hour, .minute]
  16. formatter.unitsStyle = .full
  17. formatter.maximumUnitCount = 2
  18. return formatter
  19. }()
  20. @Environment(\.guidanceColors) private var guidanceColors
  21. @Environment(\.glucoseTintColor) private var glucoseTintColor
  22. var didFinish: (() -> Void)
  23. var deleteCGM: (() -> Void)
  24. @ObservedObject var viewModel: G7SettingsViewModel
  25. @State private var showingDeletionSheet = false
  26. init(didFinish: @escaping () -> Void, deleteCGM: @escaping () -> Void, viewModel: G7SettingsViewModel) {
  27. self.didFinish = didFinish
  28. self.deleteCGM = deleteCGM
  29. self.viewModel = viewModel
  30. }
  31. private var timeFormatter: DateFormatter = {
  32. let formatter = DateFormatter()
  33. formatter.dateStyle = .short
  34. formatter.timeStyle = .short
  35. formatter.locale = Locale.current
  36. formatter.setLocalizedDateFormatFromTemplate("E, MMM d, hh:mm")
  37. return formatter
  38. }()
  39. var body: some View {
  40. List {
  41. Section() {
  42. VStack {
  43. headerImage
  44. progressBar
  45. }
  46. }
  47. if let activatedAt = viewModel.activatedAt {
  48. HStack {
  49. Text(LocalizedString("Sensor Start", comment: "title for g7 settings row showing sensor start time"))
  50. Spacer()
  51. Text(timeFormatter.string(from: activatedAt))
  52. .foregroundColor(.secondary)
  53. }
  54. HStack {
  55. Text(LocalizedString("Sensor Expiration", comment: "title for g7 settings row showing sensor expiration time"))
  56. Spacer()
  57. Text(timeFormatter.string(from: activatedAt.addingTimeInterval(G7Sensor.lifetime)))
  58. .foregroundColor(.secondary)
  59. }
  60. HStack {
  61. Text(LocalizedString("Grace Period End", comment: "title for g7 settings row showing sensor grace period end time"))
  62. Spacer()
  63. Text(timeFormatter.string(from: activatedAt.addingTimeInterval(G7Sensor.lifetime + G7Sensor.gracePeriod)))
  64. .foregroundColor(.secondary)
  65. }
  66. }
  67. Section("Last Reading") {
  68. LabeledValueView(label: LocalizedString("Glucose", comment: "Field label"),
  69. value: viewModel.lastGlucoseString)
  70. LabeledDateView(label: LocalizedString("Time", comment: "Field label"),
  71. date: viewModel.latestReadingTimestamp,
  72. dateFormatter: viewModel.dateFormatter)
  73. LabeledValueView(label: LocalizedString("Trend", comment: "Field label"),
  74. value: viewModel.lastGlucoseTrendString)
  75. }
  76. Section("Bluetooth") {
  77. if let name = viewModel.sensorName {
  78. HStack {
  79. Text(LocalizedString("Name", comment: "title for g7 settings row showing BLE Name"))
  80. Spacer()
  81. Text(name)
  82. .foregroundColor(.secondary)
  83. }
  84. }
  85. if viewModel.scanning {
  86. HStack {
  87. Text(LocalizedString("Scanning", comment: "title for g7 settings connection status when scanning"))
  88. Spacer()
  89. SwiftUI.ProgressView()
  90. }
  91. } else {
  92. if viewModel.connected {
  93. Text(LocalizedString("Connected", comment: "title for g7 settings connection status when connected"))
  94. } else {
  95. HStack {
  96. Text(LocalizedString("Connecting", comment: "title for g7 settings connection status when connecting"))
  97. Spacer()
  98. SwiftUI.ProgressView()
  99. }
  100. }
  101. }
  102. if let lastConnect = viewModel.lastConnect {
  103. LabeledValueView(label: LocalizedString("Last Connect", comment: "title for g7 settings row showing sensor last connect time"),
  104. value: timeFormatter.string(from: lastConnect))
  105. }
  106. }
  107. Section("Configuration") {
  108. HStack {
  109. Toggle(LocalizedString("Upload Readings", comment: "title for g7 config settings to upload readings"), isOn: $viewModel.uploadReadings)
  110. }
  111. }
  112. Section () {
  113. if !self.viewModel.scanning {
  114. Button("Scan for new sensor", action: {
  115. self.viewModel.scanForNewSensor()
  116. })
  117. }
  118. deleteCGMButton
  119. }
  120. }
  121. .insetGroupedListStyle()
  122. .navigationBarItems(trailing: doneButton)
  123. .navigationBarTitle(LocalizedString("Dexcom G7", comment: "Navigation bar title for G7SettingsView"))
  124. }
  125. private var deleteCGMButton: some View {
  126. Button(action: {
  127. showingDeletionSheet = true
  128. }, label: {
  129. Text(LocalizedString("Delete CGM", comment: "Button label for removing CGM"))
  130. .foregroundColor(.red)
  131. }).actionSheet(isPresented: $showingDeletionSheet) {
  132. ActionSheet(
  133. title: Text("Are you sure you want to delete this CGM?"),
  134. buttons: [
  135. .destructive(Text("Delete CGM")) {
  136. self.deleteCGM()
  137. },
  138. .cancel(),
  139. ]
  140. )
  141. }
  142. }
  143. private var headerImage: some View {
  144. VStack(alignment: .center) {
  145. Image(frameworkImage: "g7")
  146. .resizable()
  147. .aspectRatio(contentMode: ContentMode.fit)
  148. .frame(height: 150)
  149. .padding(.horizontal)
  150. }.frame(maxWidth: .infinity)
  151. }
  152. @ViewBuilder
  153. private var progressBar: some View {
  154. VStack(alignment: .leading, spacing: 4) {
  155. HStack(alignment: .firstTextBaseline) {
  156. Text(viewModel.progressBarState.label)
  157. .font(.system(size: 17))
  158. .foregroundColor(color(for: viewModel.progressBarState.labelColor))
  159. Spacer()
  160. if let referenceDate = viewModel.progressReferenceDate {
  161. Text(sessionLengthFormatter.string(from: referenceDate.timeIntervalSince(Date())) ?? "")
  162. .foregroundColor(.secondary)
  163. }
  164. }
  165. ProgressView(value: viewModel.progressBarProgress)
  166. .accentColor(color(for: viewModel.progressBarColorStyle))
  167. }
  168. }
  169. private func color(for colorStyle: ColorStyle) -> Color {
  170. switch colorStyle {
  171. case .glucose:
  172. return glucoseTintColor
  173. case .warning:
  174. return guidanceColors.warning
  175. case .critical:
  176. return guidanceColors.critical
  177. case .normal:
  178. return .primary
  179. case .dimmed:
  180. return .secondary
  181. }
  182. }
  183. private var doneButton: some View {
  184. Button("Done", action: {
  185. self.didFinish()
  186. })
  187. }
  188. }