diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryField.swift index 6f69be43..734d39e8 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryField.swift @@ -7,19 +7,41 @@ // import UIKit +import VDS +open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol { + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + open var viewModel: ItemDropdownEntryFieldModel! + open var delegateObject: MVMCoreUIDelegateObject? + open var additionalData: [AnyHashable : Any]? + + // Form Validation + var fieldKey: String? + var fieldValue: JSONValue? + var groupName: String? + + open var pickerData: [String] = [] { + didSet { + options = pickerData.compactMap({ DropdownOptionModel(text: $0) }) + } + } -open class ItemDropdownEntryField: BaseItemPickerEntryField { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + public var isValid: Bool = false + + /// Closure passed here will run as picker changes items. + public var observeDropdownChange: ((String?, String) -> ())? - open var pickerData: [String] = [] - - public var itemDropdownEntryFieldModel: ItemDropdownEntryFieldModel? { - model as? ItemDropdownEntryFieldModel - } + /// Closure passed here will run upon dismissing the selection picker. + public var observeDropdownSelection: ((String) -> ())? + /// When selecting for first responder, allow initial selected value to appear in empty text field. + public var setInitialValueInTextField = true + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -28,7 +50,7 @@ open class ItemDropdownEntryField: BaseItemPickerEntryField { super.init(frame: frame) } - @objc public convenience init() { + @objc public convenience required init() { self.init(frame: .zero) } @@ -40,14 +62,36 @@ open class ItemDropdownEntryField: BaseItemPickerEntryField { @objc required public init?(coder: NSCoder) { fatalError("ItemDropdownEntryField init(coder:) has not been implemented") } - - required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - super.init(model: model, delegateObject, additionalData) - } - + //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- + open override func setup() { + super.setup() + publisher(for: .valueChanged) + .sink { [weak self] control in + guard let self, let selectedItem else { return } + viewModel.selectedIndex = control.selectId + observeDropdownSelection?(selectedItem.text) + if let valid = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) { + isValid = valid + } + }.store(in: &subscribers) + + dropdownField + .publisher(for: .editingDidBegin) + .sink { [weak self] textField in + guard let self else { return } + setInitialValueFromPicker() + }.store(in: &subscribers) + + dropdownField + .publisher(for: .editingDidEnd) + .sink { [weak self] textField in + guard let self else { return } + performDropdownAction() + }.store(in: &subscribers) + } /// Sets the textField with the first value of the available picker data. @objc private func setInitialValueFromPicker() { @@ -55,61 +99,36 @@ open class ItemDropdownEntryField: BaseItemPickerEntryField { guard !pickerData.isEmpty else { return } if setInitialValueInTextField { - let pickerIndex = pickerView.selectedRow(inComponent: 0) - itemDropdownEntryFieldModel?.selectedIndex = pickerIndex - observeDropdownChange?(text, pickerData[pickerIndex]) - text = pickerData[pickerIndex] + let pickerIndex = optionsPicker.selectedRow(inComponent: 0) + viewModel.selectedIndex = pickerIndex + selectId = pickerIndex + observeDropdownChange?(selectedItem?.text, pickerData[pickerIndex]) } } - @objc override func startEditing() { - super.startEditing() - - setInitialValueFromPicker() + public func viewModelDidUpdate() { + pickerData = viewModel.options + labelText = viewModel.title + helperText = viewModel.feedback + isEnabled = viewModel.enabled + isReadOnly = viewModel.readOnly + isRequired = viewModel.required + isSelected = viewModel.selected ?? false + tooltipModel = viewModel.tooltip?.toVDSTooltipModel() + if let index = viewModel.selectedIndex { + selectId = index + optionsPicker.selectRow(index, inComponent: 0, animated: false) + pickerView(optionsPicker, didSelectRow: index, inComponent: 0) + } + FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate) } - @objc override func endInputing() { - super.endInputing() - - guard !pickerData.isEmpty else { return } - - observeDropdownSelection?(pickerData[pickerView.selectedRow(inComponent: 0)]) - } - - public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - super.set(with: model, delegateObject, additionalData) - - guard let model = model as? ItemDropdownEntryFieldModel else { return } - - pickerData = model.options - - if let index = model.selectedIndex { - self.pickerView.selectRow(index, inComponent: 0, animated: false) - self.pickerView(pickerView, didSelectRow: index, inComponent: 0) - } + func performDropdownAction() { + guard let actionModel = viewModel.action, + !dropdownField.isFirstResponder + else { return } + MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: viewModel, additionalData: additionalData, delegateObject: delegateObject) } - //-------------------------------------------------- - // MARK: - Picker Delegate - //-------------------------------------------------- - - @objc public override func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 } - - @objc public override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - pickerData.count - } - - @objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { - guard !pickerData.isEmpty else { return nil } - - return pickerData[row] - } - - @objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { - guard !pickerData.isEmpty else { return } - - itemDropdownEntryFieldModel?.selectedIndex = row - observeDropdownChange?(text, pickerData[row]) - text = pickerData[row] - } + public func updateView(_ size: CGFloat) { } } diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryFieldModel.swift index 1c88ddab..131c2123 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/Item Dropdown/ItemDropdownEntryFieldModel.swift @@ -5,16 +5,18 @@ // Created by Kevin Christiano on 1/22/20. // Copyright © 2020 Verizon Wireless. All rights reserved. // +import VDS -@objcMembers open class ItemDropdownEntryFieldModel: BaseItemPickerEntryFieldModel { +@objcMembers open class ItemDropdownEntryFieldModel: TextEntryFieldModel { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public override class var identifier: String { "dropDown" } - + public var action: ActionModelProtocol? public var options: [String] = [] public var selectedIndex: Int? + public var tooltip: TooltipModel? public init(with options: [String], selectedIndex: Int? = nil) { self.options = options @@ -42,6 +44,8 @@ private enum CodingKeys: String, CodingKey { case options case selectedIndex + case action + case tooltip } //-------------------------------------------------- @@ -58,6 +62,8 @@ self.selectedIndex = selectedIndex baseValue = options.indices.contains(selectedIndex) ? options[selectedIndex] : nil } + action = try typeContainer.decodeModelIfPresent(codingKey: .action) + tooltip = try typeContainer.decodeIfPresent(TooltipModel.self, forKey: .tooltip) } public override func encode(to encoder: Encoder) throws { @@ -65,5 +71,7 @@ var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(options, forKey: .options) try container.encodeIfPresent(selectedIndex, forKey: .selectedIndex) + try container.encodeModelIfPresent(action, forKey: .action) + try container.encodeIfPresent(tooltip, forKey: .tooltip) } }