AlarmViewController.swift 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. //
  2. // AlarmViewController.swift
  3. // LoopFollow
  4. //
  5. // Created by Jon Fawcett on 6/3/20.
  6. // Copyright © 2020 Jon Fawcett. All rights reserved.
  7. //
  8. import UIKit
  9. import Eureka
  10. class AlarmViewController: FormViewController {
  11. var soundFiles: [String] = [
  12. "Alarm_Buzzer",
  13. "Alarm_Clock",
  14. "Alert_Tone_Busy",
  15. "Alert_Tone_Ringtone_1",
  16. "Alert_Tone_Ringtone_2",
  17. "Alien_Siren",
  18. "Ambulance",
  19. "Analog_Watch_Alarm",
  20. "Big_Clock_Ticking",
  21. "Burglar_Alarm_Siren_1",
  22. "Burglar_Alarm_Siren_2",
  23. "Cartoon_Ascend_Climb_Sneaky",
  24. "Cartoon_Ascend_Then_Descend",
  25. "Cartoon_Bounce_To_Ceiling",
  26. "Cartoon_Dreamy_Glissando_Harp",
  27. "Cartoon_Fail_Strings_Trumpet",
  28. "Cartoon_Machine_Clumsy_Loop",
  29. "Cartoon_Siren",
  30. "Cartoon_Tip_Toe_Sneaky_Walk",
  31. "Cartoon_Uh_Oh",
  32. "Cartoon_Villain_Horns",
  33. "Cell_Phone_Ring_Tone",
  34. "Chimes_Glassy",
  35. "Computer_Magic",
  36. "CSFX-2_Alarm",
  37. "Cuckoo_Clock",
  38. "Dhol_Shuffleloop",
  39. "Discreet",
  40. "Early_Sunrise",
  41. "Emergency_Alarm_Carbon_Monoxide",
  42. "Emergency_Alarm_Siren",
  43. "Emergency_Alarm",
  44. "Ending_Reached",
  45. "Fly",
  46. "Ghost_Hover",
  47. "Good_Morning",
  48. "Hell_Yeah_Somewhat_Calmer",
  49. "In_A_Hurry",
  50. "Indeed",
  51. "Insistently",
  52. "Jingle_All_The_Way",
  53. "Laser_Shoot",
  54. "Machine_Charge",
  55. "Magical_Twinkle",
  56. "Marching_Heavy_Footed_Fat_Elephants",
  57. "Marimba_Descend",
  58. "Marimba_Flutter_or_Shake",
  59. "Martian_Gun",
  60. "Martian_Scanner",
  61. "Metallic",
  62. "Nightguard",
  63. "Not_Kiddin",
  64. "Open_Your_Eyes_And_See",
  65. "Orchestral_Horns",
  66. "Oringz",
  67. "Pager_Beeps",
  68. "Remembers_Me_Of_Asia",
  69. "Rise_And_Shine",
  70. "Rush",
  71. "Sci-Fi_Air_Raid_Alarm",
  72. "Sci-Fi_Alarm_Loop_1",
  73. "Sci-Fi_Alarm_Loop_2",
  74. "Sci-Fi_Alarm_Loop_3",
  75. "Sci-Fi_Alarm_Loop_4",
  76. "Sci-Fi_Alarm",
  77. "Sci-Fi_Computer_Console_Alarm",
  78. "Sci-Fi_Console_Alarm",
  79. "Sci-Fi_Eerie_Alarm",
  80. "Sci-Fi_Engine_Shut_Down",
  81. "Sci-Fi_Incoming_Message_Alert",
  82. "Sci-Fi_Spaceship_Message",
  83. "Sci-Fi_Spaceship_Warm_Up",
  84. "Sci-Fi_Warning",
  85. "Signature_Corporate",
  86. "Siri_Alert_Calibration_Needed",
  87. "Siri_Alert_Device_Muted",
  88. "Siri_Alert_Glucose_Dropping_Fast",
  89. "Siri_Alert_Glucose_Rising_Fast",
  90. "Siri_Alert_High_Glucose",
  91. "Siri_Alert_Low_Glucose",
  92. "Siri_Alert_Missed_Readings",
  93. "Siri_Alert_Transmitter_Battery_Low",
  94. "Siri_Alert_Urgent_High_Glucose",
  95. "Siri_Alert_Urgent_Low_Glucose",
  96. "Siri_Calibration_Needed",
  97. "Siri_Device_Muted",
  98. "Siri_Glucose_Dropping_Fast",
  99. "Siri_Glucose_Rising_Fast",
  100. "Siri_High_Glucose",
  101. "Siri_Low_Glucose",
  102. "Siri_Missed_Readings",
  103. "Siri_Transmitter_Battery_Low",
  104. "Siri_Urgent_High_Glucose",
  105. "Siri_Urgent_Low_Glucose",
  106. "Soft_Marimba_Pad_Positive",
  107. "Soft_Warm_Airy_Optimistic",
  108. "Soft_Warm_Airy_Reassuring",
  109. "Store_Door_Chime",
  110. "Sunny",
  111. "Thunder_Sound_FX",
  112. "Time_Has_Come",
  113. "Tornado_Siren",
  114. "Two_Turtle_Doves",
  115. "Unpaved",
  116. "Wake_Up_Will_You",
  117. "Win_Gain",
  118. "Wrong_Answer"
  119. ]
  120. func reloadSnoozeTime(key: String, setNil: Bool, value: Date = Date()) {
  121. if let row = form.rowBy(tag: key) as? DateTimeInlineRow {
  122. if setNil {
  123. row.value = nil
  124. } else {
  125. row.value = value
  126. }
  127. row.reload()
  128. }
  129. }
  130. func reloadIsSnoozed(key: String, value: Bool) {
  131. if let row = form.rowBy(tag: key) as? SwitchRow {
  132. row.value = value
  133. row.reload()
  134. }
  135. }
  136. // static let shared = AlarmViewController()
  137. @IBAction func unwindToAlarms(sender: UIStoryboardSegue)
  138. {
  139. }
  140. override func viewDidLoad() {
  141. super.viewDidLoad()
  142. if UserDefaultsRepository.forceDarkMode.value {
  143. overrideUserInterfaceStyle = .dark
  144. }
  145. buildSnoozeAll()
  146. buildTemporaryAlert()
  147. buildUrgentLow()
  148. buildLow()
  149. buildHigh()
  150. buildUrgentHigh()
  151. buildFastDropAlert()
  152. buildFastRiseAlert()
  153. buildMissedReadings()
  154. // buildNotLooping()
  155. // buildMissedBolus()
  156. // buildAppInactive()
  157. buildSage()
  158. buildCage()
  159. }
  160. func buildSnoozeAll(){
  161. form
  162. +++ Section(header: "Snooze All", footer: "Snooze All Alerts")
  163. <<< DateTimeInlineRow("alertSnoozeAllTime") { row in
  164. row.title = "Snooze All Until"
  165. if (UserDefaultsRepository.alertSnoozeAllTime.value != nil) {
  166. row.value = UserDefaultsRepository.alertSnoozeAllTime.value
  167. }
  168. row.minuteInterval = 5
  169. row.noValueDisplayText = "Not Snoozed"
  170. }
  171. .onChange { [weak self] row in
  172. guard let value = row.value else { return }
  173. UserDefaultsRepository.alertSnoozeAllTime.value = value
  174. UserDefaultsRepository.alertSnoozeAllIsSnoozed.value = true
  175. let otherRow = self?.form.rowBy(tag: "alertSnoozeAllIsSnoozed") as! SwitchRow
  176. otherRow.value = true
  177. otherRow.reload()
  178. }
  179. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  180. inlineRow.cellUpdate() { cell, row in
  181. cell.datePicker.datePickerMode = .dateAndTime
  182. }
  183. let color = cell.detailTextLabel?.textColor
  184. row.onCollapseInlineRow { cell, _, _ in
  185. cell.detailTextLabel?.textColor = color
  186. }
  187. cell.detailTextLabel?.textColor = cell.tintColor
  188. }
  189. <<< SwitchRow("alertSnoozeAllIsSnoozed"){ row in
  190. row.title = "All Alerts Snoozed"
  191. row.value = UserDefaultsRepository.alertSnoozeAllIsSnoozed.value
  192. row.hidden = "$alertSnoozeAllTime == nil"
  193. }.onChange { [weak self] row in
  194. guard let value = row.value else { return }
  195. UserDefaultsRepository.alertSnoozeAllIsSnoozed.value = value
  196. if !value {
  197. UserDefaultsRepository.alertSnoozeAllTime.setNil(key: "alertSnoozeAllTime")
  198. let otherRow = self?.form.rowBy(tag: "alertSnoozeAllTime") as! DateTimeInlineRow
  199. otherRow.value = nil
  200. otherRow.reload()
  201. }
  202. }
  203. }
  204. func buildTemporaryAlert(){
  205. form
  206. +++ Section(header: "Temporary Alert", footer: "Temporary Alert will trigger once and disable. Disabling Alert Below BG will trigger it as a high alert above the BG.")
  207. <<< SwitchRow("alertTemporaryActive"){ row in
  208. row.title = "Active"
  209. row.value = UserDefaultsRepository.alertTemporaryActive.value
  210. }.onChange { [weak self] row in
  211. guard let value = row.value else { return }
  212. UserDefaultsRepository.alertTemporaryActive.value = value
  213. }
  214. <<< SwitchRow("alertTemporaryBelow"){ row in
  215. row.title = "Alert Below BG"
  216. row.hidden = "$alertTemporaryActive == false"
  217. row.value = UserDefaultsRepository.alertTemporaryBelow.value
  218. }.onChange { [weak self] row in
  219. guard let value = row.value else { return }
  220. UserDefaultsRepository.alertTemporaryBelow.value = value
  221. }
  222. <<< StepperRow("alertTemporaryBG") { row in
  223. row.title = "BG"
  224. row.cell.stepper.stepValue = 1
  225. row.cell.stepper.minimumValue = 40
  226. row.cell.stepper.maximumValue = 400
  227. row.value = Double(UserDefaultsRepository.alertTemporaryBG.value)
  228. row.hidden = "$alertTemporaryActive == false"
  229. row.displayValueFor = { value in
  230. guard let value = value else { return nil }
  231. return "\(Int(value))"
  232. }
  233. }.onChange { [weak self] row in
  234. guard let value = row.value else { return }
  235. UserDefaultsRepository.alertTemporaryBG.value = Int(value)
  236. }
  237. <<< PickerInputRow<String>("alertTemporarySound") { row in
  238. row.title = "Sound"
  239. row.options = soundFiles
  240. row.hidden = "$alertTemporaryActive == false"
  241. row.value = UserDefaultsRepository.alertTemporarySound.value
  242. row.displayValueFor = { value in
  243. guard let value = value else { return nil }
  244. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  245. }
  246. }.onChange { [weak self] row in
  247. guard let value = row.value else { return }
  248. UserDefaultsRepository.alertTemporarySound.value = value
  249. AlarmSound.setSoundFile(str: value)
  250. AlarmSound.stop()
  251. AlarmSound.playTest()
  252. }
  253. }
  254. func buildUrgentLow(){
  255. form
  256. +++ Section(header: "Urgent Low Alert", footer: "Alerts when BG drops below value")
  257. <<< SwitchRow("alertUrgentLowActive"){ row in
  258. row.title = "Active"
  259. row.value = UserDefaultsRepository.alertUrgentLowActive.value
  260. }.onChange { [weak self] row in
  261. guard let value = row.value else { return }
  262. UserDefaultsRepository.alertUrgentLowActive.value = value
  263. }
  264. <<< StepperRow("alertUrgentLowBG") { row in
  265. row.title = "BG"
  266. row.cell.stepper.stepValue = 1
  267. row.cell.stepper.minimumValue = 40
  268. row.cell.stepper.maximumValue = 80
  269. row.value = Double(UserDefaultsRepository.alertUrgentLowBG.value)
  270. row.hidden = "$alertUrgentLowActive == false"
  271. row.displayValueFor = { value in
  272. guard let value = value else { return nil }
  273. return "\(Int(value))"
  274. }
  275. }.onChange { [weak self] row in
  276. guard let value = row.value else { return }
  277. UserDefaultsRepository.alertUrgentLowBG.value = Int(value)
  278. }
  279. <<< StepperRow("alertUrgentLowSnooze") { row in
  280. row.title = "Default Snooze"
  281. row.cell.stepper.stepValue = 5
  282. row.cell.stepper.minimumValue = 5
  283. row.cell.stepper.maximumValue = 15
  284. row.value = Double(UserDefaultsRepository.alertUrgentLowSnooze.value)
  285. row.hidden = "$alertUrgentLowActive == false"
  286. row.displayValueFor = { value in
  287. guard let value = value else { return nil }
  288. return "\(Int(value))"
  289. }
  290. }.onChange { [weak self] row in
  291. guard let value = row.value else { return }
  292. UserDefaultsRepository.alertUrgentLowSnooze.value = Int(value)
  293. }
  294. <<< PickerInputRow<String>("alertUrgentLowSound") { row in
  295. row.title = "Sound"
  296. row.options = soundFiles
  297. row.hidden = "$alertUrgentLowActive == false"
  298. row.value = UserDefaultsRepository.alertUrgentLowSound.value
  299. row.displayValueFor = { value in
  300. guard let value = value else { return nil }
  301. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  302. }
  303. }.onChange { [weak self] row in
  304. guard let value = row.value else { return }
  305. UserDefaultsRepository.alertUrgentLowSound.value = value
  306. AlarmSound.setSoundFile(str: value)
  307. AlarmSound.stop()
  308. AlarmSound.playTest()
  309. }
  310. <<< DateTimeInlineRow("alertUrgentLowSnoozedTime") { row in
  311. row.title = "Snoozed Until"
  312. row.hidden = "$alertUrgentLowActive == false"
  313. if (UserDefaultsRepository.alertUrgentLowSnoozedTime.value != nil) {
  314. row.value = UserDefaultsRepository.alertUrgentLowSnoozedTime.value
  315. }
  316. row.minuteInterval = 5
  317. row.noValueDisplayText = "Not Snoozed"
  318. }
  319. .onChange { [weak self] row in
  320. guard let value = row.value else { return }
  321. UserDefaultsRepository.alertUrgentLowSnoozedTime.value = value
  322. UserDefaultsRepository.alertUrgentLowIsSnoozed.value = true
  323. let otherRow = self?.form.rowBy(tag: "alertUrgentLowIsSnoozed") as! SwitchRow
  324. otherRow.value = true
  325. otherRow.reload()
  326. }
  327. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  328. inlineRow.cellUpdate() { cell, row in
  329. cell.datePicker.datePickerMode = .dateAndTime
  330. }
  331. let color = cell.detailTextLabel?.textColor
  332. row.onCollapseInlineRow { cell, _, _ in
  333. cell.detailTextLabel?.textColor = color
  334. }
  335. cell.detailTextLabel?.textColor = cell.tintColor
  336. }
  337. <<< SwitchRow("alertUrgentLowIsSnoozed"){ row in
  338. row.title = "Is Snoozed"
  339. row.value = UserDefaultsRepository.alertUrgentLowIsSnoozed.value
  340. row.hidden = "$alertUrgentLowActive == false || $alertUrgentLowSnoozedTime == nil"
  341. }.onChange { [weak self] row in
  342. guard let value = row.value else { return }
  343. UserDefaultsRepository.alertUrgentLowIsSnoozed.value = value
  344. if !value {
  345. UserDefaultsRepository.alertUrgentLowSnoozedTime.setNil(key: "alertUrgentLowSnoozedTime")
  346. let otherRow = self?.form.rowBy(tag: "alertUrgentLowSnoozedTime") as! DateTimeInlineRow
  347. otherRow.value = nil
  348. otherRow.reload()
  349. }
  350. }
  351. }
  352. func buildLow(){
  353. form
  354. +++ Section(header: "Low Alert", footer: "Alerts when BG drops below value")
  355. <<< SwitchRow("alertLowActive"){ row in
  356. row.title = "Active"
  357. row.value = UserDefaultsRepository.alertLowActive.value
  358. }.onChange { [weak self] row in
  359. guard let value = row.value else { return }
  360. UserDefaultsRepository.alertLowActive.value = value
  361. }
  362. <<< StepperRow("alertLowBG") { row in
  363. row.title = "BG"
  364. row.cell.stepper.stepValue = 1
  365. row.cell.stepper.minimumValue = 40
  366. row.cell.stepper.maximumValue = 120
  367. row.value = Double(UserDefaultsRepository.alertLowBG.value)
  368. row.hidden = "$alertLowActive == false"
  369. row.displayValueFor = { value in
  370. guard let value = value else { return nil }
  371. return "\(Int(value))"
  372. }
  373. }.onChange { [weak self] row in
  374. guard let value = row.value else { return }
  375. UserDefaultsRepository.alertLowBG.value = Int(value)
  376. }
  377. <<< StepperRow("alertLowSnooze") { row in
  378. row.title = "Snooze"
  379. row.cell.stepper.stepValue = 5
  380. row.cell.stepper.minimumValue = 5
  381. row.cell.stepper.maximumValue = 30
  382. row.value = Double(UserDefaultsRepository.alertLowSnooze.value)
  383. row.hidden = "$alertLowActive == false"
  384. row.displayValueFor = { value in
  385. guard let value = value else { return nil }
  386. return "\(Int(value))"
  387. }
  388. }.onChange { [weak self] row in
  389. guard let value = row.value else { return }
  390. UserDefaultsRepository.alertLowSnooze.value = Int(value)
  391. }
  392. <<< PickerInputRow<String>("alertLowSound") { row in
  393. row.title = "Sound"
  394. row.options = soundFiles
  395. row.hidden = "$alertLowActive == false"
  396. row.value = UserDefaultsRepository.alertLowSound.value
  397. row.displayValueFor = { value in
  398. guard let value = value else { return nil }
  399. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  400. }
  401. }.onChange { [weak self] row in
  402. guard let value = row.value else { return }
  403. UserDefaultsRepository.alertLowSound.value = value
  404. AlarmSound.setSoundFile(str: value)
  405. AlarmSound.stop()
  406. AlarmSound.playTest()
  407. }
  408. <<< DateTimeInlineRow("alertLowSnoozedTime") { row in
  409. row.title = "Snoozed Until"
  410. row.hidden = "$alertLowActive == false"
  411. if (UserDefaultsRepository.alertLowSnoozedTime.value != nil) {
  412. row.value = UserDefaultsRepository.alertLowSnoozedTime.value
  413. }
  414. row.minuteInterval = 5
  415. row.noValueDisplayText = "Not Snoozed"
  416. }
  417. .onChange { [weak self] row in
  418. guard let value = row.value else { return }
  419. UserDefaultsRepository.alertLowSnoozedTime.value = value
  420. UserDefaultsRepository.alertLowIsSnoozed.value = true
  421. let otherRow = self?.form.rowBy(tag: "alertLowIsSnoozed") as! SwitchRow
  422. otherRow.value = true
  423. otherRow.reload()
  424. }
  425. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  426. inlineRow.cellUpdate() { cell, row in
  427. cell.datePicker.datePickerMode = .dateAndTime
  428. }
  429. let color = cell.detailTextLabel?.textColor
  430. row.onCollapseInlineRow { cell, _, _ in
  431. cell.detailTextLabel?.textColor = color
  432. }
  433. cell.detailTextLabel?.textColor = cell.tintColor
  434. }
  435. <<< SwitchRow("alertLowIsSnoozed"){ row in
  436. row.title = "Is Snoozed"
  437. row.value = UserDefaultsRepository.alertLowIsSnoozed.value
  438. row.hidden = "$alertLowActive == false || $alertLowSnoozedTime == nil"
  439. }.onChange { [weak self] row in
  440. guard let value = row.value else { return }
  441. UserDefaultsRepository.alertLowIsSnoozed.value = value
  442. if !value {
  443. UserDefaultsRepository.alertLowSnoozedTime.setNil(key: "alertLowSnoozedTime")
  444. let otherRow = self?.form.rowBy(tag: "alertLowSnoozedTime") as! DateTimeInlineRow
  445. otherRow.value = nil
  446. otherRow.reload()
  447. }
  448. }
  449. }
  450. func buildHigh(){
  451. form
  452. +++ Section(header: "High Alert", footer: "Alerts when BG rises above value. If Persistence is set greater than 0, it will not alert until BG has been high for that many minutes.")
  453. <<< SwitchRow("alertHighActive"){ row in
  454. row.title = "Active"
  455. row.value = UserDefaultsRepository.alertHighActive.value
  456. }.onChange { [weak self] row in
  457. guard let value = row.value else { return }
  458. UserDefaultsRepository.alertHighActive.value = value
  459. }
  460. <<< StepperRow("alertHighBG") { row in
  461. row.title = "BG"
  462. row.cell.stepper.stepValue = 1
  463. row.cell.stepper.minimumValue = 120
  464. row.cell.stepper.maximumValue = 300
  465. row.value = Double(UserDefaultsRepository.alertHighBG.value)
  466. row.hidden = "$alertHighActive == false"
  467. row.displayValueFor = { value in
  468. guard let value = value else { return nil }
  469. return "\(Int(value))"
  470. }
  471. }.onChange { [weak self] row in
  472. guard let value = row.value else { return }
  473. UserDefaultsRepository.alertHighBG.value = Int(value)
  474. }
  475. <<< StepperRow("alertHighPersistent") { row in
  476. row.title = "Persistent For"
  477. row.cell.stepper.stepValue = 1
  478. row.cell.stepper.minimumValue = 0
  479. row.cell.stepper.maximumValue = 120
  480. row.value = Double(UserDefaultsRepository.alertHighPersistent.value)
  481. row.hidden = "$alertHighActive == false"
  482. row.displayValueFor = { value in
  483. guard let value = value else { return nil }
  484. return "\(Int(value))"
  485. }
  486. }.onChange { [weak self] row in
  487. guard let value = row.value else { return }
  488. UserDefaultsRepository.alertHighPersistent.value = Int(value)
  489. }
  490. <<< StepperRow("alertHighSnooze") { row in
  491. row.title = "Snooze"
  492. row.cell.stepper.stepValue = 5
  493. row.cell.stepper.minimumValue = 10
  494. row.cell.stepper.maximumValue = 120
  495. row.value = Double(UserDefaultsRepository.alertHighSnooze.value)
  496. row.hidden = "$alertHighActive == false"
  497. row.displayValueFor = { value in
  498. guard let value = value else { return nil }
  499. return "\(Int(value))"
  500. }
  501. }.onChange { [weak self] row in
  502. guard let value = row.value else { return }
  503. UserDefaultsRepository.alertHighSnooze.value = Int(value)
  504. }
  505. <<< PickerInputRow<String>("alertHighSound") { row in
  506. row.title = "Sound"
  507. row.options = soundFiles
  508. row.hidden = "$alertHighActive == false"
  509. row.value = UserDefaultsRepository.alertHighSound.value
  510. row.displayValueFor = { value in
  511. guard let value = value else { return nil }
  512. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  513. }
  514. }.onChange { [weak self] row in
  515. guard let value = row.value else { return }
  516. UserDefaultsRepository.alertHighSound.value = value
  517. AlarmSound.setSoundFile(str: value)
  518. AlarmSound.stop()
  519. AlarmSound.playTest()
  520. }
  521. <<< DateTimeInlineRow("alertHighSnoozedTime") { row in
  522. row.title = "Snoozed Until"
  523. row.hidden = "$alertHighActive == false"
  524. if (UserDefaultsRepository.alertHighSnoozedTime.value != nil) {
  525. row.value = UserDefaultsRepository.alertHighSnoozedTime.value
  526. }
  527. row.minuteInterval = 5
  528. row.noValueDisplayText = "Not Snoozed"
  529. }
  530. .onChange { [weak self] row in
  531. guard let value = row.value else { return }
  532. UserDefaultsRepository.alertHighSnoozedTime.value = value
  533. UserDefaultsRepository.alertHighIsSnoozed.value = true
  534. let otherRow = self?.form.rowBy(tag: "alertHighIsSnoozed") as! SwitchRow
  535. otherRow.value = true
  536. otherRow.reload()
  537. }
  538. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  539. inlineRow.cellUpdate() { cell, row in
  540. cell.datePicker.datePickerMode = .dateAndTime
  541. }
  542. let color = cell.detailTextLabel?.textColor
  543. row.onCollapseInlineRow { cell, _, _ in
  544. cell.detailTextLabel?.textColor = color
  545. }
  546. cell.detailTextLabel?.textColor = cell.tintColor
  547. }
  548. <<< SwitchRow("alertHighIsSnoozed"){ row in
  549. row.title = "Is Snoozed"
  550. row.value = UserDefaultsRepository.alertHighIsSnoozed.value
  551. row.hidden = "$alertHighActive == false || $alertHighSnoozedTime == nil"
  552. }.onChange { [weak self] row in
  553. guard let value = row.value else { return }
  554. UserDefaultsRepository.alertHighIsSnoozed.value = value
  555. if !value {
  556. UserDefaultsRepository.alertHighSnoozedTime.setNil(key: "alertHighSnoozedTime")
  557. let otherRow = self?.form.rowBy(tag: "alertHighSnoozedTime") as! DateTimeInlineRow
  558. otherRow.value = nil
  559. otherRow.reload()
  560. }
  561. }
  562. }
  563. func buildUrgentHigh(){
  564. form
  565. +++ Section(header: "Urgent High Alert", footer: "Alerts when BG rises above value.")
  566. <<< SwitchRow("alertUrgentHighActive"){ row in
  567. row.title = "Active"
  568. row.value = UserDefaultsRepository.alertUrgentHighActive.value
  569. }.onChange { [weak self] row in
  570. guard let value = row.value else { return }
  571. UserDefaultsRepository.alertUrgentHighActive.value = value
  572. }
  573. <<< StepperRow("alertUrgentHighBG") { row in
  574. row.title = "BG"
  575. row.cell.stepper.stepValue = 1
  576. row.cell.stepper.minimumValue = 120
  577. row.cell.stepper.maximumValue = 350
  578. row.value = Double(UserDefaultsRepository.alertUrgentHighBG.value)
  579. row.hidden = "$alertUrgentHighActive == false"
  580. row.displayValueFor = { value in
  581. guard let value = value else { return nil }
  582. return "\(Int(value))"
  583. }
  584. }.onChange { [weak self] row in
  585. guard let value = row.value else { return }
  586. UserDefaultsRepository.alertUrgentHighBG.value = Int(value)
  587. }
  588. <<< StepperRow("alertUrgentHighSnooze") { row in
  589. row.title = "Snooze"
  590. row.cell.stepper.stepValue = 5
  591. row.cell.stepper.minimumValue = 10
  592. row.cell.stepper.maximumValue = 120
  593. row.value = Double(UserDefaultsRepository.alertUrgentHighSnooze.value)
  594. row.hidden = "$alertUrgentHighActive == false"
  595. row.displayValueFor = { value in
  596. guard let value = value else { return nil }
  597. return "\(Int(value))"
  598. }
  599. }.onChange { [weak self] row in
  600. guard let value = row.value else { return }
  601. UserDefaultsRepository.alertUrgentHighSnooze.value = Int(value)
  602. }
  603. <<< PickerInputRow<String>("alertUrgentHighSound") { row in
  604. row.title = "Sound"
  605. row.options = soundFiles
  606. row.hidden = "$alertUrgentHighActive == false"
  607. row.value = UserDefaultsRepository.alertUrgentHighSound.value
  608. row.displayValueFor = { value in
  609. guard let value = value else { return nil }
  610. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  611. }
  612. }.onChange { [weak self] row in
  613. guard let value = row.value else { return }
  614. UserDefaultsRepository.alertUrgentHighSound.value = value
  615. AlarmSound.setSoundFile(str: value)
  616. AlarmSound.stop()
  617. AlarmSound.playTest()
  618. }
  619. <<< DateTimeInlineRow("alertUrgentHighSnoozedTime") { row in
  620. row.title = "Snoozed Until"
  621. row.hidden = "$alertUrgentHighActive == false"
  622. if (UserDefaultsRepository.alertUrgentHighSnoozedTime.value != nil) {
  623. row.value = UserDefaultsRepository.alertUrgentHighSnoozedTime.value
  624. }
  625. row.minuteInterval = 5
  626. row.noValueDisplayText = "Not Snoozed"
  627. }
  628. .onChange { [weak self] row in
  629. guard let value = row.value else { return }
  630. UserDefaultsRepository.alertUrgentHighSnoozedTime.value = value
  631. UserDefaultsRepository.alertUrgentHighIsSnoozed.value = true
  632. let otherRow = self?.form.rowBy(tag: "alertUrgentHighIsSnoozed") as! SwitchRow
  633. otherRow.value = true
  634. otherRow.reload()
  635. }
  636. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  637. inlineRow.cellUpdate() { cell, row in
  638. cell.datePicker.datePickerMode = .dateAndTime
  639. }
  640. let color = cell.detailTextLabel?.textColor
  641. row.onCollapseInlineRow { cell, _, _ in
  642. cell.detailTextLabel?.textColor = color
  643. }
  644. cell.detailTextLabel?.textColor = cell.tintColor
  645. }
  646. <<< SwitchRow("alertUrgentHighIsSnoozed"){ row in
  647. row.title = "Is Snoozed"
  648. row.value = UserDefaultsRepository.alertUrgentHighIsSnoozed.value
  649. row.hidden = "$alertUrgentHighActive == false || $alertUrgentHighSnoozedTime == nil"
  650. }.onChange { [weak self] row in
  651. guard let value = row.value else { return }
  652. UserDefaultsRepository.alertUrgentHighIsSnoozed.value = value
  653. if !value {
  654. UserDefaultsRepository.alertUrgentHighSnoozedTime.setNil(key: "alertUrgentHighSnoozedTime")
  655. let otherRow = self?.form.rowBy(tag: "alertUrgentHighSnoozedTime") as! DateTimeInlineRow
  656. otherRow.value = nil
  657. otherRow.reload()
  658. }
  659. }
  660. }
  661. func buildFastDropAlert(){
  662. form
  663. +++ Section(header: "Fast Drop Alert", footer: "Alert when BG is dropping fast over consecutive readings. Optional: only alert when dropping below a specific BG")
  664. <<< SwitchRow("alertFastDropActive"){ row in
  665. row.title = "Active"
  666. row.value = UserDefaultsRepository.alertFastDropActive.value
  667. }.onChange { [weak self] row in
  668. guard let value = row.value else { return }
  669. UserDefaultsRepository.alertFastDropActive.value = value
  670. }
  671. <<< StepperRow("alertFastDropDelta") { row in
  672. row.title = "Delta"
  673. row.cell.stepper.stepValue = 1
  674. row.cell.stepper.minimumValue = 3
  675. row.cell.stepper.maximumValue = 20
  676. row.value = Double(UserDefaultsRepository.alertFastDropDelta.value)
  677. row.hidden = "$alertFastDropActive == false"
  678. row.displayValueFor = { value in
  679. guard let value = value else { return nil }
  680. return "\(Int(value))"
  681. }
  682. }.onChange { [weak self] row in
  683. guard let value = row.value else { return }
  684. UserDefaultsRepository.alertFastDropDelta.value = Int(value)
  685. }
  686. <<< StepperRow("alertFastDropReadings") { row in
  687. row.title = "# Readings"
  688. row.cell.stepper.stepValue = 1
  689. row.cell.stepper.minimumValue = 2
  690. row.cell.stepper.maximumValue = 4
  691. row.value = Double(UserDefaultsRepository.alertFastDropReadings.value)
  692. row.hidden = "$alertFastDropActive == false"
  693. row.displayValueFor = { value in
  694. guard let value = value else { return nil }
  695. return "\(Int(value))"
  696. }
  697. }.onChange { [weak self] row in
  698. guard let value = row.value else { return }
  699. UserDefaultsRepository.alertFastDropReadings.value = Int(value)
  700. }
  701. <<< SwitchRow("alertFastDropUseLimit"){ row in
  702. row.title = "Use BG Limit"
  703. row.hidden = "$alertFastDropActive == false"
  704. row.value = UserDefaultsRepository.alertFastDropUseLimit.value
  705. }.onChange { [weak self] row in
  706. guard let value = row.value else { return }
  707. UserDefaultsRepository.alertFastDropUseLimit.value = value
  708. }
  709. <<< StepperRow("alertFastDropBelowBG") { row in
  710. row.title = "Dropping Below BG"
  711. row.cell.stepper.stepValue = 1
  712. row.cell.stepper.minimumValue = 100
  713. row.cell.stepper.maximumValue = 300
  714. row.value = Double(UserDefaultsRepository.alertFastDropBelowBG.value)
  715. row.hidden = "$alertFastDropActive == false || $alertFastDropUseLimit == false"
  716. row.displayValueFor = { value in
  717. guard let value = value else { return nil }
  718. return "\(Int(value))"
  719. }
  720. }.onChange { [weak self] row in
  721. guard let value = row.value else { return }
  722. UserDefaultsRepository.alertFastDropBelowBG.value = Int(value)
  723. }
  724. <<< StepperRow("alertFastDropSnooze") { row in
  725. row.title = "Snooze"
  726. row.cell.stepper.stepValue = 5
  727. row.cell.stepper.minimumValue = 5
  728. row.cell.stepper.maximumValue = 60
  729. row.value = Double(UserDefaultsRepository.alertFastDropSnooze.value)
  730. row.hidden = "$alertFastDropActive == false"
  731. row.displayValueFor = { value in
  732. guard let value = value else { return nil }
  733. return "\(Int(value))"
  734. }
  735. }.onChange { [weak self] row in
  736. guard let value = row.value else { return }
  737. UserDefaultsRepository.alertFastDropSnooze.value = Int(value)
  738. }
  739. <<< PickerInputRow<String>("alertFastDropSound") { row in
  740. row.title = "Sound"
  741. row.options = soundFiles
  742. row.hidden = "$alertFastDropActive == false"
  743. row.value = UserDefaultsRepository.alertFastDropSound.value
  744. row.displayValueFor = { value in
  745. guard let value = value else { return nil }
  746. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  747. }
  748. }.onChange { [weak self] row in
  749. guard let value = row.value else { return }
  750. UserDefaultsRepository.alertFastDropSound.value = value
  751. AlarmSound.setSoundFile(str: value)
  752. AlarmSound.stop()
  753. AlarmSound.playTest()
  754. }
  755. <<< DateTimeInlineRow("alertFastDropSnoozedTime") { row in
  756. row.title = "Snoozed Until"
  757. row.hidden = "$alertFastDropActive == false"
  758. if (UserDefaultsRepository.alertFastDropSnoozedTime.value != nil) {
  759. row.value = UserDefaultsRepository.alertFastDropSnoozedTime.value
  760. }
  761. row.minuteInterval = 5
  762. row.noValueDisplayText = "Not Snoozed"
  763. }
  764. .onChange { [weak self] row in
  765. guard let value = row.value else { return }
  766. UserDefaultsRepository.alertFastDropSnoozedTime.value = value
  767. UserDefaultsRepository.alertFastDropIsSnoozed.value = true
  768. let otherRow = self?.form.rowBy(tag: "alertFastDropIsSnoozed") as! SwitchRow
  769. otherRow.value = true
  770. otherRow.reload()
  771. }
  772. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  773. inlineRow.cellUpdate() { cell, row in
  774. cell.datePicker.datePickerMode = .dateAndTime
  775. }
  776. let color = cell.detailTextLabel?.textColor
  777. row.onCollapseInlineRow { cell, _, _ in
  778. cell.detailTextLabel?.textColor = color
  779. }
  780. cell.detailTextLabel?.textColor = cell.tintColor
  781. }
  782. <<< SwitchRow("alertFastDropIsSnoozed"){ row in
  783. row.title = "Is Snoozed"
  784. row.value = UserDefaultsRepository.alertFastDropIsSnoozed.value
  785. row.hidden = "$alertFastDropActive == false || $alertFastDropSnoozedTime == nil"
  786. }.onChange { [weak self] row in
  787. guard let value = row.value else { return }
  788. UserDefaultsRepository.alertFastDropIsSnoozed.value = value
  789. if !value {
  790. UserDefaultsRepository.alertFastDropSnoozedTime.setNil(key: "alertFastDropSnoozedTime")
  791. let otherRow = self?.form.rowBy(tag: "alertFastDropSnoozedTime") as! DateTimeInlineRow
  792. otherRow.value = nil
  793. otherRow.reload()
  794. }
  795. }
  796. }
  797. func buildFastRiseAlert(){
  798. form
  799. +++ Section(header: "Fast Rise Alert", footer: "Alert when BG is rising fast over consecutive readings. Optional: only alert when rising above a specific BG")
  800. <<< SwitchRow("alertFastRiseActive"){ row in
  801. row.title = "Active"
  802. row.value = UserDefaultsRepository.alertFastRiseActive.value
  803. }.onChange { [weak self] row in
  804. guard let value = row.value else { return }
  805. UserDefaultsRepository.alertFastRiseActive.value = value
  806. }
  807. <<< StepperRow("alertFastRiseDelta") { row in
  808. row.title = "Delta"
  809. row.cell.stepper.stepValue = 1
  810. row.cell.stepper.minimumValue = 3
  811. row.cell.stepper.maximumValue = 20
  812. row.value = Double(UserDefaultsRepository.alertFastRiseDelta.value)
  813. row.hidden = "$alertFastRiseActive == false"
  814. row.displayValueFor = { value in
  815. guard let value = value else { return nil }
  816. return "\(Int(value))"
  817. }
  818. }.onChange { [weak self] row in
  819. guard let value = row.value else { return }
  820. UserDefaultsRepository.alertFastRiseDelta.value = Int(value)
  821. }
  822. <<< StepperRow("alertFastRiseReadings") { row in
  823. row.title = "# Readings"
  824. row.cell.stepper.stepValue = 1
  825. row.cell.stepper.minimumValue = 2
  826. row.cell.stepper.maximumValue = 4
  827. row.value = Double(UserDefaultsRepository.alertFastRiseReadings.value)
  828. row.hidden = "$alertFastRiseActive == false"
  829. row.displayValueFor = { value in
  830. guard let value = value else { return nil }
  831. return "\(Int(value))"
  832. }
  833. }.onChange { [weak self] row in
  834. guard let value = row.value else { return }
  835. UserDefaultsRepository.alertFastRiseReadings.value = Int(value)
  836. }
  837. <<< SwitchRow("alertFastRiseUseLimit"){ row in
  838. row.title = "Use BG Limit"
  839. row.hidden = "$alertFastRiseActive == false"
  840. row.value = UserDefaultsRepository.alertFastRiseUseLimit.value
  841. }.onChange { [weak self] row in
  842. guard let value = row.value else { return }
  843. UserDefaultsRepository.alertFastRiseUseLimit.value = value
  844. }
  845. <<< StepperRow("alertFastRiseAboveBG") { row in
  846. row.title = "Rising Above BG"
  847. row.cell.stepper.stepValue = 1
  848. row.cell.stepper.minimumValue = 100
  849. row.cell.stepper.maximumValue = 300
  850. row.value = Double(UserDefaultsRepository.alertFastRiseAboveBG.value)
  851. row.hidden = "$alertFastRiseActive == false || $alertFastRiseUseLimit == false"
  852. row.displayValueFor = { value in
  853. guard let value = value else { return nil }
  854. return "\(Int(value))"
  855. }
  856. }.onChange { [weak self] row in
  857. guard let value = row.value else { return }
  858. UserDefaultsRepository.alertFastRiseAboveBG.value = Int(value)
  859. }
  860. <<< StepperRow("alertFastRiseSnooze") { row in
  861. row.title = "Snooze"
  862. row.cell.stepper.stepValue = 5
  863. row.cell.stepper.minimumValue = 5
  864. row.cell.stepper.maximumValue = 60
  865. row.value = Double(UserDefaultsRepository.alertFastRiseSnooze.value)
  866. row.hidden = "$alertFastRiseActive == false"
  867. row.displayValueFor = { value in
  868. guard let value = value else { return nil }
  869. return "\(Int(value))"
  870. }
  871. }.onChange { [weak self] row in
  872. guard let value = row.value else { return }
  873. UserDefaultsRepository.alertFastRiseSnooze.value = Int(value)
  874. }
  875. <<< PickerInputRow<String>("alertFastRiseSound") { row in
  876. row.title = "Sound"
  877. row.options = soundFiles
  878. row.hidden = "$alertFastRiseActive == false"
  879. row.value = UserDefaultsRepository.alertFastRiseSound.value
  880. row.displayValueFor = { value in
  881. guard let value = value else { return nil }
  882. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  883. }
  884. }.onChange { [weak self] row in
  885. guard let value = row.value else { return }
  886. UserDefaultsRepository.alertFastRiseSound.value = value
  887. AlarmSound.setSoundFile(str: value)
  888. AlarmSound.stop()
  889. AlarmSound.playTest()
  890. }
  891. <<< DateTimeInlineRow("alertFastRiseSnoozedTime") { row in
  892. row.title = "Snoozed Until"
  893. row.hidden = "$alertFastRiseActive == false"
  894. if (UserDefaultsRepository.alertFastRiseSnoozedTime.value != nil) {
  895. row.value = UserDefaultsRepository.alertFastRiseSnoozedTime.value
  896. }
  897. row.minuteInterval = 5
  898. row.noValueDisplayText = "Not Snoozed"
  899. }
  900. .onChange { [weak self] row in
  901. guard let value = row.value else { return }
  902. UserDefaultsRepository.alertFastRiseSnoozedTime.value = value
  903. UserDefaultsRepository.alertFastRiseIsSnoozed.value = true
  904. let otherRow = self?.form.rowBy(tag: "alertFastRiseIsSnoozed") as! SwitchRow
  905. otherRow.value = true
  906. otherRow.reload()
  907. }
  908. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  909. inlineRow.cellUpdate() { cell, row in
  910. cell.datePicker.datePickerMode = .dateAndTime
  911. }
  912. let color = cell.detailTextLabel?.textColor
  913. row.onCollapseInlineRow { cell, _, _ in
  914. cell.detailTextLabel?.textColor = color
  915. }
  916. cell.detailTextLabel?.textColor = cell.tintColor
  917. }
  918. <<< SwitchRow("alertFastRiseIsSnoozed"){ row in
  919. row.title = "Is Snoozed"
  920. row.value = UserDefaultsRepository.alertFastRiseIsSnoozed.value
  921. row.hidden = "$alertFastRiseActive == false || $alertFastRiseSnoozedTime == nil"
  922. }.onChange { [weak self] row in
  923. guard let value = row.value else { return }
  924. UserDefaultsRepository.alertFastRiseIsSnoozed.value = value
  925. if !value {
  926. UserDefaultsRepository.alertFastRiseSnoozedTime.setNil(key: "alertFastRiseSnoozedTime")
  927. let otherRow = self?.form.rowBy(tag: "alertFastRiseSnoozedTime") as! DateTimeInlineRow
  928. otherRow.value = nil
  929. otherRow.reload()
  930. }
  931. }
  932. }
  933. func buildMissedReadings(){
  934. form
  935. +++ Section(header: "Missed Readings", footer: "Alert when there have been no BG readings for X minutes")
  936. <<< SwitchRow("alertMissedReadingActive"){ row in
  937. row.title = "Active"
  938. row.value = UserDefaultsRepository.alertMissedReadingActive.value
  939. }.onChange { [weak self] row in
  940. guard let value = row.value else { return }
  941. UserDefaultsRepository.alertMissedReadingActive.value = value
  942. }
  943. <<< StepperRow("alertMissedReading") { row in
  944. row.title = "Time"
  945. row.cell.stepper.stepValue = 5
  946. row.cell.stepper.minimumValue = 10
  947. row.cell.stepper.maximumValue = 120
  948. row.value = Double(UserDefaultsRepository.alertMissedReading.value)
  949. row.hidden = "$alertMissedReadingActive == false"
  950. row.displayValueFor = { value in
  951. guard let value = value else { return nil }
  952. return "\(Int(value))"
  953. }
  954. }.onChange { [weak self] row in
  955. guard let value = row.value else { return }
  956. UserDefaultsRepository.alertMissedReading.value = Int(value)
  957. }
  958. <<< StepperRow("alertMissedReadingSnooze") { row in
  959. row.title = "Snooze"
  960. row.cell.stepper.stepValue = 5
  961. row.cell.stepper.minimumValue = 10
  962. row.cell.stepper.maximumValue = 180
  963. row.value = Double(UserDefaultsRepository.alertMissedReadingSnooze.value)
  964. row.hidden = "$alertMissedReadingActive == false"
  965. row.displayValueFor = { value in
  966. guard let value = value else { return nil }
  967. return "\(Int(value))"
  968. }
  969. }.onChange { [weak self] row in
  970. guard let value = row.value else { return }
  971. UserDefaultsRepository.alertMissedReadingSnooze.value = Int(value)
  972. }
  973. <<< PickerInputRow<String>("alertMissedReadingSound") { row in
  974. row.title = "Sound"
  975. row.options = soundFiles
  976. row.hidden = "$alertMissedReadingActive == false"
  977. row.value = UserDefaultsRepository.alertMissedReadingSound.value
  978. row.displayValueFor = { value in
  979. guard let value = value else { return nil }
  980. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  981. }
  982. }.onChange { [weak self] row in
  983. guard let value = row.value else { return }
  984. UserDefaultsRepository.alertMissedReadingSound.value = value
  985. AlarmSound.setSoundFile(str: value)
  986. AlarmSound.stop()
  987. AlarmSound.playTest()
  988. }
  989. <<< DateTimeInlineRow("alertMissedReadingSnoozedTime") { row in
  990. row.title = "Snoozed Until"
  991. row.hidden = "$alertMissedReadingActive == false"
  992. if (UserDefaultsRepository.alertMissedReadingSnoozedTime.value != nil) {
  993. row.value = UserDefaultsRepository.alertMissedReadingSnoozedTime.value
  994. }
  995. row.minuteInterval = 5
  996. row.noValueDisplayText = "Not Snoozed"
  997. }
  998. .onChange { [weak self] row in
  999. guard let value = row.value else { return }
  1000. UserDefaultsRepository.alertMissedReadingSnoozedTime.value = value
  1001. UserDefaultsRepository.alertMissedReadingIsSnoozed.value = true
  1002. let otherRow = self?.form.rowBy(tag: "alertMissedReadingIsSnoozed") as! SwitchRow
  1003. otherRow.value = true
  1004. otherRow.reload()
  1005. }
  1006. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  1007. inlineRow.cellUpdate() { cell, row in
  1008. cell.datePicker.datePickerMode = .dateAndTime
  1009. }
  1010. let color = cell.detailTextLabel?.textColor
  1011. row.onCollapseInlineRow { cell, _, _ in
  1012. cell.detailTextLabel?.textColor = color
  1013. }
  1014. cell.detailTextLabel?.textColor = cell.tintColor
  1015. }
  1016. <<< SwitchRow("alertMissedReadingIsSnoozed"){ row in
  1017. row.title = "Is Snoozed"
  1018. row.value = UserDefaultsRepository.alertMissedReadingIsSnoozed.value
  1019. row.hidden = "$alertMissedReadingActive == false || $alertMissedReadingSnoozedTime == nil"
  1020. }.onChange { [weak self] row in
  1021. guard let value = row.value else { return }
  1022. UserDefaultsRepository.alertMissedReadingIsSnoozed.value = value
  1023. if !value {
  1024. UserDefaultsRepository.alertMissedReadingSnoozedTime.setNil(key: "alertMissedReadingSnoozedTime")
  1025. let otherRow = self?.form.rowBy(tag: "alertMissedReadingSnoozedTime") as! DateTimeInlineRow
  1026. otherRow.value = nil
  1027. otherRow.reload()
  1028. }
  1029. }
  1030. }
  1031. func buildNotLooping(){
  1032. form
  1033. +++ Section(header: "Not Looping", footer: "Alert when Loop has not completed a successful Loop for X minutes")
  1034. <<< SwitchRow("alertNotLoopingActive"){ row in
  1035. row.title = "Active"
  1036. row.value = UserDefaultsRepository.alertNotLoopingActive.value
  1037. }.onChange { [weak self] row in
  1038. guard let value = row.value else { return }
  1039. UserDefaultsRepository.alertNotLoopingActive.value = value
  1040. }
  1041. <<< StepperRow("alertNotLooping") { row in
  1042. row.title = "Time"
  1043. row.cell.stepper.stepValue = 5
  1044. row.cell.stepper.minimumValue = 10
  1045. row.cell.stepper.maximumValue = 60
  1046. row.value = Double(UserDefaultsRepository.alertNotLooping.value)
  1047. row.hidden = "$alertNotLoopingActive == false"
  1048. row.displayValueFor = { value in
  1049. guard let value = value else { return nil }
  1050. return "\(Int(value))"
  1051. }
  1052. }.onChange { [weak self] row in
  1053. guard let value = row.value else { return }
  1054. UserDefaultsRepository.alertNotLooping.value = Int(value)
  1055. }
  1056. <<< SwitchRow("alertNotLoopingUseLimits"){ row in
  1057. row.title = "Use BG Limits"
  1058. row.hidden = "$alertNotLoopingActive == false"
  1059. row.value = UserDefaultsRepository.alertNotLoopingUseLimits.value
  1060. }.onChange { [weak self] row in
  1061. guard let value = row.value else { return }
  1062. UserDefaultsRepository.alertNotLoopingUseLimits.value = value
  1063. }
  1064. <<< StepperRow("alertNotLoopingLowerLimit") { row in
  1065. row.title = "Below BG"
  1066. row.cell.stepper.stepValue = 1
  1067. row.cell.stepper.minimumValue = 50
  1068. row.cell.stepper.maximumValue = 200
  1069. row.value = Double(UserDefaultsRepository.alertNotLoopingLowerLimit.value)
  1070. row.hidden = "$alertNotLoopingActive == false || $alertNotLoopingUseLimits == false"
  1071. row.displayValueFor = { value in
  1072. guard let value = value else { return nil }
  1073. return "\(Int(value))"
  1074. }
  1075. }.onChange { [weak self] row in
  1076. guard let value = row.value else { return }
  1077. UserDefaultsRepository.alertNotLoopingLowerLimit.value = Int(value)
  1078. }
  1079. <<< StepperRow("alertNotLoopingUpperLimit") { row in
  1080. row.title = "Above BG"
  1081. row.cell.stepper.stepValue = 1
  1082. row.cell.stepper.minimumValue = 100
  1083. row.cell.stepper.maximumValue = 300
  1084. row.value = Double(UserDefaultsRepository.alertNotLoopingUpperLimit.value)
  1085. row.hidden = "$alertNotLoopingActive == false || $alertNotLoopingUseLimits == false"
  1086. row.displayValueFor = { value in
  1087. guard let value = value else { return nil }
  1088. return "\(Int(value))"
  1089. }
  1090. }.onChange { [weak self] row in
  1091. guard let value = row.value else { return }
  1092. UserDefaultsRepository.alertNotLoopingUpperLimit.value = Int(value)
  1093. }
  1094. <<< StepperRow("alertNotLoopingSnooze") { row in
  1095. row.title = "Snooze"
  1096. row.cell.stepper.stepValue = 5
  1097. row.cell.stepper.minimumValue = 10
  1098. row.cell.stepper.maximumValue = 120
  1099. row.value = Double(UserDefaultsRepository.alertNotLoopingSnooze.value)
  1100. row.hidden = "$alertNotLoopingActive == false"
  1101. row.displayValueFor = { value in
  1102. guard let value = value else { return nil }
  1103. return "\(Int(value))"
  1104. }
  1105. }.onChange { [weak self] row in
  1106. guard let value = row.value else { return }
  1107. UserDefaultsRepository.alertNotLoopingSnooze.value = Int(value)
  1108. }
  1109. <<< PickerInputRow<String>("alertNotLoopingSound") { row in
  1110. row.title = "Sound"
  1111. row.options = soundFiles
  1112. row.hidden = "$alertNotLoopingActive == false"
  1113. row.value = UserDefaultsRepository.alertNotLoopingSound.value
  1114. row.displayValueFor = { value in
  1115. guard let value = value else { return nil }
  1116. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  1117. }
  1118. }.onChange { [weak self] row in
  1119. guard let value = row.value else { return }
  1120. UserDefaultsRepository.alertNotLoopingSound.value = value
  1121. AlarmSound.setSoundFile(str: value)
  1122. AlarmSound.stop()
  1123. AlarmSound.playTest()
  1124. }
  1125. <<< DateTimeInlineRow("alertNotLoopingSnoozedTime") { row in
  1126. row.title = "Snoozed Until"
  1127. row.hidden = "$alertNotLoopingActive == false"
  1128. if (UserDefaultsRepository.alertNotLoopingSnoozedTime.value != nil) {
  1129. row.value = UserDefaultsRepository.alertNotLoopingSnoozedTime.value
  1130. }
  1131. row.minuteInterval = 5
  1132. row.noValueDisplayText = "Not Snoozed"
  1133. }
  1134. .onChange { [weak self] row in
  1135. guard let value = row.value else { return }
  1136. UserDefaultsRepository.alertNotLoopingSnoozedTime.value = value
  1137. UserDefaultsRepository.alertNotLoopingIsSnoozed.value = true
  1138. let otherRow = self?.form.rowBy(tag: "alertNotLoopingIsSnoozed") as! SwitchRow
  1139. otherRow.value = true
  1140. otherRow.reload()
  1141. }
  1142. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  1143. inlineRow.cellUpdate() { cell, row in
  1144. cell.datePicker.datePickerMode = .dateAndTime
  1145. }
  1146. let color = cell.detailTextLabel?.textColor
  1147. row.onCollapseInlineRow { cell, _, _ in
  1148. cell.detailTextLabel?.textColor = color
  1149. }
  1150. cell.detailTextLabel?.textColor = cell.tintColor
  1151. }
  1152. <<< SwitchRow("alertNotLoopingIsSnoozed"){ row in
  1153. row.title = "Is Snoozed"
  1154. row.value = UserDefaultsRepository.alertNotLoopingIsSnoozed.value
  1155. row.hidden = "$alertNotLoopingActive == false || $alertNotLoopingSnoozedTime == nil"
  1156. }.onChange { [weak self] row in
  1157. guard let value = row.value else { return }
  1158. UserDefaultsRepository.alertNotLoopingIsSnoozed.value = value
  1159. if !value {
  1160. UserDefaultsRepository.alertNotLoopingSnoozedTime.setNil(key: "alertNotLoopingSnoozedTime")
  1161. let otherRow = self?.form.rowBy(tag: "alertNotLoopingSnoozedTime") as! DateTimeInlineRow
  1162. otherRow.value = nil
  1163. otherRow.reload()
  1164. }
  1165. }
  1166. }
  1167. func buildMissedBolus(){
  1168. form
  1169. +++ Section(header: "Missed Bolus", footer: "Alert after X minutes when carbs are entered with no Bolus. Optional: Ignore low treatment carbs under a certain BG")
  1170. <<< SwitchRow("alertMissedBolusActive"){ row in
  1171. row.title = "Active"
  1172. row.value = UserDefaultsRepository.alertMissedBolusActive.value
  1173. }.onChange { [weak self] row in
  1174. guard let value = row.value else { return }
  1175. UserDefaultsRepository.alertMissedBolusActive.value = value
  1176. }
  1177. <<< StepperRow("alertMissedBolus") { row in
  1178. row.title = "Time"
  1179. row.cell.stepper.stepValue = 5
  1180. row.cell.stepper.minimumValue = 5
  1181. row.cell.stepper.maximumValue = 60
  1182. row.value = Double(UserDefaultsRepository.alertMissedBolus.value)
  1183. row.hidden = "$alertMissedBolusActive == false"
  1184. row.displayValueFor = { value in
  1185. guard let value = value else { return nil }
  1186. return "\(Int(value))"
  1187. }
  1188. }.onChange { [weak self] row in
  1189. guard let value = row.value else { return }
  1190. UserDefaultsRepository.alertMissedBolus.value = Int(value)
  1191. }
  1192. <<< SwitchRow("alertMissedBolusLowGramsActive"){ row in
  1193. row.title = "Ignore Low Treatments"
  1194. row.hidden = "$alertMissedBolusActive == false"
  1195. row.value = UserDefaultsRepository.alertMissedBolusLowGramsActive.value
  1196. }.onChange { [weak self] row in
  1197. guard let value = row.value else { return }
  1198. UserDefaultsRepository.alertMissedBolusLowGramsActive.value = value
  1199. }
  1200. <<< StepperRow("alertMissedBolusLowGrams") { row in
  1201. row.title = "Ignore Under Grams"
  1202. row.tag = "missedBolusLowGrams"
  1203. row.cell.stepper.stepValue = 1
  1204. row.cell.stepper.minimumValue = 1
  1205. row.cell.stepper.maximumValue = 15
  1206. row.value = Double(UserDefaultsRepository.alertMissedBolusLowGrams.value)
  1207. row.hidden = "$alertMissedBolusLowGramsActive == false || $alertMissedBolusActive == false"
  1208. row.displayValueFor = { value in
  1209. guard let value = value else { return nil }
  1210. return "\(Int(value))"
  1211. }
  1212. }.onChange { [weak self] row in
  1213. guard let value = row.value else { return }
  1214. UserDefaultsRepository.alertMissedBolusLowGrams.value = Int(value)
  1215. }
  1216. <<< StepperRow("alertMissedBolusLowGramsBG") { row in
  1217. row.title = "Ignore Under BG"
  1218. row.tag = "missedBolusLowGramsBG"
  1219. row.cell.stepper.stepValue = 1
  1220. row.cell.stepper.minimumValue = 40
  1221. row.cell.stepper.maximumValue = 100
  1222. row.value = Double(UserDefaultsRepository.alertMissedBolusLowGramsBG.value)
  1223. row.hidden = "$alertMissedBolusLowGramsActive == false || $alertMissedBolusActive == false"
  1224. row.displayValueFor = { value in
  1225. guard let value = value else { return nil }
  1226. return "\(Int(value))"
  1227. }
  1228. }.onChange { [weak self] row in
  1229. guard let value = row.value else { return }
  1230. UserDefaultsRepository.alertMissedBolusLowGramsBG.value = Int(value)
  1231. }
  1232. <<< StepperRow("alertMissedBolusSnooze") { row in
  1233. row.title = "Snooze"
  1234. row.cell.stepper.stepValue = 5
  1235. row.cell.stepper.minimumValue = 5
  1236. row.cell.stepper.maximumValue = 60
  1237. row.value = Double(UserDefaultsRepository.alertMissedBolusSnooze.value)
  1238. row.hidden = "$alertMissedBolusActive == false"
  1239. row.displayValueFor = { value in
  1240. guard let value = value else { return nil }
  1241. return "\(Int(value))"
  1242. }
  1243. }.onChange { [weak self] row in
  1244. guard let value = row.value else { return }
  1245. UserDefaultsRepository.alertMissedBolusSnooze.value = Int(value)
  1246. }
  1247. <<< PickerInputRow<String>("alertMissedBolusSound") { row in
  1248. row.title = "Sound"
  1249. row.options = soundFiles
  1250. row.hidden = "$alertMissedBolusActive == false"
  1251. row.value = UserDefaultsRepository.alertMissedBolusSound.value
  1252. row.displayValueFor = { value in
  1253. guard let value = value else { return nil }
  1254. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  1255. }
  1256. }.onChange { [weak self] row in
  1257. guard let value = row.value else { return }
  1258. UserDefaultsRepository.alertMissedBolusSound.value = value
  1259. AlarmSound.setSoundFile(str: value)
  1260. AlarmSound.stop()
  1261. AlarmSound.playTest()
  1262. }
  1263. <<< DateTimeInlineRow("alertMissedBolusSnoozedTime") { row in
  1264. row.title = "Snoozed Until"
  1265. row.hidden = "$alertMissedBolusActive == false"
  1266. if (UserDefaultsRepository.alertMissedBolusSnoozedTime.value != nil) {
  1267. row.value = UserDefaultsRepository.alertMissedBolusSnoozedTime.value
  1268. }
  1269. row.minuteInterval = 5
  1270. row.noValueDisplayText = "Not Snoozed"
  1271. }
  1272. .onChange { [weak self] row in
  1273. guard let value = row.value else { return }
  1274. UserDefaultsRepository.alertMissedBolusSnoozedTime.value = value
  1275. UserDefaultsRepository.alertMissedBolusIsSnoozed.value = true
  1276. let otherRow = self?.form.rowBy(tag: "alertMissedBolusIsSnoozed") as! SwitchRow
  1277. otherRow.value = true
  1278. otherRow.reload()
  1279. }
  1280. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  1281. inlineRow.cellUpdate() { cell, row in
  1282. cell.datePicker.datePickerMode = .dateAndTime
  1283. }
  1284. let color = cell.detailTextLabel?.textColor
  1285. row.onCollapseInlineRow { cell, _, _ in
  1286. cell.detailTextLabel?.textColor = color
  1287. }
  1288. cell.detailTextLabel?.textColor = cell.tintColor
  1289. }
  1290. <<< SwitchRow("alertMissedBolusIsSnoozed"){ row in
  1291. row.title = "Is Snoozed"
  1292. row.value = UserDefaultsRepository.alertMissedBolusIsSnoozed.value
  1293. row.hidden = "$alertMissedBolusActive == false || $alertMissedBolusSnoozedTime == nil"
  1294. }.onChange { [weak self] row in
  1295. guard let value = row.value else { return }
  1296. UserDefaultsRepository.alertMissedBolusIsSnoozed.value = value
  1297. if !value {
  1298. UserDefaultsRepository.alertMissedBolusSnoozedTime.setNil(key: "alertMissedBolusSnoozedTime")
  1299. let otherRow = self?.form.rowBy(tag: "alertMissedBolusSnoozedTime") as! DateTimeInlineRow
  1300. otherRow.value = nil
  1301. otherRow.reload()
  1302. }
  1303. }
  1304. }
  1305. func buildAppInactive(){
  1306. form
  1307. +++ Section(header: "App Inactive", footer: "Attempt to alert if IOS kills the app in the background")
  1308. <<< SwitchRow("alertAppInactive"){ row in
  1309. row.title = "Active"
  1310. row.value = UserDefaultsRepository.alertAppInactive.value
  1311. }.onChange { [weak self] row in
  1312. guard let value = row.value else { return }
  1313. UserDefaultsRepository.alertAppInactive.value = value
  1314. }
  1315. }
  1316. func buildSage(){
  1317. form
  1318. +++ Section(header: "Sensor Change Reminder", footer: "Alert for 10 Day Sensor Change. Values are in Hours.")
  1319. <<< SwitchRow("alertSAGEActive"){ row in
  1320. row.title = "Active"
  1321. row.value = UserDefaultsRepository.alertSAGEActive.value
  1322. }.onChange { [weak self] row in
  1323. guard let value = row.value else { return }
  1324. UserDefaultsRepository.alertSAGEActive.value = value
  1325. }
  1326. <<< StepperRow("alertSAGE") { row in
  1327. row.title = "Time"
  1328. row.cell.stepper.stepValue = 1
  1329. row.cell.stepper.minimumValue = 1
  1330. row.cell.stepper.maximumValue = 24
  1331. row.value = Double(UserDefaultsRepository.alertSAGE.value)
  1332. row.hidden = "$alertSAGEActive == false"
  1333. row.displayValueFor = { value in
  1334. guard let value = value else { return nil }
  1335. return "\(Int(value))"
  1336. }
  1337. }.onChange { [weak self] row in
  1338. guard let value = row.value else { return }
  1339. UserDefaultsRepository.alertSAGE.value = Int(value)
  1340. }
  1341. <<< StepperRow("alertSAGESnooze") { row in
  1342. row.title = "Snooze"
  1343. row.cell.stepper.stepValue = 1
  1344. row.cell.stepper.minimumValue = 1
  1345. row.cell.stepper.maximumValue = 24
  1346. row.value = Double(UserDefaultsRepository.alertSAGESnooze.value)
  1347. row.hidden = "$alertSAGEActive == false"
  1348. row.displayValueFor = { value in
  1349. guard let value = value else { return nil }
  1350. return "\(Int(value))"
  1351. }
  1352. }.onChange { [weak self] row in
  1353. guard let value = row.value else { return }
  1354. UserDefaultsRepository.alertSAGESnooze.value = Int(value)
  1355. }
  1356. <<< PickerInputRow<String>("alertSAGESound") { row in
  1357. row.title = "Sound"
  1358. row.options = soundFiles
  1359. row.hidden = "$alertSAGEActive == false"
  1360. row.value = UserDefaultsRepository.alertSAGESound.value
  1361. row.displayValueFor = { value in
  1362. guard let value = value else { return nil }
  1363. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  1364. }
  1365. }.onChange { [weak self] row in
  1366. guard let value = row.value else { return }
  1367. UserDefaultsRepository.alertSAGESound.value = value
  1368. AlarmSound.setSoundFile(str: value)
  1369. AlarmSound.stop()
  1370. AlarmSound.playTest()
  1371. }
  1372. <<< DateTimeInlineRow("alertSAGESnoozedTime") { row in
  1373. row.title = "Snoozed Until"
  1374. row.hidden = "$alertSAGEActive == false"
  1375. if (UserDefaultsRepository.alertSAGESnoozedTime.value != nil) {
  1376. row.value = UserDefaultsRepository.alertSAGESnoozedTime.value
  1377. }
  1378. row.minuteInterval = 5
  1379. row.noValueDisplayText = "Not Snoozed"
  1380. }
  1381. .onChange { [weak self] row in
  1382. guard let value = row.value else { return }
  1383. UserDefaultsRepository.alertSAGESnoozedTime.value = value
  1384. UserDefaultsRepository.alertSAGEIsSnoozed.value = true
  1385. let otherRow = self?.form.rowBy(tag: "alertSAGEIsSnoozed") as! SwitchRow
  1386. otherRow.value = true
  1387. otherRow.reload()
  1388. }
  1389. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  1390. inlineRow.cellUpdate() { cell, row in
  1391. cell.datePicker.datePickerMode = .dateAndTime
  1392. }
  1393. let color = cell.detailTextLabel?.textColor
  1394. row.onCollapseInlineRow { cell, _, _ in
  1395. cell.detailTextLabel?.textColor = color
  1396. }
  1397. cell.detailTextLabel?.textColor = cell.tintColor
  1398. }
  1399. <<< SwitchRow("alertSAGEIsSnoozed"){ row in
  1400. row.title = "Is Snoozed"
  1401. row.value = UserDefaultsRepository.alertSAGEIsSnoozed.value
  1402. row.hidden = "$alertSAGEActive == false || $alertSAGESnoozedTime == nil"
  1403. }.onChange { [weak self] row in
  1404. guard let value = row.value else { return }
  1405. UserDefaultsRepository.alertSAGEIsSnoozed.value = value
  1406. if !value {
  1407. UserDefaultsRepository.alertSAGESnoozedTime.setNil(key: "alertSAGESnoozedTime")
  1408. let otherRow = self?.form.rowBy(tag: "alertSAGESnoozedTime") as! DateTimeInlineRow
  1409. otherRow.value = nil
  1410. otherRow.reload()
  1411. }
  1412. }
  1413. }
  1414. func buildCage(){
  1415. form
  1416. +++ Section(header: "Pump Change Reminder", footer: "Alert for Canula Change. Values are in Hours.")
  1417. <<< SwitchRow("alertCAGEActive"){ row in
  1418. row.title = "Active"
  1419. row.value = UserDefaultsRepository.alertCAGEActive.value
  1420. }.onChange { [weak self] row in
  1421. guard let value = row.value else { return }
  1422. UserDefaultsRepository.alertCAGEActive.value = value
  1423. }
  1424. <<< StepperRow("alertCAGE") { row in
  1425. row.title = "Time"
  1426. row.cell.stepper.stepValue = 1
  1427. row.cell.stepper.minimumValue = 1
  1428. row.cell.stepper.maximumValue = 24
  1429. row.value = Double(UserDefaultsRepository.alertCAGE.value)
  1430. row.hidden = "$alertCAGEActive == false"
  1431. row.displayValueFor = { value in
  1432. guard let value = value else { return nil }
  1433. return "\(Int(value))"
  1434. }
  1435. }.onChange { [weak self] row in
  1436. guard let value = row.value else { return }
  1437. UserDefaultsRepository.alertCAGE.value = Int(value)
  1438. }
  1439. <<< StepperRow("alertCAGESnooze") { row in
  1440. row.title = "Snooze"
  1441. row.cell.stepper.stepValue = 1
  1442. row.cell.stepper.minimumValue = 1
  1443. row.cell.stepper.maximumValue = 24
  1444. row.value = Double(UserDefaultsRepository.alertCAGESnooze.value)
  1445. row.hidden = "$alertCAGEActive == false"
  1446. row.displayValueFor = { value in
  1447. guard let value = value else { return nil }
  1448. return "\(Int(value))"
  1449. }
  1450. }.onChange { [weak self] row in
  1451. guard let value = row.value else { return }
  1452. UserDefaultsRepository.alertCAGESnooze.value = Int(value)
  1453. }
  1454. <<< PickerInputRow<String>("alertCAGESound") { row in
  1455. row.title = "Sound"
  1456. row.options = soundFiles
  1457. row.hidden = "$alertCAGEActive == false"
  1458. row.value = UserDefaultsRepository.alertCAGESound.value
  1459. row.displayValueFor = { value in
  1460. guard let value = value else { return nil }
  1461. return "\(String(value.replacingOccurrences(of: "_", with: " ")))"
  1462. }
  1463. }.onChange { [weak self] row in
  1464. guard let value = row.value else { return }
  1465. UserDefaultsRepository.alertCAGESound.value = value
  1466. AlarmSound.setSoundFile(str: value)
  1467. AlarmSound.stop()
  1468. AlarmSound.playTest()
  1469. }
  1470. <<< DateTimeInlineRow("alertCAGESnoozedTime") { row in
  1471. row.title = "Snoozed Until"
  1472. row.hidden = "$alertCAGEActive == false"
  1473. if (UserDefaultsRepository.alertCAGESnoozedTime.value != nil) {
  1474. row.value = UserDefaultsRepository.alertCAGESnoozedTime.value
  1475. }
  1476. row.minuteInterval = 5
  1477. row.noValueDisplayText = "Not Snoozed"
  1478. }
  1479. .onChange { [weak self] row in
  1480. guard let value = row.value else { return }
  1481. UserDefaultsRepository.alertCAGESnoozedTime.value = value
  1482. UserDefaultsRepository.alertCAGEIsSnoozed.value = true
  1483. let otherRow = self?.form.rowBy(tag: "alertCAGEIsSnoozed") as! SwitchRow
  1484. otherRow.value = true
  1485. otherRow.reload()
  1486. }
  1487. .onExpandInlineRow { [weak self] cell, row, inlineRow in
  1488. inlineRow.cellUpdate() { cell, row in
  1489. cell.datePicker.datePickerMode = .dateAndTime
  1490. }
  1491. let color = cell.detailTextLabel?.textColor
  1492. row.onCollapseInlineRow { cell, _, _ in
  1493. cell.detailTextLabel?.textColor = color
  1494. }
  1495. cell.detailTextLabel?.textColor = cell.tintColor
  1496. }
  1497. <<< SwitchRow("alertCAGEIsSnoozed"){ row in
  1498. row.title = "Is Snoozed"
  1499. row.value = UserDefaultsRepository.alertCAGEIsSnoozed.value
  1500. row.hidden = "$alertCAGEActive == false || $alertCAGESnoozedTime == nil"
  1501. }.onChange { [weak self] row in
  1502. guard let value = row.value else { return }
  1503. UserDefaultsRepository.alertCAGEIsSnoozed.value = value
  1504. if !value {
  1505. UserDefaultsRepository.alertCAGESnoozedTime.setNil(key: "alertCAGESnoozedTime")
  1506. let otherRow = self?.form.rowBy(tag: "alertCAGESnoozedTime") as! DateTimeInlineRow
  1507. otherRow.value = nil
  1508. otherRow.reload()
  1509. }
  1510. }
  1511. }
  1512. }