InsulinSensitivityScalingTableViewCell.swift 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. //
  2. // InsulinSensitivityScalingTableViewCell.swift
  3. // LoopKitUI
  4. //
  5. // Created by Michael Pangburn on 3/22/19.
  6. // Copyright © 2019 LoopKit Authors. All rights reserved.
  7. //
  8. import UIKit
  9. protocol InsulinSensitivityScalingTableViewCellDelegate: AnyObject {
  10. func insulinSensitivityScalingTableViewCellDidUpdateScaleFactor(_ cell: InsulinSensitivityScalingTableViewCell)
  11. }
  12. final class InsulinSensitivityScalingTableViewCell: UITableViewCell {
  13. private let allScaleFactorPercentages = Array(stride(from: 10, through: 200, by: 10))
  14. @IBOutlet private weak var titleLabel: UILabel!
  15. @IBOutlet private weak var valueLabel: UILabel!
  16. @IBOutlet weak var gaugeBar: SegmentedGaugeBarView! {
  17. didSet {
  18. if #available(iOSApplicationExtension 13.0, *) {
  19. gaugeBar.backgroundColor = .systemGray6
  20. } else {
  21. gaugeBar.backgroundColor = .white
  22. }
  23. }
  24. }
  25. @IBOutlet private weak var scaleFactorPicker: UIPickerView! {
  26. didSet {
  27. scaleFactorPicker.dataSource = self
  28. scaleFactorPicker.delegate = self
  29. }
  30. }
  31. @IBOutlet private weak var scaleFactorPickerHeightConstraint: NSLayoutConstraint! {
  32. didSet {
  33. pickerExpandedHeight = scaleFactorPickerHeightConstraint.constant
  34. }
  35. }
  36. private var pickerExpandedHeight: CGFloat = 0
  37. @IBOutlet private weak var footerLabel: UILabel!
  38. private lazy var percentFormatter: NumberFormatter = {
  39. let formatter = NumberFormatter()
  40. formatter.numberStyle = .percent
  41. formatter.maximumFractionDigits = 0
  42. return formatter
  43. }()
  44. var isPickerHidden: Bool {
  45. get {
  46. return scaleFactorPicker.isHidden
  47. }
  48. set {
  49. scaleFactorPicker.isHidden = newValue
  50. scaleFactorPickerHeightConstraint.constant = newValue ? 0 : pickerExpandedHeight
  51. if !newValue {
  52. guard let selectedRow = allScaleFactorPercentages.firstIndex(of: selectedPercentage) else {
  53. fatalError("selectedPercentage should always be validated against all possible scale factors")
  54. }
  55. scaleFactorPicker.selectRow(selectedRow, inComponent: 0, animated: false)
  56. }
  57. }
  58. }
  59. private var selectedPercentage = 100 {
  60. didSet {
  61. gaugeBar.progress = Double(self.selectedPercentage) / 100
  62. valueLabel.text = percentageString(from: selectedPercentage)
  63. updateFooterLabel()
  64. delegate?.insulinSensitivityScalingTableViewCellDidUpdateScaleFactor(self)
  65. }
  66. }
  67. var scaleFactor: Double {
  68. get {
  69. return Double(selectedPercentage) / 100
  70. }
  71. set {
  72. let percentage = Int(round(newValue * 100))
  73. .clamped(to: allScaleFactorPercentages.first!...allScaleFactorPercentages.last!)
  74. if allScaleFactorPercentages.contains(percentage) {
  75. selectedPercentage = percentage
  76. } else {
  77. // Truncate to nearest valid percentage
  78. selectedPercentage = allScaleFactorPercentages
  79. .adjacentPairs()
  80. .first(where: { lower, upper in
  81. (lower..<upper).contains(percentage)
  82. })?.0 ?? 100
  83. }
  84. }
  85. }
  86. weak var delegate: InsulinSensitivityScalingTableViewCellDelegate?
  87. override func awakeFromNib() {
  88. super.awakeFromNib()
  89. titleLabel.text = NSLocalizedString("Overall Insulin Needs", comment: "The title text for the insulin sensitivity scaling setting")
  90. selectedPercentage = 100
  91. setSelected(true, animated: false)
  92. }
  93. override func setSelected(_ selected: Bool, animated: Bool) {
  94. // Save and reassign the background color to avoid propagated transparency during the animation.
  95. let gaugeBarBackgroundColor = gaugeBar.backgroundColor
  96. super.setSelected(selected, animated: animated)
  97. if selected {
  98. gaugeBar.backgroundColor = gaugeBarBackgroundColor
  99. isPickerHidden.toggle()
  100. }
  101. }
  102. override func setHighlighted(_ highlighted: Bool, animated: Bool) {
  103. // Save and reassign the background color to avoid propagated transparency during the animation.
  104. let gaugeBarBackgroundColor = gaugeBar.backgroundColor
  105. super.setHighlighted(highlighted, animated: animated)
  106. if highlighted {
  107. gaugeBar.backgroundColor = gaugeBarBackgroundColor
  108. }
  109. }
  110. private func updateFooterLabel() {
  111. let footerText: String
  112. let delta = selectedPercentage - 100
  113. if delta < 0 {
  114. footerText = String(
  115. format: NSLocalizedString("Basal, bolus, and correction insulin dose amounts are decreased by %@%%.", comment: "Describes a percentage decrease in overall insulin needs"),
  116. String(abs(delta))
  117. )
  118. } else if delta > 0 {
  119. footerText = String(
  120. format: NSLocalizedString("Basal, bolus, and correction insulin dose amounts are increased by %@%%.", comment: "Describes a percentage increase in overall insulin needs"),
  121. String(delta)
  122. )
  123. } else {
  124. footerText = NSLocalizedString("Basal, bolus, and correction insulin dose amounts are unaffected.", comment: "Describes a lack of change in overall insulin needs")
  125. }
  126. footerLabel.text = footerText
  127. }
  128. private func percentageString(from percentage: Int) -> String? {
  129. return percentFormatter.string(from: Double(percentage) / 100)
  130. }
  131. }
  132. extension InsulinSensitivityScalingTableViewCell: UIPickerViewDataSource {
  133. func numberOfComponents(in pickerView: UIPickerView) -> Int {
  134. return 1
  135. }
  136. func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
  137. return allScaleFactorPercentages.count
  138. }
  139. }
  140. extension InsulinSensitivityScalingTableViewCell: UIPickerViewDelegate {
  141. func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
  142. return percentageString(from: allScaleFactorPercentages[row])
  143. }
  144. func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
  145. selectedPercentage = allScaleFactorPercentages[row]
  146. }
  147. }
  148. extension InsulinSensitivityScalingTableViewCellDelegate where Self: UITableViewController {
  149. func collapseInsulinSensitivityScalingCells(excluding indexPath: IndexPath? = nil) {
  150. for case let cell as InsulinSensitivityScalingTableViewCell in tableView.visibleCells where tableView.indexPath(for: cell) != indexPath && !cell.isPickerHidden {
  151. cell.isPickerHidden = true
  152. }
  153. }
  154. }