GlucoseNotificationSettingsRootView.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import ActivityKit
  2. import Combine
  3. import SwiftUI
  4. import Swinject
  5. extension GlucoseNotificationSettings {
  6. struct RootView: BaseView {
  7. let resolver: Resolver
  8. @StateObject var state = StateModel()
  9. @State private var shouldDisplayHint: Bool = false
  10. @State var hintDetent = PresentationDetent.large
  11. @State var selectedVerboseHint: String?
  12. @State var hintLabel: String?
  13. @State private var decimalPlaceholder: Decimal = 0.0
  14. @State private var booleanPlaceholder: Bool = false
  15. @State var notificationsDisabled = false
  16. @State private var displayPickerLowGlucose: Bool = false
  17. @State private var displayPickerHighGlucose: Bool = false
  18. private var glucoseFormatter: NumberFormatter {
  19. let formatter = NumberFormatter()
  20. formatter.numberStyle = .decimal
  21. formatter.maximumFractionDigits = 0
  22. if state.units == .mmolL {
  23. formatter.maximumFractionDigits = 1
  24. }
  25. formatter.roundingMode = .halfUp
  26. return formatter
  27. }
  28. private var carbsFormatter: NumberFormatter {
  29. let formatter = NumberFormatter()
  30. formatter.numberStyle = .decimal
  31. formatter.maximumFractionDigits = 0
  32. return formatter
  33. }
  34. @Environment(\.colorScheme) var colorScheme
  35. var color: LinearGradient {
  36. colorScheme == .dark ? LinearGradient(
  37. gradient: Gradient(colors: [
  38. Color.bgDarkBlue,
  39. Color.bgDarkerDarkBlue
  40. ]),
  41. startPoint: .top,
  42. endPoint: .bottom
  43. )
  44. :
  45. LinearGradient(
  46. gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
  47. startPoint: .top,
  48. endPoint: .bottom
  49. )
  50. }
  51. var body: some View {
  52. Form {
  53. SettingInputSection(
  54. decimalValue: $decimalPlaceholder,
  55. booleanValue: $state.notificationsPump,
  56. shouldDisplayHint: $shouldDisplayHint,
  57. selectedVerboseHint: Binding(
  58. get: { selectedVerboseHint },
  59. set: {
  60. selectedVerboseHint = $0
  61. hintLabel = "Always Notify Pump"
  62. }
  63. ),
  64. units: state.units,
  65. type: .boolean,
  66. label: "Always Notify Pump",
  67. miniHint: "Always Notify Pump Warnings",
  68. verboseHint: "With iOS Trio Notifications enabled, you can let Trio display most Pump Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue.\n\nIf iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.\n\nAn example of a Pump Warning is 'Pod Expiration Reminder'",
  69. headerText: "Trio Information Notifications"
  70. )
  71. SettingInputSection(
  72. decimalValue: $decimalPlaceholder,
  73. booleanValue: $state.notificationsCgm,
  74. shouldDisplayHint: $shouldDisplayHint,
  75. selectedVerboseHint: Binding(
  76. get: { selectedVerboseHint },
  77. set: {
  78. selectedVerboseHint = $0
  79. hintLabel = "Always Notify CGM"
  80. }
  81. ),
  82. units: state.units,
  83. type: .boolean,
  84. label: "Always Notify CGM",
  85. miniHint: "Always Notify CGM Warnings",
  86. verboseHint: "With iOS Trio Notifications enabled, you can let Trio display most CGM Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue.\n\nIf iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.\n\nAn example of a CGM Warning is 'Unable to open the app'"
  87. )
  88. SettingInputSection(
  89. decimalValue: $decimalPlaceholder,
  90. booleanValue: $state.notificationsCarb,
  91. shouldDisplayHint: $shouldDisplayHint,
  92. selectedVerboseHint: Binding(
  93. get: { selectedVerboseHint },
  94. set: {
  95. selectedVerboseHint = $0
  96. hintLabel = "Always Notify Carb"
  97. }
  98. ),
  99. units: state.units,
  100. type: .boolean,
  101. label: "Always Notify Carb",
  102. miniHint: "Always Notify Carb Warnings",
  103. verboseHint: "With iOS Trio Notifications enabled, you can let Trio display most Carb Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue.\n\nIf iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.\n\nAn example of a Carb Warning is 'Carbs required: 30 g'"
  104. )
  105. SettingInputSection(
  106. decimalValue: $decimalPlaceholder,
  107. booleanValue: $state.notificationsAlgorithm,
  108. shouldDisplayHint: $shouldDisplayHint,
  109. selectedVerboseHint: Binding(
  110. get: { selectedVerboseHint },
  111. set: {
  112. selectedVerboseHint = $0
  113. hintLabel = "Always Notify Algorithm"
  114. }
  115. ),
  116. units: state.units,
  117. type: .boolean,
  118. label: "Always Notify Algorithm",
  119. miniHint: "Always Notify Algorithm Warnings",
  120. verboseHint: "With iOS Trio Notifications enabled, you can let Trio display most Algorithm Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue.\n\nIf iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.\n\nAn example of a Algorithm Warning is 'Error: Invalid glucose: Not enough glucose data'"
  121. )
  122. SettingInputSection(
  123. decimalValue: $decimalPlaceholder,
  124. booleanValue: $state.glucoseBadge,
  125. shouldDisplayHint: $shouldDisplayHint,
  126. selectedVerboseHint: Binding(
  127. get: { selectedVerboseHint },
  128. set: {
  129. selectedVerboseHint = $0
  130. hintLabel = "Show Glucose App Badge"
  131. }
  132. ),
  133. units: state.units,
  134. type: .boolean,
  135. label: "Show Glucose App Badge",
  136. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  137. verboseHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  138. headerText: "Various Glucose Notifications"
  139. )
  140. SettingInputSection(
  141. decimalValue: $decimalPlaceholder,
  142. booleanValue: $state.glucoseNotificationsAlways,
  143. shouldDisplayHint: $shouldDisplayHint,
  144. selectedVerboseHint: Binding(
  145. get: { selectedVerboseHint },
  146. set: {
  147. selectedVerboseHint = $0
  148. hintLabel = "e"
  149. }
  150. ),
  151. units: state.units,
  152. type: .boolean,
  153. label: "Always Notify Glucose",
  154. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  155. verboseHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  156. )
  157. SettingInputSection(
  158. decimalValue: $decimalPlaceholder,
  159. booleanValue: $state.useAlarmSound,
  160. shouldDisplayHint: $shouldDisplayHint,
  161. selectedVerboseHint: Binding(
  162. get: { selectedVerboseHint },
  163. set: {
  164. selectedVerboseHint = $0
  165. hintLabel = "Play Alarm Sound"
  166. }
  167. ),
  168. units: state.units,
  169. type: .boolean,
  170. label: "Play Alarm Sound",
  171. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  172. verboseHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  173. )
  174. SettingInputSection(
  175. decimalValue: $decimalPlaceholder,
  176. booleanValue: $state.addSourceInfoToGlucoseNotifications,
  177. shouldDisplayHint: $shouldDisplayHint,
  178. selectedVerboseHint: Binding(
  179. get: { selectedVerboseHint },
  180. set: {
  181. selectedVerboseHint = $0
  182. hintLabel = "Add Glucose Source to Alarm"
  183. }
  184. ),
  185. units: state.units,
  186. type: .boolean,
  187. label: "Add Glucose Source to Alarm",
  188. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  189. verboseHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  190. )
  191. self.lowAndHighGlucoseAlertSection
  192. }
  193. .sheet(isPresented: $shouldDisplayHint) {
  194. SettingInputHintView(
  195. hintDetent: $hintDetent,
  196. shouldDisplayHint: $shouldDisplayHint,
  197. hintLabel: hintLabel ?? "",
  198. hintText: selectedVerboseHint ?? "",
  199. sheetTitle: "Help"
  200. )
  201. }
  202. .onReceive(
  203. resolver.resolve(AlertPermissionsChecker.self)!.$notificationsDisabled,
  204. perform: {
  205. notificationsDisabled = $0
  206. }
  207. )
  208. .scrollContentBackground(.hidden).background(color)
  209. // .onAppear(perform: configureView)
  210. .onAppear {
  211. configureView {}
  212. }
  213. .navigationBarTitle("Trio Notifications")
  214. .navigationBarTitleDisplayMode(.automatic)
  215. }
  216. var lowAndHighGlucoseAlertSection: some View {
  217. Section {
  218. VStack {
  219. VStack {
  220. HStack {
  221. Text("Low Glucose Alarm Limit")
  222. Spacer()
  223. Group {
  224. Text(
  225. state.units == .mgdL ? state.lowGlucose.description : state.lowGlucose.formattedAsMmolL
  226. )
  227. .foregroundColor(!displayPickerLowGlucose ? .primary : .accentColor)
  228. Text(state.units == .mgdL ? " mg/dL" : " mmol/L").foregroundColor(.secondary)
  229. }
  230. }
  231. .onTapGesture {
  232. displayPickerLowGlucose.toggle()
  233. }
  234. }
  235. .padding(.top)
  236. if displayPickerLowGlucose {
  237. let setting = PickerSettingsProvider.shared.settings.lowGlucose
  238. Picker(selection: $state.lowGlucose, label: Text("")) {
  239. ForEach(
  240. PickerSettingsProvider.shared.generatePickerValues(from: setting, units: state.units),
  241. id: \.self
  242. ) { value in
  243. let displayValue = state.units == .mgdL ? value.description : value.formattedAsMmolL
  244. Text(displayValue).tag(value)
  245. }
  246. }
  247. .pickerStyle(WheelPickerStyle())
  248. .frame(maxWidth: .infinity)
  249. }
  250. VStack {
  251. HStack {
  252. Text("High Glucose Alarm Limit")
  253. Spacer()
  254. Group {
  255. Text(
  256. state.units == .mgdL ? state.highGlucose.description : state.highGlucose.formattedAsMmolL
  257. )
  258. .foregroundColor(!displayPickerHighGlucose ? .primary : .accentColor)
  259. Text(state.units == .mgdL ? " mg/dL" : " mmol/L").foregroundColor(.secondary)
  260. }
  261. }
  262. .onTapGesture {
  263. displayPickerHighGlucose.toggle()
  264. }
  265. }
  266. .padding(.top)
  267. if displayPickerHighGlucose {
  268. let setting = PickerSettingsProvider.shared.settings.highGlucose
  269. Picker(selection: $state.highGlucose, label: Text("")) {
  270. ForEach(
  271. PickerSettingsProvider.shared.generatePickerValues(from: setting, units: state.units),
  272. id: \.self
  273. ) { value in
  274. let displayValue = state.units == .mgdL ? value.description : value.formattedAsMmolL
  275. Text(displayValue).tag(value)
  276. }
  277. }
  278. .pickerStyle(WheelPickerStyle())
  279. .frame(maxWidth: .infinity)
  280. }
  281. HStack(alignment: .top) {
  282. Text(
  283. "Set the lower and upper limit for glucose alarms. See hint for more details."
  284. )
  285. .lineLimit(nil)
  286. .font(.footnote)
  287. .foregroundColor(.secondary)
  288. Spacer()
  289. Button(
  290. action: {
  291. hintLabel = "Low and High Glucose Alarm Limits"
  292. selectedVerboseHint =
  293. "These two settings limit the range outside of which you will be notified via push notifications. If your CGM readings are below 'Low' or above 'High', you will receive an alarm via push notification."
  294. shouldDisplayHint.toggle()
  295. },
  296. label: {
  297. HStack {
  298. Image(systemName: "questionmark.circle")
  299. }
  300. }
  301. ).buttonStyle(BorderlessButtonStyle())
  302. }.padding(.top)
  303. }.padding(.bottom)
  304. }.listRowBackground(Color.chart)
  305. }
  306. }
  307. }