| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- //
- // GeneralSetingsViewController.swift
- // LoopFollow
- //
- // Created by Jose Paredes on 7/16/20.
- // Copyright © 2020 Jon Fawcett. All rights reserved.
- //
- import Foundation
- import Eureka
- import EventKit
- import EventKitUI
- class GeneralSettingsViewController: FormViewController {
-
- var appStateController: AppStateController?
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- if UserDefaultsRepository.forceDarkMode.value {
- overrideUserInterfaceStyle = .dark
- }
- buildGeneralSettings()
- // Register the GeneralSettingsViewController as an observer for the UIApplication.willEnterForegroundNotification, which will be triggered when the app enters the foreground. This helps ensure that the "Speak BG" switch in the General Settings is updated according to the current setting.
- NotificationCenter.default.addObserver(self, selector: #selector(handleAppWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
- }
-
- private func buildGeneralSettings() {
- form
- +++ Section("App Settings")
- <<< SwitchRow("appBadge"){ row in
- row.title = "Display App Badge"
- row.tag = "appBadge"
- row.value = UserDefaultsRepository.appBadge.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.appBadge.value = value
- // Force main screen update
- //guard let mainScreen = self?.tabBarController!.viewControllers?[0] as? MainViewController else { return }
- //mainScreen.nightscoutLoader(forceLoad: true)
-
- // set the appstate to indicate settings change and flags
- if let appState = self!.appStateController {
- appState.generalSettingsChanged = true
- appState.generalSettingsChanges |= GeneralSettingsChangeEnum.appBadgeChange.rawValue
- }
-
- }
- <<< SwitchRow("persistentNotification") { row in
- row.title = "Persistent Notification"
- row.value = UserDefaultsRepository.persistentNotification.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.persistentNotification.value = value
- }
-
- +++ Section("Display Settings")
- <<< SwitchRow("forceDarkMode") { row in
- row.title = "Force Dark Mode (Restart App)"
- row.value = UserDefaultsRepository.forceDarkMode.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.forceDarkMode.value = value
-
- }
- <<< SwitchRow("showStats") { row in
- row.title = "Display Stats"
- row.value = UserDefaultsRepository.showStats.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.showStats.value = value
-
- // set the appstate to indicate settings change and flags
- if let appState = self!.appStateController {
- appState.generalSettingsChanged = true
- appState.generalSettingsChanges |= GeneralSettingsChangeEnum.showStatsChange.rawValue
- }
- }
- <<< SwitchRow("useIFCC") { row in
- row.title = "Use IFCC A1C"
- row.value = UserDefaultsRepository.useIFCC.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.useIFCC.value = value
-
- // set the appstate to indicate settings change and flags
- if let appState = self!.appStateController {
- appState.generalSettingsChanged = true
- appState.generalSettingsChanges |= GeneralSettingsChangeEnum.useIFCCChange.rawValue
- }
- }
- <<< SwitchRow("showSmallGraph") { row in
- row.title = "Display Small Graph"
- row.value = UserDefaultsRepository.showSmallGraph.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.showSmallGraph.value = value
-
- // set the appstate to indicate settings change and flags
- if let appState = self!.appStateController {
- appState.generalSettingsChanged = true
- appState.generalSettingsChanges |= GeneralSettingsChangeEnum.showSmallGraphChange.rawValue
- }
- }
- <<< SwitchRow("colorBGText") { row in
- row.title = "Color Main BG Text"
- row.value = UserDefaultsRepository.colorBGText.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.colorBGText.value = value
- // Force main screen update
- //guard let mainScreen = self?.tabBarController!.viewControllers?[0] as? MainViewController else { return }
- //mainScreen.setBGTextColor()
-
- // set the appstate to indicate settings change and flags
- if let appState = self!.appStateController {
- appState.generalSettingsChanged = true
- appState.generalSettingsChanges |= GeneralSettingsChangeEnum.colorBGTextChange.rawValue
- }
- }
-
- <<< SwitchRow("screenlockSwitchState") { row in
- row.title = "Keep Screen Active"
- row.value = UserDefaultsRepository.screenlockSwitchState.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.screenlockSwitchState.value = value
- }
-
- <<< SwitchRow("showDisplayName") { row in
- row.title = "Show Display Name"
- row.value = UserDefaultsRepository.showDisplayName.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.showDisplayName.value = value
- if let appState = self!.appStateController {
- appState.generalSettingsChanged = true
- appState.generalSettingsChanges |= GeneralSettingsChangeEnum.showDisplayNameChange.rawValue
- }
- }
-
- +++ Section("Speak BG Settings")
- <<< SwitchRow("speakBG") { row in
- row.title = "Speak BG"
- row.value = UserDefaultsRepository.speakBG.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakBG.value = value
- self?.updateSpeakBGSettingsVisibility()
- }
-
- <<< PushRow<String>("speakLanguage") { row in
- row.title = "Speaking Language"
- row.options = ["en", "it", "sk", "sv"]
- row.value = UserDefaultsRepository.speakLanguage.value
- row.displayValueFor = { value in
- switch value {
- case "en": return "English"
- case "it": return "Italian"
- case "sk": return "Slovak"
- case "sv": return "Swedish"
- default: return "Unknown"
- }
- }
- row.hidden = Condition.function(["speakBG"], { form in
- let speakBGRow: SwitchRow! = form.rowBy(tag: "speakBG")
- return !(speakBGRow.value ?? false)
- })
- row.presentationMode = PresentationMode.presentModally(
- controllerProvider: ControllerProvider.callback {
- return SelectorViewController<SelectorRow<PushSelectorCell<String>>> { _ in }
- },
- onDismiss: { vc in
- vc.dismiss(animated: true)
- })
- }.onChange { row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakLanguage.value = value
- }
- <<< SwitchRow("speakBGAlways") { row in
- row.title = "Always"
- row.value = UserDefaultsRepository.speakBGAlways.value
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakBGAlways.value = value
- self?.updateSpeakBGSettingsVisibility()
- }
-
- <<< SwitchRow("speakLowBG") { row in
- row.title = "Low"
- row.value = UserDefaultsRepository.speakLowBG.value
- }.onChange { [weak self] row in
- self?.handleLowProactiveLowToggle(row: row, opposingRowTag: "speakProactiveLowBG")
- }
-
- <<< SwitchRow("speakProactiveLowBG") { row in
- row.title = "Proactive Low"
- row.value = UserDefaultsRepository.speakProactiveLowBG.value
- }.onChange { [weak self] row in
- self?.handleLowProactiveLowToggle(row: row, opposingRowTag: "speakLowBG")
- }
-
- <<< StepperRow("speakLowBGLimit") { row in
- row.title = "Low BG Limit"
- row.cell.stepper.stepValue = 1
- row.cell.stepper.minimumValue = 40
- row.cell.stepper.maximumValue = 108
- row.value = Double(UserDefaultsRepository.speakLowBGLimit.value)
- row.displayValueFor = { value in
- guard let value = value else { return nil }
- return Localizer.toDisplayUnits(String(value))
- }
- // Visibility depends on either 'speakLowBG' or 'speakProactiveLowBG' being true
- row.hidden = Condition.function(["speakLowBG", "speakProactiveLowBG", "speakBG", "speakBGAlways"], { form in
- let speakBGRow: SwitchRow! = form.rowBy(tag: "speakBG")
- let speakBGAlwaysRow: SwitchRow! = form.rowBy(tag: "speakBGAlways")
- let speakLowBGRow: SwitchRow! = form.rowBy(tag: "speakLowBG")
- let speakProactiveLowBGRow: SwitchRow! = form.rowBy(tag: "speakProactiveLowBG")
- return !(speakLowBGRow.value ?? false) && !(speakProactiveLowBGRow.value ?? false) || !(speakBGRow.value ?? true) || (speakBGAlwaysRow.value ?? false)
- })
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakLowBGLimit.value = Float(value)
- }
- <<< StepperRow("speakFastDropDelta") { row in
- row.title = "Fast Drop Delta"
- row.cell.stepper.stepValue = 1
- row.cell.stepper.minimumValue = 3
- row.cell.stepper.maximumValue = 20
- row.value = Double(UserDefaultsRepository.speakFastDropDelta.value)
- row.displayValueFor = { value in
- guard let value = value else { return nil }
- return Localizer.toDisplayUnits(String(value))
- }
- // Visibility depends on 'speakProactiveLowBG' being true
- row.hidden = Condition.function(["speakProactiveLowBG", "speakBG", "speakBGAlways"], { form in
- let speakBGRow: SwitchRow! = form.rowBy(tag: "speakBG")
- let speakBGAlwaysRow: SwitchRow! = form.rowBy(tag: "speakBGAlways")
- let speakProactiveLowBGRow: SwitchRow! = form.rowBy(tag: "speakProactiveLowBG")
- return !(speakProactiveLowBGRow.value ?? false) || !(speakBGRow.value ?? true) || (speakBGAlwaysRow.value ?? false)
- })
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakFastDropDelta.value = Float(value)
- }
-
- <<< SwitchRow("speakHighBG") { row in
- row.title = "High"
- row.value = UserDefaultsRepository.speakHighBG.value
- }.onChange { row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakHighBG.value = value
- }
-
- <<< StepperRow("speakHighBGLimit") { row in
- row.title = "High BG Limit"
- row.cell.stepper.stepValue = 1
- row.cell.stepper.minimumValue = 140
- row.cell.stepper.maximumValue = 300
- row.value = Double(UserDefaultsRepository.speakHighBGLimit.value)
- row.displayValueFor = { value in
- guard let value = value else { return nil }
- return Localizer.toDisplayUnits(String(value))
- }
- // Visibility depends on 'speakHighBG' or 'speakProactiveLowBG' being true
- row.hidden = Condition.function(["speakHighBG", "speakProactiveLowBG", "speakBG", "speakBGAlways"], { form in
- let speakBGRow: SwitchRow! = form.rowBy(tag: "speakBG")
- let speakBGAlwaysRow: SwitchRow! = form.rowBy(tag: "speakBGAlways")
- let speakHighBGRow: SwitchRow! = form.rowBy(tag: "speakHighBG")
- let speakProactiveLowBGRow: SwitchRow! = form.rowBy(tag: "speakProactiveLowBG")
- return !(speakHighBGRow.value ?? false) && !(speakProactiveLowBGRow.value ?? false) || !(speakBGRow.value ?? true) || (speakBGAlwaysRow.value ?? false)
- })
- }.onChange { [weak self] row in
- guard let value = row.value else { return }
- UserDefaultsRepository.speakHighBGLimit.value = Float(value)
- }
- +++ ButtonRow() {
- $0.title = "DONE"
- }.onCellSelection { (row, arg) in
- self.dismiss(animated:true, completion: nil)
- }
-
- // Call to update initial visibility based on current settings
- updateSpeakBGSettingsVisibility()
- }
-
- func updateSpeakBGSettingsVisibility() {
- let alwaysOn = UserDefaultsRepository.speakBGAlways.value
- let speakBGOn = UserDefaultsRepository.speakBG.value
-
- // Determine visibility for "Always", "Low", "Proactive Low", and "High" based on "Speak BG" and "Always"
- let shouldHideAlways = !speakBGOn
- let shouldHideSettings = alwaysOn || !speakBGOn
-
- form.rowBy(tag: "speakBGAlways")?.hidden = Condition(booleanLiteral: shouldHideAlways)
- form.rowBy(tag: "speakBGAlways")?.evaluateHidden()
-
- ["speakLowBG", "speakProactiveLowBG", "speakHighBG"].forEach { tag in
- if let row = form.rowBy(tag: tag) {
- row.hidden = Condition(booleanLiteral: shouldHideSettings)
- row.evaluateHidden()
- row.updateCell()
- }
- }
- }
-
- func handleLowProactiveLowToggle(row: BaseRow, opposingRowTag: String) {
- guard let switchRow = row as? SwitchRow, let value = switchRow.value else { return }
-
- // Update the UserDefaults value for the current row.
- if row.tag == "speakLowBG" {
- UserDefaultsRepository.speakLowBG.value = value
- } else if row.tag == "speakProactiveLowBG" {
- UserDefaultsRepository.speakProactiveLowBG.value = value
- }
-
- // If the current switch is being turned ON, turn the opposing switch OFF.
- if value {
- if let opposingRow = form.rowBy(tag: opposingRowTag) as? SwitchRow {
- opposingRow.value = false
- opposingRow.updateCell()
-
- // Update the UserDefaults value for the opposing row.
- if opposingRowTag == "speakLowBG" {
- UserDefaultsRepository.speakLowBG.value = false
- } else if opposingRowTag == "speakProactiveLowBG" {
- UserDefaultsRepository.speakProactiveLowBG.value = false
- }
- }
- }
- }
-
- // Update the "Speak BG" SwitchRow value in the General Settings when the app enters the foreground. This ensures that the switch reflects the current setting in UserDefaultsRepository, even if it was changed using the Home Screen Quick Action while the app was in the background.
- @objc func handleAppWillEnterForeground() {
- if let row = self.form.rowBy(tag: "speakBG") as? SwitchRow {
- row.value = UserDefaultsRepository.speakBG.value
- row.updateCell()
- }
- }
- deinit {
- NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
- }
- }
|