TriplePickerInputRow.swift 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //
  2. // TriplePickerInputRow.swift
  3. // Eureka
  4. //
  5. // Created by Mathias Claassen on 5/10/18.
  6. // Copyright © 2018 Xmartlabs. All rights reserved.
  7. //
  8. import Foundation
  9. import UIKit
  10. open class TriplePickerInputCell<A, B, C> : _PickerInputCell<Tuple3<A, B, C>> where A: Equatable, B: Equatable, C: Equatable {
  11. private var pickerRow: _TriplePickerInputRow<A, B, C>! { return row as? _TriplePickerInputRow<A, B, C> }
  12. public required init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  13. super.init(style: style, reuseIdentifier: reuseIdentifier)
  14. }
  15. required public init?(coder aDecoder: NSCoder) {
  16. super.init(coder: aDecoder)
  17. }
  18. open override func update() {
  19. super.update()
  20. if let selectedValue = pickerRow.value, let indexA = pickerRow.firstOptions().firstIndex(of: selectedValue.a),
  21. let indexB = pickerRow.secondOptions(selectedValue.a).firstIndex(of: selectedValue.b),
  22. let indexC = pickerRow.thirdOptions(selectedValue.a, selectedValue.b).firstIndex(of: selectedValue.c){
  23. picker.selectRow(indexA, inComponent: 0, animated: true)
  24. picker.selectRow(indexB, inComponent: 1, animated: true)
  25. picker.selectRow(indexC, inComponent: 2, animated: true)
  26. }
  27. }
  28. open override func numberOfComponents(in pickerView: UIPickerView) -> Int {
  29. return 3
  30. }
  31. open override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
  32. if component == 0 {
  33. return pickerRow.firstOptions().count
  34. } else if component == 1 {
  35. return pickerRow.secondOptions(pickerRow.selectedFirst()).count
  36. } else {
  37. return pickerRow.thirdOptions(pickerRow.selectedFirst(), pickerRow.selectedSecond()).count
  38. }
  39. }
  40. open override func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
  41. if component == 0 {
  42. return pickerRow.displayValueForFirstRow(pickerRow.firstOptions()[row])
  43. } else if component == 1 {
  44. return pickerRow.displayValueForSecondRow(pickerRow.secondOptions(pickerRow.selectedFirst())[row])
  45. } else {
  46. return pickerRow.displayValueForThirdRow(pickerRow.thirdOptions(pickerRow.selectedFirst(), pickerRow.selectedSecond())[row])
  47. }
  48. }
  49. open override func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
  50. if component == 0 {
  51. let a = pickerRow.firstOptions()[row]
  52. if let value = pickerRow.value {
  53. guard value.a != a else {
  54. return
  55. }
  56. let b: B = pickerRow.secondOptions(a).contains(value.b) ? value.b : pickerRow.secondOptions(a)[0]
  57. let c: C = pickerRow.thirdOptions(a, b).contains(value.c) ? value.c : pickerRow.thirdOptions(a, b)[0]
  58. pickerRow.value = Tuple3(a: a, b: b, c: c)
  59. pickerView.reloadComponent(1)
  60. pickerView.reloadComponent(2)
  61. if b != value.b {
  62. pickerView.selectRow(0, inComponent: 1, animated: true)
  63. }
  64. if c != value.c {
  65. pickerView.selectRow(0, inComponent: 2, animated: true)
  66. }
  67. } else {
  68. let b = pickerRow.secondOptions(a)[0]
  69. pickerRow.value = Tuple3(a: a, b: b, c: pickerRow.thirdOptions(a, b)[0])
  70. pickerView.reloadComponent(1)
  71. pickerView.reloadComponent(2)
  72. pickerView.selectRow(0, inComponent: 1, animated: true)
  73. pickerView.selectRow(0, inComponent: 2, animated: true)
  74. }
  75. } else if component == 1 {
  76. let a = pickerRow.selectedFirst()
  77. let b = pickerRow.secondOptions(a)[row]
  78. if let value = pickerRow.value {
  79. guard value.b != b else {
  80. return
  81. }
  82. if pickerRow.thirdOptions(a, b).contains(value.c) {
  83. pickerRow.value = Tuple3(a: a, b: b, c: value.c)
  84. pickerView.reloadComponent(2)
  85. update()
  86. return
  87. } else {
  88. pickerRow.value = Tuple3(a: a, b: b, c: pickerRow.thirdOptions(a, b)[0])
  89. }
  90. } else {
  91. pickerRow.value = Tuple3(a: a, b: b, c: pickerRow.thirdOptions(a, b)[0])
  92. }
  93. pickerView.reloadComponent(2)
  94. pickerView.selectRow(0, inComponent: 2, animated: true)
  95. } else {
  96. let a = pickerRow.selectedFirst()
  97. let b = pickerRow.selectedSecond()
  98. pickerRow.value = Tuple3(a: a, b: b, c: pickerRow.thirdOptions(a, b)[row])
  99. }
  100. update()
  101. }
  102. }
  103. open class _TriplePickerInputRow<A: Equatable, B: Equatable, C: Equatable> : Row<TriplePickerInputCell<A, B, C>>, NoValueDisplayTextConformance {
  104. open var noValueDisplayText: String? = nil
  105. /// Options for first component. Will be called often so should be O(1)
  106. public var firstOptions: (() -> [A]) = {[]}
  107. /// Options for second component given the selected value from the first component. Will be called often so should be O(1)
  108. public var secondOptions: ((A) -> [B]) = {_ in []}
  109. /// Options for third component given the selected value from the first and second components. Will be called often so should be O(1)
  110. public var thirdOptions: ((A, B) -> [C]) = {_, _ in []}
  111. /// Modify the displayed values for the first picker row.
  112. public var displayValueForFirstRow: ((A) -> (String)) = { a in return String(describing: a) }
  113. /// Modify the displayed values for the second picker row.
  114. public var displayValueForSecondRow: ((B) -> (String)) = { b in return String(describing: b) }
  115. /// Modify the displayed values for the third picker row.
  116. public var displayValueForThirdRow: ((C) -> (String)) = { c in return String(describing: c) }
  117. required public init(tag: String?) {
  118. super.init(tag: tag)
  119. }
  120. func selectedFirst() -> A {
  121. return value?.a ?? firstOptions()[0]
  122. }
  123. func selectedSecond() -> B {
  124. return value?.b ?? secondOptions(selectedFirst())[0]
  125. }
  126. }
  127. /// A generic row where the user can pick an option from a picker view displayed in the keyboard area
  128. public final class TriplePickerInputRow<A, B, C>: _TriplePickerInputRow<A, B, C>, RowType where A: Equatable, B: Equatable, C: Equatable {
  129. required public init(tag: String?) {
  130. super.init(tag: tag)
  131. self.displayValueFor = { [weak self] tuple in
  132. guard let tuple = tuple else {
  133. return self?.noValueDisplayText
  134. }
  135. return String(describing: tuple.a) + ", " + String(describing: tuple.b) + ", " + String(describing: tuple.c)
  136. }
  137. }
  138. }