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 51504dc8..ad38f476 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 @@ -27,11 +27,13 @@ open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol, options = pickerData.compactMap({ DropdownOptionModel(text: $0) }) } } + + private var isEditting: Bool = false //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public var isValid: Bool = false + public var isValid: Bool = true /// Closure passed here will run as picker changes items. public var observeDropdownChange: ((String?, String) -> ())? @@ -42,6 +44,12 @@ open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol, /// When selecting for first responder, allow initial selected value to appear in empty text field. public var setInitialValueInTextField = true + open override var errorText: String? { + get { + viewModel.dynamicErrorMessage ?? viewModel.errorMessage + } + set {} + } //-------------------------------------------------- // MARK: - Delegate Properties //-------------------------------------------------- @@ -90,15 +98,14 @@ open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol, 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) + _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) + }.store(in: &subscribers) dropdownField .publisher(for: .editingDidBegin) .sink { [weak self] textField in guard let self else { return } + isEditting = true setInitialValueFromPicker() }.store(in: &subscribers) @@ -106,12 +113,76 @@ open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol, .publisher(for: .editingDidEnd) .sink { [weak self] textField in guard let self else { return } + isEditting = false + _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) + if let valid = viewModel.isValid { + updateValidation(valid) + } performDropdownAction() }.store(in: &subscribers) } + public func viewModelDidUpdate() { + pickerData = viewModel.options + labelText = viewModel.title + helperText = viewModel.feedback + isEnabled = viewModel.enabled + isReadOnly = viewModel.readOnly + isRequired = viewModel.required + tooltipModel = viewModel.tooltip?.toVDSTooltipModel() + + if let index = viewModel.selectedIndex { + selectId = index + optionsPicker.selectRow(index, inComponent: 0, animated: false) + pickerView(optionsPicker, didSelectRow: index, inComponent: 0) + } + + if (viewModel.selected ?? false) && !viewModel.wasInitiallySelected { + + viewModel.wasInitiallySelected = true + isEditting = true + } + + FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate) + if isEditting { + DispatchQueue.main.async { + _ = self.becomeFirstResponder() + } + } + + viewModel.updateUI = { + MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in + guard let self = self else { return } + + if isEditting { + updateValidation(viewModel.isValid ?? true) + + } else if viewModel.isValid ?? true && showError { + showError = false + } + isEnabled = viewModel.enabled + }) + } + + viewModel.updateUIDynamicError = { + MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in + guard let self = self else { return } + + let validState = viewModel.isValid ?? false + if !validState && viewModel.shouldClearText { + selectId = nil + viewModel.shouldClearText = false + } + updateValidation(validState) + }) + } + + } + + public func updateView(_ size: CGFloat) { } + /// Sets the textField with the first value of the available picker data. - @objc private func setInitialValueFromPicker() { + private func setInitialValueFromPicker() { guard !pickerData.isEmpty else { return } @@ -123,29 +194,21 @@ open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol, } } - 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) - } - - func performDropdownAction() { + private func performDropdownAction() { guard let actionModel = viewModel.action, !dropdownField.isFirstResponder else { return } MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: viewModel, additionalData: additionalData, delegateObject: delegateObject) } - - public func updateView(_ size: CGFloat) { } + + private func updateValidation(_ isValid: Bool) { + let previousValidity = self.isValid + self.isValid = isValid + + if previousValidity && !isValid { + showError = true + } else if (!previousValidity && isValid) { + showError = false + } + } }