AlarmViewController.swift 70 KB

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