InsulinSensitivityScalingTableViewCell.swift 6.7 KB

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