CGMRootView.swift 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import LoopKitUI
  2. import SwiftUI
  3. import Swinject
  4. extension CGM {
  5. struct RootView: BaseView {
  6. let resolver: Resolver
  7. let displayClose: Bool
  8. @StateObject var state = StateModel()
  9. @State private var setupCGM = false
  10. @Environment(\.colorScheme) var colorScheme
  11. var color: LinearGradient {
  12. colorScheme == .dark ? LinearGradient(
  13. gradient: Gradient(colors: [
  14. Color.bgDarkBlue,
  15. Color.bgDarkerDarkBlue
  16. ]),
  17. startPoint: .top,
  18. endPoint: .bottom
  19. )
  20. :
  21. LinearGradient(
  22. gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
  23. startPoint: .top,
  24. endPoint: .bottom
  25. )
  26. }
  27. // @AppStorage(UserDefaults.BTKey.cgmTransmitterDeviceAddress.rawValue) private var cgmTransmitterDeviceAddress: String? = nil
  28. var body: some View {
  29. NavigationView {
  30. Form {
  31. Section(header: Text("CGM")) {
  32. Picker("Type", selection: $state.cgmCurrent) {
  33. ForEach(state.listOfCGM) { type in
  34. VStack(alignment: .leading) {
  35. Text(type.displayName)
  36. Text(type.subtitle).font(.caption).foregroundColor(.secondary)
  37. }.tag(type)
  38. }
  39. }
  40. if let link = state.cgmCurrent.type.externalLink {
  41. Button("About this source") {
  42. UIApplication.shared.open(link, options: [:], completionHandler: nil)
  43. }
  44. }
  45. }
  46. if let appURL = state.urlOfApp()
  47. {
  48. Section {
  49. Button {
  50. UIApplication.shared.open(appURL, options: [:]) { success in
  51. if !success {
  52. self.router.alertMessage
  53. .send(MessageContent(content: "Unable to open the app", type: .warning))
  54. }
  55. }
  56. }
  57. label: {
  58. Label(state.displayNameOfApp() ?? "-", systemImage: "waveform.path.ecg.rectangle").font(.title3) }
  59. .frame(maxWidth: .infinity, alignment: .center)
  60. .buttonStyle(.bordered)
  61. }
  62. .listRowBackground(Color.clear)
  63. } else if state.cgmCurrent.type == .nightscout {
  64. if let url = state.url {
  65. Section {
  66. Button {
  67. UIApplication.shared.open(url, options: [:]) { success in
  68. if !success {
  69. self.router.alertMessage
  70. .send(MessageContent(content: "No URL available", type: .warning))
  71. }
  72. }
  73. }
  74. label: { Label("Open URL", systemImage: "waveform.path.ecg.rectangle").font(.title3) }
  75. .frame(maxWidth: .infinity, alignment: .center)
  76. .buttonStyle(.bordered)
  77. }
  78. .listRowBackground(Color.clear)
  79. } else {
  80. Section {
  81. Button {
  82. state.showModal(for: .nighscoutConfigDirect)
  83. // router.mainSecondaryModalView.send(router.view(for: .nighscoutConfigDirect))
  84. }
  85. label: { Label("Config Nightscout", systemImage: "waveform.path.ecg.rectangle").font(.title3)
  86. }
  87. .frame(maxWidth: .infinity, alignment: .center)
  88. .buttonStyle(.bordered)
  89. }
  90. .listRowBackground(Color.clear)
  91. }
  92. }
  93. if state.cgmCurrent.type == .plugin {
  94. Section {
  95. Button("CGM Configuration") {
  96. setupCGM.toggle()
  97. }
  98. }
  99. }
  100. if state.cgmCurrent.type == .xdrip {
  101. Section(header: Text("Heartbeat")) {
  102. VStack(alignment: .leading) {
  103. if let cgmTransmitterDeviceAddress = state.cgmTransmitterDeviceAddress {
  104. Text("CGM address :")
  105. Text(cgmTransmitterDeviceAddress)
  106. } else {
  107. Text("CGM is not used as heartbeat.")
  108. }
  109. }
  110. }
  111. }
  112. if state.cgmCurrent.type == .plugin && state.cgmCurrent.id.contains("Libre") {
  113. Section(header: Text("Calibrations")) {
  114. Text("Calibrations").navigationLink(to: .calibrations, from: self)
  115. }
  116. }
  117. // }
  118. Section(header: Text("Calendar")) {
  119. Toggle("Create Events in Calendar", isOn: $state.createCalendarEvents)
  120. if state.calendarIDs.isNotEmpty {
  121. Picker("Calendar", selection: $state.currentCalendarID) {
  122. ForEach(state.calendarIDs, id: \.self) {
  123. Text($0).tag($0)
  124. }
  125. }
  126. Toggle("Display Emojis as Labels", isOn: $state.displayCalendarEmojis)
  127. Toggle("Display IOB and COB", isOn: $state.displayCalendarIOBandCOB)
  128. } else if state.createCalendarEvents {
  129. if #available(iOS 17.0, *) {
  130. Text(
  131. "If you are not seeing calendars to choose here, please go to Settings -> iAPS -> Calendars and change permissions to \"Full Access\""
  132. ).font(.footnote)
  133. Button("Open Settings") {
  134. // Get the settings URL and open it
  135. if let url = URL(string: UIApplication.openSettingsURLString) {
  136. UIApplication.shared.open(url)
  137. }
  138. }
  139. }
  140. }
  141. }
  142. Section(header: Text("Experimental")) {
  143. Toggle("Smooth Glucose Value", isOn: $state.smoothGlucose)
  144. }
  145. }
  146. .scrollContentBackground(.hidden).background(color)
  147. .onAppear(perform: configureView)
  148. .navigationTitle("CGM")
  149. .navigationBarTitleDisplayMode(.automatic)
  150. .navigationBarItems(leading: displayClose ? Button("Close", action: state.hideModal) : nil)
  151. .sheet(isPresented: $setupCGM) {
  152. if let cgmFetchManager = state.cgmManager,
  153. let cgmManager = cgmFetchManager.cgmManager,
  154. state.cgmCurrent.type == cgmFetchManager.cgmGlucoseSourceType,
  155. state.cgmCurrent.id == cgmFetchManager.cgmGlucosePluginId
  156. {
  157. CGMSettingsView(
  158. cgmManager: cgmManager,
  159. bluetoothManager: state.provider.apsManager.bluetoothManager!,
  160. unit: state.settingsManager.settings.units,
  161. completionDelegate: state
  162. )
  163. } else {
  164. CGMSetupView(
  165. CGMType: state.cgmCurrent,
  166. bluetoothManager: state.provider.apsManager.bluetoothManager!,
  167. unit: state.settingsManager.settings.units,
  168. completionDelegate: state,
  169. setupDelegate: state,
  170. pluginCGMManager: self.state.pluginCGMManager
  171. )
  172. }
  173. }
  174. .onChange(of: setupCGM) { setupCGM in
  175. state.setupCGM = setupCGM
  176. }
  177. .onChange(of: state.setupCGM) { setupCGM in
  178. self.setupCGM = setupCGM
  179. }
  180. .screenNavigation(self)
  181. }
  182. }
  183. }
  184. }