SMBSettingsRootView.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. import SwiftUI
  2. import Swinject
  3. extension SMBSettings {
  4. struct RootView: BaseView {
  5. let resolver: Resolver
  6. @State var state = StateModel()
  7. @State private var shouldDisplayHint: Bool = false
  8. @State var hintDetent = PresentationDetent.large
  9. @State var selectedVerboseHint: AnyView?
  10. @State var hintLabel: String?
  11. @State private var decimalPlaceholder: Decimal = 0.0
  12. @State private var booleanPlaceholder: Bool = false
  13. @Environment(\.colorScheme) var colorScheme
  14. @EnvironmentObject var appIcons: Icons
  15. private var color: LinearGradient {
  16. colorScheme == .dark ? LinearGradient(
  17. gradient: Gradient(colors: [
  18. Color.bgDarkBlue,
  19. Color.bgDarkerDarkBlue
  20. ]),
  21. startPoint: .top,
  22. endPoint: .bottom
  23. )
  24. :
  25. LinearGradient(
  26. gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
  27. startPoint: .top,
  28. endPoint: .bottom
  29. )
  30. }
  31. var body: some View {
  32. List {
  33. SettingInputSection(
  34. decimalValue: $decimalPlaceholder,
  35. booleanValue: $state.enableSMBAlways,
  36. shouldDisplayHint: $shouldDisplayHint,
  37. selectedVerboseHint: Binding(
  38. get: { selectedVerboseHint },
  39. set: {
  40. selectedVerboseHint = $0.map { AnyView($0) }
  41. hintLabel = NSLocalizedString("Enable SMB Always", comment: "Enable SMB Always")
  42. }
  43. ),
  44. units: state.units,
  45. type: .boolean,
  46. label: NSLocalizedString("Enable SMB Always", comment: "Enable SMB Always"),
  47. miniHint: """
  48. Allow SMBs at all times except when a high Temp Target is set
  49. Default: OFF
  50. """,
  51. verboseHint: VStack {
  52. Text("Default: OFF").bold()
  53. Text("""
  54. When enabled, Super Micro Boluses (SMBs) will always be allowed if dosing calculations determine insulin is needed via the SMB delivery method, except in instances where a high Temp Target is set.
  55. """)
  56. },
  57. headerText: "Super-Micro-Bolus"
  58. )
  59. if !state.enableSMBAlways {
  60. SettingInputSection(
  61. decimalValue: $decimalPlaceholder,
  62. booleanValue: $state.enableSMBWithCOB,
  63. shouldDisplayHint: $shouldDisplayHint,
  64. selectedVerboseHint: Binding(
  65. get: { selectedVerboseHint },
  66. set: {
  67. selectedVerboseHint = $0.map { AnyView($0) }
  68. hintLabel = NSLocalizedString("Enable SMB With COB", comment: "Enable SMB With COB")
  69. }
  70. ),
  71. units: state.units,
  72. type: .boolean,
  73. label: NSLocalizedString("Enable SMB With COB", comment: "Enable SMB With COB"),
  74. miniHint: """
  75. Allow SMB when carbs are on board
  76. Default: OFF
  77. """,
  78. verboseHint: VStack {
  79. Text("Default: OFF").bold()
  80. Text("""
  81. When the carb on board (COB) forecast line is active, enabling this feature allows Trio to use Super Micro Boluses (SMB) to deliver the insulin required.
  82. """)
  83. Text(
  84. "If this is enabled and the criteria is met, SMBs could be utilized regardless of other SMB settings being enabled or not."
  85. )
  86. .italic()
  87. }
  88. )
  89. SettingInputSection(
  90. decimalValue: $decimalPlaceholder,
  91. booleanValue: $state.enableSMBWithTemptarget,
  92. shouldDisplayHint: $shouldDisplayHint,
  93. selectedVerboseHint: Binding(
  94. get: { selectedVerboseHint },
  95. set: {
  96. selectedVerboseHint = $0.map { AnyView($0) }
  97. hintLabel = NSLocalizedString("Enable SMB With Temptarget", comment: "Enable SMB With Temptarget")
  98. }
  99. ),
  100. units: state.units,
  101. type: .boolean,
  102. label: NSLocalizedString("Enable SMB With Temptarget", comment: "Enable SMB With Temptarget"),
  103. miniHint: """
  104. Allow SMB when a manual Temporary Target is set under 100 mg/dL (5.5 mmol/L)
  105. Default: OFF
  106. """,
  107. verboseHint: VStack {
  108. Text("Default: OFF").bold()
  109. Text("""
  110. Enabling this feature allows Trio to deliver insulin required using Super Micro Boluses (SMB) at times when a manual Temporary Target under 100 mg/dL (5.5 mmol/L) is set.
  111. """)
  112. Text(
  113. "If this is enabled and the criteria is met, SMBs could be utilized regardless of other SMB settings being enabled or not."
  114. )
  115. .italic()
  116. }
  117. )
  118. SettingInputSection(
  119. decimalValue: $decimalPlaceholder,
  120. booleanValue: $state.enableSMBAfterCarbs,
  121. shouldDisplayHint: $shouldDisplayHint,
  122. selectedVerboseHint: Binding(
  123. get: { selectedVerboseHint },
  124. set: {
  125. selectedVerboseHint = $0.map { AnyView($0) }
  126. hintLabel = NSLocalizedString("Enable SMB After Carbs", comment: "Enable SMB After Carbs")
  127. }
  128. ),
  129. units: state.units,
  130. type: .boolean,
  131. label: NSLocalizedString("Enable SMB After Carbs", comment: "Enable SMB After Carbs"),
  132. miniHint: """
  133. Allow SMB for 6 hrs after carbs are logged
  134. Default: OFF
  135. """,
  136. verboseHint: VStack {
  137. Text("Default: OFF").bold()
  138. Text("""
  139. Enabling this feature allows Trio to deliver insulin required using Super Micro Boluses (SMB) for 6 hours after a carb entry, regardless of whether there are active carbs on board (COB).
  140. """)
  141. Text(
  142. "If this is enabled and the criteria is met, SMBs could be utilized regardless of other SMB settings being enabled or not."
  143. )
  144. .italic()
  145. }
  146. )
  147. SettingInputSection(
  148. decimalValue: $state.enableSMB_high_bg_target,
  149. booleanValue: $state.enableSMB_high_bg,
  150. shouldDisplayHint: $shouldDisplayHint,
  151. selectedVerboseHint: Binding(
  152. get: { selectedVerboseHint },
  153. set: {
  154. selectedVerboseHint = $0.map { AnyView($0) }
  155. hintLabel = NSLocalizedString("Enable SMB With High BG", comment: "Enable SMB With High BG")
  156. }
  157. ),
  158. units: state.units,
  159. type: .conditionalDecimal("enableSMB_high_bg_target"),
  160. label: NSLocalizedString("Enable SMB With High BG", comment: "Enable SMB With High BG"),
  161. conditionalLabel: "High BG Target",
  162. miniHint: """
  163. Allow SMB when glucose is above the High BG Target value
  164. Default: OFF
  165. """,
  166. verboseHint: VStack {
  167. Text("Default: OFF").bold()
  168. Text("""
  169. Enabling this feature allows Trio to deliver insulin required using Super Micro Boluses (SMB) when glucose reading is above the value set as High BG Target.
  170. """)
  171. Text(
  172. "If this is enabled and the criteria is met, SMBs could be utilized regardless of other SMB settings being enabled or not."
  173. )
  174. .italic()
  175. }
  176. )
  177. }
  178. SettingInputSection(
  179. decimalValue: $decimalPlaceholder,
  180. booleanValue: $state.allowSMBWithHighTemptarget,
  181. shouldDisplayHint: $shouldDisplayHint,
  182. selectedVerboseHint: Binding(
  183. get: { selectedVerboseHint },
  184. set: {
  185. selectedVerboseHint = $0.map { AnyView($0) }
  186. hintLabel = NSLocalizedString(
  187. "Allow SMB With High Temptarget",
  188. comment: "Allow SMB With High Temptarget"
  189. )
  190. }
  191. ),
  192. units: state.units,
  193. type: .boolean,
  194. label: NSLocalizedString(
  195. "Allow SMB With High Temptarget",
  196. comment: "Allow SMB With High Temptarget"
  197. ),
  198. miniHint: """
  199. Allow SMB when a manual Temporary Target is set greater than 100 mg/dL (5.5 mmol/L)
  200. Default: OFF
  201. """,
  202. verboseHint: VStack {
  203. Text("Default: OFF").bold()
  204. Text("""
  205. Enabling this feature allows Trio to deliver insulin required using Super Micro Boluses (SMB) when a manual Temporary Target above 100 mg/dL (5.5 mmol/L) is set.
  206. """)
  207. Text("""
  208. If this is enabled and the criteria is met, SMBs could be utilized regardless of other SMB settings being enabled or not.
  209. High Temp Targets are often set when recovering from lows. If you use High Temp Targets for that purpose, this feature should remain disabled.
  210. """).italic()
  211. }
  212. )
  213. SettingInputSection(
  214. decimalValue: $decimalPlaceholder,
  215. booleanValue: $state.enableUAM,
  216. shouldDisplayHint: $shouldDisplayHint,
  217. selectedVerboseHint: Binding(
  218. get: { selectedVerboseHint },
  219. set: {
  220. selectedVerboseHint = $0.map { AnyView($0) }
  221. hintLabel = NSLocalizedString("Enable UAM", comment: "Enable UAM")
  222. }
  223. ),
  224. units: state.units,
  225. type: .boolean,
  226. label: NSLocalizedString("Enable UAM", comment: "Enable UAM"),
  227. miniHint: """
  228. Automatically adjust insulin delivery when carbs are not announced or miscalculated
  229. Default: OFF
  230. """,
  231. verboseHint: VStack {
  232. Text("Default: OFF").bold()
  233. Text("""
  234. Enabling the UAM (Unannounced Meals) feature allows the system to detect and respond to unexpected rises in blood glucose caused by unannounced or miscalculated carbs, meals high in fat or protein, or other factors like adrenaline.
  235. It uses the SMB (Super Micro Bolus) algorithm to deliver insulin in small amounts to correct glucose spikes. UAM also works in reverse, reducing or stopping SMBs if glucose levels drop unexpectedly.
  236. This feature ensures more accurate insulin adjustments even when carb entries are missing or incorrect.
  237. """)
  238. }
  239. )
  240. SettingInputSection(
  241. decimalValue: $state.maxSMBBasalMinutes,
  242. booleanValue: $booleanPlaceholder,
  243. shouldDisplayHint: $shouldDisplayHint,
  244. selectedVerboseHint: Binding(
  245. get: { selectedVerboseHint },
  246. set: {
  247. selectedVerboseHint = $0.map { AnyView($0) }
  248. hintLabel = NSLocalizedString("Max SMB Basal Minutes", comment: "Max SMB Basal Minutes")
  249. }
  250. ),
  251. units: state.units,
  252. type: .decimal("maxSMBBasalMinutes"),
  253. label: NSLocalizedString("Max SMB Basal Minutes", comment: "Max SMB Basal Minutes"),
  254. miniHint: """
  255. Limits the size of a single Super Micro Bolus (SMB) dose
  256. Default: 30 minutes
  257. """,
  258. verboseHint: VStack {
  259. Text("""
  260. Default: 30 minutes
  261. (50% current basal rate)
  262. """).bold()
  263. Text("""
  264. This is a limit on the size of a single SMB. One SMB can only be as large as this many minutes of your current profile basal rate.
  265. To calculate the maximum SMB allowed based on this setting, use the following formula, where 𝒳 = Max SMB Basal Minutes:
  266. """)
  267. Text("(𝒳 ÷ 60) × current basal rate").italic()
  268. Text("""
  269. A Max SMB Basal Minutes setting of 30 minutes means SMBs are limited to 50% of your current basal rate:
  270. """)
  271. Text("30min ÷ 60min = 0.5 = 50%").italic()
  272. Text("""
  273. Increasing this value above 90 minutes may impact Trio's ability to effectively zero temp and prevent lows.
  274. """)
  275. Text("SMBs must be enabled to use this limit").italic()
  276. }
  277. )
  278. SettingInputSection(
  279. decimalValue: $state.maxUAMSMBBasalMinutes,
  280. booleanValue: $booleanPlaceholder,
  281. shouldDisplayHint: $shouldDisplayHint,
  282. selectedVerboseHint: Binding(
  283. get: { selectedVerboseHint },
  284. set: {
  285. selectedVerboseHint = $0.map { AnyView($0) }
  286. hintLabel = NSLocalizedString("Max UAM Basal Minutes", comment: "Max UAM Basal Minutes")
  287. }
  288. ),
  289. units: state.units,
  290. type: .decimal("maxUAMSMBBasalMinutes"),
  291. label: NSLocalizedString("Max UAM Basal Minutes", comment: "Max UAM Basal Minutes"),
  292. miniHint: """
  293. Limits the size of a single Unannounced Meal (UAM) SMB dose
  294. Default: 30 minutes
  295. """,
  296. verboseHint: VStack {
  297. Text("""
  298. Default: 30 minutes
  299. (50% current basal rate)
  300. """).bold()
  301. Text("""
  302. This is a limit on the size of a single UAM SMB. One UAM SMB can only be as large as this many minutes of your current profile basal rate.
  303. To calculate the maximum UAM SMB allowed based on this setting, use the following formula, where 𝒳 = Max UAM SMB Basal Minutes:
  304. """)
  305. Text("(𝒳 ÷ 60) × current basal rate").italic()
  306. Text("""
  307. A Max UAM SMB Basal Minutes setting of 30 minutes means SMBs are limited to 50% of your current basal rate:
  308. """)
  309. Text("30min ÷ 60min = 0.5 = 50%").italic()
  310. Text("""
  311. Increasing this value above 90 may impact Trio's ability to effectively zero temp and prevent lows.
  312. """)
  313. Text("UAM SMBs must be enabled to use this limit").italic()
  314. }
  315. )
  316. SettingInputSection(
  317. decimalValue: $state.maxDeltaBGthreshold,
  318. booleanValue: $booleanPlaceholder,
  319. shouldDisplayHint: $shouldDisplayHint,
  320. selectedVerboseHint: Binding(
  321. get: { selectedVerboseHint },
  322. set: {
  323. selectedVerboseHint = $0.map { AnyView($0) }
  324. hintLabel = NSLocalizedString("Max Delta-BG Threshold SMB", comment: "Max Delta-BG Threshold")
  325. }
  326. ),
  327. units: state.units,
  328. type: .decimal("maxDeltaBGthreshold"),
  329. label: NSLocalizedString("Max Delta-BG Threshold SMB", comment: "Max Delta-BG Threshold"),
  330. miniHint: """
  331. When the difference between the last two glucose values is larger than this, it will disable SMBs
  332. Default: 20%
  333. """,
  334. verboseHint: VStack {
  335. Text("Default: 20% increase").bold()
  336. Text("""
  337. Maximum allowed positive percentual change in glucose level to permit SMBs. If the difference in glucose is greater than this, Trio will disable SMBs.
  338. """)
  339. Text("This setting has a hard-coded cap of 40%").italic()
  340. }
  341. )
  342. SettingInputSection(
  343. decimalValue: $state.smbDeliveryRatio,
  344. booleanValue: $booleanPlaceholder,
  345. shouldDisplayHint: $shouldDisplayHint,
  346. selectedVerboseHint: Binding(
  347. get: { selectedVerboseHint },
  348. set: {
  349. selectedVerboseHint = $0.map { AnyView($0) }
  350. hintLabel = NSLocalizedString("SMB DeliveryRatio", comment: "SMB DeliveryRatio")
  351. }
  352. ),
  353. units: state.units,
  354. type: .decimal("smbDeliveryRatio"),
  355. label: NSLocalizedString("SMB DeliveryRatio", comment: "SMB DeliveryRatio"),
  356. miniHint: """
  357. Safety limit on what percentage of total calculated insulin required can be administered as an SMB
  358. Default: 50%
  359. """,
  360. verboseHint: VStack {
  361. Text("Default: 50%").bold()
  362. Text("""
  363. Once the total insulin required is calculated, this safety limit specifies what share of the total insulin required can be delivered as an SMB.
  364. Due to SMBs occurring every 5 minutes, it is important to set this value to a reasonable level that allows Trio to safely zero temp should dosing needs suddenly change. Increase this value with caution.
  365. """)
  366. Text("Limited to a range of 30 - 70%").italic()
  367. }
  368. )
  369. SettingInputSection(
  370. decimalValue: $state.smbInterval,
  371. booleanValue: $booleanPlaceholder,
  372. shouldDisplayHint: $shouldDisplayHint,
  373. selectedVerboseHint: Binding(
  374. get: { selectedVerboseHint },
  375. set: {
  376. selectedVerboseHint = $0.map { AnyView($0) }
  377. hintLabel = NSLocalizedString("SMB Interval", comment: "SMB Interval")
  378. }
  379. ),
  380. units: state.units,
  381. type: .decimal("smbInterval"),
  382. label: NSLocalizedString("SMB Interval", comment: "SMB Interval"),
  383. miniHint: """
  384. Minimum minutes since the last SMB or manual bolus to allow an automated SMB
  385. Default: 3 min
  386. """,
  387. verboseHint: VStack {
  388. Text("Default: 3 min").bold()
  389. Text("""
  390. This is the minimum number of minutes since the last SMB or manual bolus before Trio will permit an automated SMB.
  391. For Omnipod Dash, this value can be as low as 3 min. For Omnipod Eros, the value can be as low as 5 min.
  392. """)
  393. }
  394. )
  395. }
  396. .sheet(isPresented: $shouldDisplayHint) {
  397. SettingInputHintView(
  398. hintDetent: $hintDetent,
  399. shouldDisplayHint: $shouldDisplayHint,
  400. hintLabel: hintLabel ?? "",
  401. hintText: selectedVerboseHint ?? AnyView(EmptyView()),
  402. sheetTitle: "Help"
  403. )
  404. }
  405. .scrollContentBackground(.hidden).background(color)
  406. .onAppear(perform: configureView)
  407. .navigationTitle("SMB Settings")
  408. .navigationBarTitleDisplayMode(.automatic)
  409. .onDisappear {
  410. state.saveIfChanged()
  411. }
  412. }
  413. }
  414. }