SettingItems.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. import Foundation
  2. import LoopKitUI
  3. import SwiftUI
  4. struct SettingItem: Identifiable {
  5. let id = UUID()
  6. let title: String
  7. let view: Screen
  8. let searchContents: [String]?
  9. let path: [String]?
  10. init(
  11. title: String,
  12. view: Screen,
  13. searchContents: [String]? = nil,
  14. path: [String]? = nil
  15. ) {
  16. self.title = title
  17. self.view = view
  18. self.searchContents = searchContents
  19. self.path = path
  20. }
  21. }
  22. struct FilteredSettingItem: Identifiable {
  23. let id = UUID()
  24. let settingItem: SettingItem
  25. let matchedContent: String
  26. }
  27. enum SettingItems {
  28. static let trioConfig = [
  29. SettingItem(title: "Devices", view: .devices),
  30. SettingItem(title: "Therapy", view: .therapySettings),
  31. SettingItem(title: "Algorithm", view: .algorithmSettings),
  32. SettingItem(title: "Features", view: .featureSettings),
  33. SettingItem(title: "Notifications", view: .notificationSettings),
  34. SettingItem(title: "Services", view: .serviceSettings)
  35. ]
  36. static let devicesItems = [
  37. SettingItem(title: "Insulin Pump", view: .pumpConfig, path: ["Devices"]),
  38. SettingItem(
  39. title: "CGM",
  40. view: .cgm,
  41. searchContents: ["Smooth Glucose Value"],
  42. path: ["Devices", "Continuous Glucose Monitor"]
  43. ),
  44. SettingItem(title: "Smart Watch", view: .watch, path: ["Devices"]),
  45. SettingItem(
  46. title: "Apple Watch",
  47. view: .watch,
  48. searchContents: ["Display on Watch", "Show Protein and Fat", "Confirm Bolus Faster"],
  49. path: ["Devices", "Smart Watch", "Apple Watch"]
  50. ),
  51. SettingItem(
  52. title: "Contact Image",
  53. view: .watch,
  54. searchContents: ["Display on Watch", "Watch Complication"],
  55. path: ["Devices", "Smart Watch", "Apple Watch", "Contact Image"]
  56. )
  57. ]
  58. static let therapyItems = [
  59. SettingItem(
  60. title: "Units and Limits",
  61. view: .unitsAndLimits,
  62. searchContents: [
  63. "Glucose Units",
  64. "Max Basal",
  65. "Max Bolus",
  66. "Max IOB",
  67. "Max COB",
  68. "Minimum Safety Threshold",
  69. "Delivery Limits"
  70. ],
  71. path: ["Therapy Settings", "Units and Limits"]
  72. ),
  73. SettingItem(title: "Basal Rates", view: .basalProfileEditor, path: ["Therapy Settings"]),
  74. SettingItem(title: "Insulin Sensitivities", view: .isfEditor, path: ["Therapy Settings"]),
  75. SettingItem(title: "ISF", view: .isfEditor, path: ["Therapy Settings"]),
  76. SettingItem(title: "Carb Ratios", view: .crEditor, path: ["Therapy Settings"]),
  77. SettingItem(title: "CR", view: .crEditor, path: ["Therapy Settings"]),
  78. SettingItem(title: "Glucose Targets", view: .targetsEditor, path: ["Therapy Settings"])
  79. ]
  80. static let algorithmItems = [
  81. SettingItem(
  82. title: "Autosens",
  83. view: .autosensSettings,
  84. searchContents: ["Autosens Max", "Autosens Min", "Rewind Resets Autosens"],
  85. path: ["Algorithm", "Autosens"]
  86. ),
  87. SettingItem(
  88. title: "Super Micro Bolus (SMB)",
  89. view: .smbSettings,
  90. searchContents: [
  91. "Enable SMB Always",
  92. "Enable SMB With COB",
  93. "Enable SMB With Temporary Target",
  94. "Enable SMB After Carbs",
  95. "Enable SMB With High BG",
  96. "High BG Target",
  97. "Allow SMB With High Temporary Target",
  98. "Enable UAM",
  99. "Max SMB Basal Minutes",
  100. "Max UAM SMB Basal Minutes",
  101. "Max Delta-BG Threshold SMB"
  102. ],
  103. path: ["Algorithm", "Super Micro Bolus (SMB)"]
  104. ),
  105. SettingItem(
  106. title: "Dynamic Settings",
  107. view: .dynamicISF,
  108. searchContents: [
  109. "Activate Dynamic Sensitivity (ISF)",
  110. "Activate Dynamic Carb Ratio (CR)",
  111. "Use Sigmoid Formula",
  112. "Adjustment Factor",
  113. "AF",
  114. "Sigmoid Adjustment Factor",
  115. "Weighted Average of TDD",
  116. "Adjust Basal"
  117. ],
  118. path: ["Algorithm", "Dynamic Sensitivity"]
  119. ),
  120. SettingItem(
  121. title: "Target Behavior",
  122. view: .targetBehavior,
  123. searchContents: [
  124. "High Temptarget Raises Sensitivity",
  125. "Low Temptarget Lowers Sensitivity",
  126. "Sensitivity Raises Target",
  127. "Resistance Lowers Target",
  128. "Half Basal Exercise Target"
  129. ],
  130. path: ["Algorithm", "Target Behavior"]
  131. ),
  132. SettingItem(
  133. title: "Additionals",
  134. view: .algorithmAdvancedSettings,
  135. searchContents: [
  136. "Max Daily Safety Multiplier",
  137. "Current Basal Safety Multiplier",
  138. "Use Custom Peak Time",
  139. "Duration of Insulin Action", "DIA",
  140. "Insulin Peak Time",
  141. "Skip Neutral Temps",
  142. "Unsuspend If No Temp",
  143. "Suspend Zeros IOB",
  144. "SMB Delivery Ratio",
  145. "SMB Interval",
  146. "Min 5m Carbimpact",
  147. "Remaining Carbs Fraction",
  148. "Remaining Carbs Cap",
  149. "Noisy CGM Target Multiplier"
  150. ],
  151. path: ["Algorithm", "Additionals"]
  152. )
  153. ]
  154. static let trioFeaturesItems = [
  155. SettingItem(
  156. title: "Bolus Calculator",
  157. view: .bolusCalculatorConfig,
  158. searchContents: [
  159. "Display Meal Presets",
  160. "Recommended Bolus Percentage",
  161. "Enable Fatty Meal Factor",
  162. "Fatty Meal Factor",
  163. "Enable Super Bolus",
  164. "Super Bolus Factor",
  165. "Very Low Glucose Warning"
  166. ],
  167. path: ["Features", "Bolus Calculator"]
  168. ),
  169. SettingItem(
  170. title: "Meal Settings",
  171. view: .mealSettings,
  172. searchContents: [
  173. "Max Carbs",
  174. "Max Meal Absorption Time",
  175. "Max Fat",
  176. "Max Protein",
  177. "Display and Allow Fat and Protein Entries",
  178. "Fat and Protein Delay",
  179. "Maximum Duration (hours)",
  180. "Spread Interval (minutes)",
  181. "Fat and Protein Factor",
  182. "FPU"
  183. ],
  184. path: ["Features", "Meal Settings"]
  185. ),
  186. SettingItem(
  187. title: "Shortcuts",
  188. view: .shortcutsConfig,
  189. searchContents: ["Allow Bolusing with Shortcuts"],
  190. path: ["Features", "Shortcuts"]
  191. ),
  192. SettingItem(
  193. title: "Remote Control",
  194. view: .remoteControlConfig,
  195. searchContents: ["Remote Control"],
  196. path: ["Features", "Remote Control"]
  197. ),
  198. SettingItem(
  199. title: "User Interface",
  200. view: .userInterfaceSettings,
  201. searchContents: [
  202. "Show X-Axis Grid Lines",
  203. "Show Y-Axis Grid Lines",
  204. "Show Low and High Thresholds",
  205. "Low Threshold",
  206. "High Threshold",
  207. "X-Axis Interval Step",
  208. "eA1c/GMI Display Unit",
  209. "Show Carbs Required Badge",
  210. "Carbs Required Threshold",
  211. "Forecast Display Type",
  212. "Cone",
  213. "Lines",
  214. "Dark Mode",
  215. "Light Mode",
  216. "Appearance",
  217. "Dark Scheme",
  218. "Light Scheme",
  219. "Glucose Color Scheme",
  220. "Time in Range Type",
  221. "Time in Tight Range (TITR)",
  222. "Time in Normoglycemia (TING)"
  223. ],
  224. path: ["Features", "User Interface"]
  225. ),
  226. SettingItem(title: "App Icons", view: .iconConfig)
  227. ]
  228. static let notificationItems = [
  229. SettingItem(title: "Manage iOS Preferences", view: .notificationSettings),
  230. SettingItem(
  231. title: "Trio Notifications",
  232. view: .glucoseNotificationSettings,
  233. searchContents: [
  234. "Always Notify Pump",
  235. "Always Notify CGM",
  236. "Always Notify Carb",
  237. "Always Notify Algorithm",
  238. "Show Glucose App Badge",
  239. "Glucose Notifications",
  240. "Add Glucose Source to Alarm",
  241. "Low Glucose Alarm Limit",
  242. "High Glucose Alarm Limit"
  243. ],
  244. path: ["Notifications", "Trio Notifications"] // Glucose
  245. ),
  246. SettingItem(
  247. title: "Live Activity",
  248. view: .liveActivitySettings,
  249. searchContents: [
  250. "Enable Live Activity",
  251. "Lock Screen Widget Style"
  252. ],
  253. path: ["Notifications", "Live Activity"]
  254. ),
  255. SettingItem(
  256. title: "Calendar Events",
  257. view: .calendarEventSettings,
  258. searchContents: [
  259. "Create Calendar Events",
  260. "Choose Calendar",
  261. "Display Emojis as Labels",
  262. "Display IOB and COB"
  263. ],
  264. path: ["Notifications", "Calendar Events"]
  265. )
  266. ]
  267. static let serviceItems = [
  268. SettingItem(
  269. title: "Nightscout",
  270. view: .nighscoutConfig,
  271. searchContents: [
  272. "Import Settings",
  273. "Backfill Glucose"
  274. ],
  275. path: ["Services", "Nightscout"]
  276. ),
  277. SettingItem(
  278. title: "Nightscout Upload",
  279. view: .nighscoutConfig,
  280. searchContents: [
  281. "Allow Uploading to Nightscout",
  282. "Upload Glucose"
  283. ],
  284. path: ["Services", "Nightscout", "Upload"]
  285. ),
  286. SettingItem(
  287. title: "Nightscout Fetch & Remote Control",
  288. view: .nighscoutConfig,
  289. searchContents: [
  290. "Allow Fetching From Nightscout"
  291. ],
  292. path: ["Services", "Nightscout", "Fetch and Remote Control"]
  293. ),
  294. SettingItem(title: "Tidepool", view: .serviceSettings, path: ["Services"]),
  295. SettingItem(title: "Apple Health", view: .healthkit, path: ["Services"])
  296. ]
  297. static var allItems: [SettingItem] {
  298. trioConfig + devicesItems + therapyItems + algorithmItems + trioFeaturesItems + notificationItems + serviceItems
  299. }
  300. static func filteredItems(searchText: String) -> [FilteredSettingItem] {
  301. allItems.flatMap { item in
  302. var results = [FilteredSettingItem]()
  303. let searchLower = searchText.lowercased()
  304. let titleLocalized = item.title.localized
  305. let titleEnglish = item.title.englishLocalized
  306. if titleLocalized.localizedCaseInsensitiveContains(searchLower) ||
  307. titleEnglish.localizedCaseInsensitiveContains(searchLower)
  308. {
  309. results.append(FilteredSettingItem(settingItem: item, matchedContent: item.title))
  310. }
  311. if let contents = item.searchContents {
  312. let matched = contents.filter {
  313. $0.localized.localizedCaseInsensitiveContains(searchLower) ||
  314. $0.englishLocalized.localizedCaseInsensitiveContains(searchLower)
  315. }
  316. results.append(contentsOf: matched.map { FilteredSettingItem(settingItem: item, matchedContent: $0) })
  317. }
  318. return results
  319. }
  320. }
  321. }
  322. extension String {
  323. func localizedString(locale: Locale = .current) -> String {
  324. if locale.identifier == "en",
  325. let path = Bundle.main.path(forResource: "en", ofType: "lproj"),
  326. let bundle = Bundle(path: path)
  327. {
  328. return NSLocalizedString(self, bundle: bundle, comment: "")
  329. }
  330. return NSLocalizedString(self, comment: "")
  331. }
  332. var localized: String { localizedString() }
  333. var englishLocalized: String { localizedString(locale: Locale(identifier: "en")) }
  334. }