DoublePickerInputRow.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //
  2. // DoublePickerInputRow.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 DoublePickerInputCell<A, B> : _PickerInputCell<Tuple<A, B>> where A: Equatable, B: Equatable {
  11. private var pickerRow: _DoublePickerInputRow<A, B>! { return row as? _DoublePickerInputRow<A, B> }
  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. picker.selectRow(indexA, inComponent: 0, animated: true)
  23. picker.selectRow(indexB, inComponent: 1, animated: true)
  24. }
  25. }
  26. open override func numberOfComponents(in pickerView: UIPickerView) -> Int {
  27. return 2
  28. }
  29. open override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
  30. return component == 0 ? pickerRow.firstOptions().count : pickerRow.secondOptions(pickerRow.selectedFirst()).count
  31. }
  32. open override func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
  33. if component == 0 {
  34. return pickerRow.displayValueForFirstRow(pickerRow.firstOptions()[row])
  35. } else {
  36. return pickerRow.displayValueForSecondRow(pickerRow.secondOptions(pickerRow.selectedFirst())[row])
  37. }
  38. }
  39. open override func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
  40. if component == 0 {
  41. let a = pickerRow.firstOptions()[row]
  42. if let value = pickerRow.value {
  43. guard value.a != a else {
  44. return
  45. }
  46. if pickerRow.secondOptions(a).contains(value.b) {
  47. pickerRow.value = Tuple(a: a, b: value.b)
  48. pickerView.reloadComponent(1)
  49. update()
  50. return
  51. } else {
  52. pickerRow.value = Tuple(a: a, b: pickerRow.secondOptions(a)[0])
  53. }
  54. } else {
  55. pickerRow.value = Tuple(a: a, b: pickerRow.secondOptions(a)[0])
  56. }
  57. pickerView.reloadComponent(1)
  58. pickerView.selectRow(0, inComponent: 1, animated: true)
  59. } else {
  60. let a = pickerRow.selectedFirst()
  61. pickerRow.value = Tuple(a: a, b: pickerRow.secondOptions(a)[row])
  62. }
  63. update()
  64. }
  65. }
  66. open class _DoublePickerInputRow<A: Equatable, B: Equatable> : Row<DoublePickerInputCell<A, B>>, NoValueDisplayTextConformance {
  67. open var noValueDisplayText: String? = nil
  68. /// Options for first component. Will be called often so should be O(1)
  69. public var firstOptions: (() -> [A]) = {[]}
  70. /// Options for second component given the selected value from the first component. Will be called often so should be O(1)
  71. public var secondOptions: ((A) -> [B]) = {_ in []}
  72. /// Modify the displayed values for the first picker row.
  73. public var displayValueForFirstRow: ((A) -> (String)) = { a in return String(describing: a) }
  74. /// Modify the displayed values for the second picker row.
  75. public var displayValueForSecondRow: ((B) -> (String)) = { b in return String(describing: b) }
  76. required public init(tag: String?) {
  77. super.init(tag: tag)
  78. }
  79. func selectedFirst() -> A {
  80. return value?.a ?? firstOptions()[0]
  81. }
  82. }
  83. /// A generic row where the user can pick an option from a picker view displayed in the keyboard area
  84. public final class DoublePickerInputRow<A, B>: _DoublePickerInputRow<A, B>, RowType where A: Equatable, B: Equatable {
  85. required public init(tag: String?) {
  86. super.init(tag: tag)
  87. self.displayValueFor = { [weak self] tuple in
  88. guard let tuple = tuple else {
  89. return self?.noValueDisplayText
  90. }
  91. return String(describing: tuple.a) + ", " + String(describing: tuple.b)
  92. }
  93. }
  94. }