ChartsTableViewController.swift 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. //
  2. // ChartsTableViewController.swift
  3. // LoopKitUI
  4. //
  5. // Copyright © 2017 LoopKit Authors. All rights reserved.
  6. //
  7. import UIKit
  8. import HealthKit
  9. /// Abstract class providing boilerplate setup for chart-based table view controllers
  10. open class ChartsTableViewController: UITableViewController, UIGestureRecognizerDelegate {
  11. public var preferredGlucoseUnit: HKUnit?
  12. open override func viewDidLoad() {
  13. super.viewDidLoad()
  14. if let unit = preferredGlucoseUnit {
  15. self.charts.setGlucoseUnit(unit)
  16. }
  17. let gestureRecognizer = UILongPressGestureRecognizer()
  18. gestureRecognizer.delegate = self
  19. gestureRecognizer.minimumPressDuration = 0.3
  20. gestureRecognizer.addTarget(self, action: #selector(handlePan(_:)))
  21. charts.gestureRecognizer = gestureRecognizer
  22. NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] _ in
  23. guard let self = self else { return }
  24. if self.visible {
  25. DispatchQueue.main.async {
  26. self.reloadData()
  27. }
  28. }
  29. }
  30. }
  31. open override func didReceiveMemoryWarning() {
  32. super.didReceiveMemoryWarning()
  33. if !visible {
  34. charts.didReceiveMemoryWarning()
  35. }
  36. }
  37. open override func viewWillAppear(_ animated: Bool) {
  38. super.viewWillAppear(animated)
  39. visible = true
  40. }
  41. open override func viewWillDisappear(_ animated: Bool) {
  42. super.viewWillDisappear(animated)
  43. visible = false
  44. }
  45. open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
  46. super.viewWillTransition(to: size, with: coordinator)
  47. reloadData(animated: false)
  48. }
  49. open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
  50. super.traitCollectionDidChange(previousTraitCollection)
  51. charts.traitCollection = traitCollection
  52. }
  53. // MARK: - State
  54. // This function should only be called from the main thread
  55. public func unitPreferencesDidChange(to unit: HKUnit?) {
  56. if let unit = unit {
  57. self.charts.setGlucoseUnit(unit)
  58. self.glucoseUnitDidChange()
  59. }
  60. self.reloadData()
  61. }
  62. open func glucoseUnitDidChange() {
  63. // To override.
  64. }
  65. open func createChartsManager() -> ChartsManager {
  66. fatalError("Subclasses must implement \(#function)")
  67. }
  68. lazy public private(set) var charts = createChartsManager()
  69. // References to registered notification center observers
  70. public var notificationObservers: [Any] = []
  71. open var active: Bool = true {
  72. didSet {
  73. reloadData()
  74. }
  75. }
  76. public var visible = false {
  77. didSet {
  78. reloadData()
  79. }
  80. }
  81. // MARK: - Data loading
  82. /// Refetches all data and updates the views. Must be called on the main queue.
  83. ///
  84. /// - Parameters:
  85. /// - animated: Whether the updating should be animated if possible
  86. open func reloadData(animated: Bool = false) {
  87. }
  88. // MARK: - UIGestureRecognizer
  89. public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
  90. /// Only start the long-press recognition when it starts in a chart cell
  91. let point = gestureRecognizer.location(in: tableView)
  92. if let indexPath = tableView.indexPathForRow(at: point) {
  93. if let cell = tableView.cellForRow(at: indexPath), cell is ChartTableViewCell {
  94. return true
  95. }
  96. }
  97. return false
  98. }
  99. public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
  100. return true
  101. }
  102. @objc func handlePan(_ gestureRecognizer: UIGestureRecognizer) {
  103. switch gestureRecognizer.state {
  104. case .possible, .changed:
  105. // Follow your dreams!
  106. break
  107. case .began, .cancelled, .ended, .failed:
  108. for case let row as ChartTableViewCell in self.tableView.visibleCells {
  109. let forwards = gestureRecognizer.state == .began
  110. UIView.animate(withDuration: forwards ? 0.2 : 0.5, delay: forwards ? 0 : 1, animations: {
  111. let alpha: CGFloat = forwards ? 0 : 1
  112. row.titleLabel?.alpha = alpha
  113. row.subtitleLabel?.alpha = alpha
  114. })
  115. }
  116. @unknown default:
  117. break
  118. }
  119. }
  120. }
  121. fileprivate extension ChartsManager {
  122. func setGlucoseUnit(_ unit: HKUnit) {
  123. for case let chart as GlucoseChart in charts {
  124. chart.glucoseUnit = unit
  125. }
  126. }
  127. }