From d2fddaf769fa4a3c0211e8c4e73402e580733625 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 17 Oct 2019 11:42:34 -0400 Subject: [PATCH] latest textfield development. --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Atoms/TextFields/DigitTextBox.swift | 27 +-- .../Atoms/TextFields/DigitTextField.swift | 127 ++++++++++---- MVMCoreUI/Atoms/TextFields/MFDigitTextField.m | 4 +- MVMCoreUI/Atoms/TextFields/MdnTextField.swift | 89 ++++------ MVMCoreUI/Atoms/TextFields/TextField.swift | 165 ++++++++++-------- 6 files changed, 238 insertions(+), 178 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 67d0519a..7c1fac20 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextField.swift */; }; + 0A52C1492357B5380051AECD /* MdnTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321A72355062F00CB7F00 /* MdnTextField.swift */; }; + 0A52C14A2358B57E0051AECD /* DigitTextBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; 0A8321C523563D3500CB7F00 /* MFTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24221E6A176003B2FB9 /* MFTextField.m */; }; 0A8321C623563D3800CB7F00 /* MFTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24C21E6A177003B2FB9 /* MFTextField.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1109,6 +1111,7 @@ D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, + 0A52C1492357B5380051AECD /* MdnTextField.swift in Sources */, 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, @@ -1117,6 +1120,7 @@ D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, + 0A52C14A2358B57E0051AECD /* DigitTextBox.swift in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, diff --git a/MVMCoreUI/Atoms/TextFields/DigitTextBox.swift b/MVMCoreUI/Atoms/TextFields/DigitTextBox.swift index 9bed633c..30b2b16d 100644 --- a/MVMCoreUI/Atoms/TextFields/DigitTextBox.swift +++ b/MVMCoreUI/Atoms/TextFields/DigitTextBox.swift @@ -8,7 +8,7 @@ import UIKit -@objc protocol MFDigitTextBoxDelegate: NSObjectProtocol { +@objc protocol DigitTextBoxDelegate: NSObjectProtocol { @objc optional func textFieldDidDelete(_ textField: UITextField?) } @@ -23,7 +23,7 @@ import UIKit // MARK: - Properties //-------------------------------------------------- - weak var mfTextBoxDelegate: MFDigitTextBoxDelegate? + weak var textBoxDelegate: DigitTextBoxDelegate? private var previousSize: CGFloat = 0.0 @@ -85,18 +85,18 @@ import UIKit override open func deleteBackward() { super.deleteBackward() - - if let delegate = mfTextBoxDelegate { - delegate.textFieldDidDelete?(self) - } + + textBoxDelegate?.textFieldDidDelete?(self) } public func updateView(_ size: CGFloat) { - DispatchQueue.main.async { - if !MVMCoreGetterUtility.fequal(a: Float(size), b: Float(self.previousSize)) { - MFStyler.styleTextField(self) - self.font = MFFonts.mfFont55Rg(28) + DispatchQueue.main.async { [weak self] in + guard let wSelf = self else { return } + + if !MVMCoreGetterUtility.fequal(a: Float(size), b: Float(wSelf.previousSize)) { + MFStyler.styleTextField(wSelf) + self?.font = MFFonts.mfFont55Rg(28) var digitWidth: CGFloat = 0 var digitHeight: CGFloat = 0 @@ -115,9 +115,9 @@ import UIKit }) sizeObject?.performBlockBase(onSize: size) - self.widthConstraint?.constant = digitWidth - self.heightConstraint?.constant = digitHeight - self.previousSize = size + self?.widthConstraint?.constant = digitWidth + self?.heightConstraint?.constant = digitHeight + self?.previousSize = size } } } @@ -130,6 +130,7 @@ import UIKit } func hideError() { + layer.borderColor = UIColor.mfSilver().cgColor bottomBar?.setAsMedium() } diff --git a/MVMCoreUI/Atoms/TextFields/DigitTextField.swift b/MVMCoreUI/Atoms/TextFields/DigitTextField.swift index c2f5c290..7fff621d 100644 --- a/MVMCoreUI/Atoms/TextFields/DigitTextField.swift +++ b/MVMCoreUI/Atoms/TextFields/DigitTextField.swift @@ -8,7 +8,8 @@ import UIKit -@objcMembers open class DigitTextField: TextField, UITextFieldDelegate, MFDigitTextBoxDelegate { + +@objcMembers open class DigitTextField: TextField, UITextFieldDelegate, DigitTextBoxDelegate { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- @@ -21,6 +22,7 @@ import UIKit private var numberOfDigits = 0 private var switchedAutomatically = false + public var textFields: [DigitTextBox]? //-------------------------------------------------- // MARK: - Constraints @@ -33,43 +35,49 @@ import UIKit // MARK: - Initializers //-------------------------------------------------- - func digitField() -> MFDigitTextBox? { - let textField = MFDigitTextBox() - textField.delegate = self - textField.mfTextBoxDelegate = self - return textField + required public init?(coder: NSCoder) { + super.init(coder: coder) + fatalError("init(coder:) has not been implemented") } - - class func withNumberOfDigits(_ numberOfDigits: Int) -> Self? { - let field = self.mf() - field?.numberOfDigits = numberOfDigits - field?.buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth()) - return field + + public init(dinumberOfDigits: Int) { + super.init(frame: .zero) + + numberOfDigits = dinumberOfDigits + buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth()) } - - class func withNumberOfDigits(_ numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) -> Self? { - let field = self.mfTextField(withBothDelegates: delegate) - field?.numberOfDigits = numberOfDigits - field?.buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth()) - return field + + public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) { + super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate)) + + self.numberOfDigits = numberOfDigits + buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth()) } - - class func withNumberOfDigits(_ numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) -> Self? { - let field = self.mfTextField(withBothDelegates: delegate) - field?.numberOfDigits = numberOfDigits - field?.buildTextFieldsView(forSize: size) - return field + + public init(withNumberOfDigits numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) { + super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate)) + + self.numberOfDigits = numberOfDigits + buildTextFieldsView(forSize: size) } //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- + func digitField() -> DigitTextBox? { + + let textField = DigitTextBox() + textField.delegate = self + textField.textBoxDelegate = self + return textField + } + func buildTextFieldsView(forSize size: CGFloat) { // Remove all current UI. - if let textFields = textFields, !textFields.isEmpt { - StackableViewController.removeUIViews(self.textFields) + if let textFields = textFields, !textFields.isEmpty { + StackableViewController.remove(textFields) } if numberOfDigits > 0 { @@ -85,9 +93,7 @@ import UIKit textFields.append(textField) } } - self.textFields = textFields as? [UITextField] - - // Layout text boxes. + self.textFields = textFields as? [DigitTextBox] setupTextFieldsView(forSize: size) } else { @@ -97,11 +103,16 @@ import UIKit func setupTextFieldsView(forSize size: CGFloat) { - let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3).getValueBasedOnScreenSize() + + + guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(), + let textFieldsView = textFieldsView, + let textFields = textFields + else { return } StackableViewController.populateViewHorizontally(textFieldsView, withUIArray: textFields, withSpacingBlock: { object in - let inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space) + var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space) if self.textFields?.count == 1 { inset.left = 0 @@ -113,21 +124,67 @@ import UIKit } else if (object as? UITextField) == self.textFields?.last { inset.right = 0 } + return inset }) } - func valueChanged() { + override func valueChanged() { super.valueChanged() - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in if self.label.text.length > 0 { - self.labelToTextFieldPin.constant = 10 + self?.labelToTextFieldPin?.constant = 10 } else { - self.labelToTextFieldPin.constant = 0 + self?.labelToTextFieldPin?.constant = 0 } } } + + func updateView(_ size: CGFloat) { + super.updateView(size) + MVMCoreDispatchUtility.performBlock(onMainThread: { + self.formLabel.updateView(size) + + // Remove all current UI. + if (self.textFields?.count ?? 0) > 0 { + StackableViewController.removeUIViews(self.textFields) + } + + // Update text boxes. + for textField in self.textFields ?? [] { + guard let textField = textField as? MFDigitTextBox else { + continue + } + textField.updateView(size) + } + + // Layout text boxes. + self.setupTextFieldsView(forSize: size) + }) + } + + func setupView() { + super.setupView() + formLabel.styleB2(true) + self.formText = "" + alignCenterHorizontal() + } + + // MARK: - Molecule + func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + let digitsNumber = json?.optionalNumber(forKey: "digits") + let digits = digitsNumber != nil ? digitsNumber?.intValue ?? 0 : 4 + if digits != numberOfDigits { + numberOfDigits = digits + buildTextFieldsView(forSize: MVMCoreUIUtility.getWidth()) + } + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + } + + class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 44 + } } diff --git a/MVMCoreUI/Atoms/TextFields/MFDigitTextField.m b/MVMCoreUI/Atoms/TextFields/MFDigitTextField.m index dcc08512..3e00d6f5 100644 --- a/MVMCoreUI/Atoms/TextFields/MFDigitTextField.m +++ b/MVMCoreUI/Atoms/TextFields/MFDigitTextField.m @@ -118,8 +118,6 @@ }]; } -// CONTINUE - - (void)updateView:(CGFloat)size { [super updateView:size]; [MVMCoreDispatchUtility performBlockOnMainThread:^{ @@ -163,6 +161,8 @@ return 44; } +// CONTINUE + #pragma mark - Getters - (NSString *)placeholder { diff --git a/MVMCoreUI/Atoms/TextFields/MdnTextField.swift b/MVMCoreUI/Atoms/TextFields/MdnTextField.swift index 93ee73b7..35ab49d7 100644 --- a/MVMCoreUI/Atoms/TextFields/MdnTextField.swift +++ b/MVMCoreUI/Atoms/TextFields/MdnTextField.swift @@ -21,11 +21,23 @@ import MVMCore public var isNationalMdn = false public var shouldValidateMDN = false + public var mdn: String? { + get { + guard let text = text else { return nil } + + return MVMCoreUIUtility.removeMdnFormat(text) + } + set { + guard let MDN = newValue else { return } + text = MVMCoreUIUtility.formatMdn(MDN) + } + } + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- - open override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: .zero) setup() } @@ -34,7 +46,7 @@ import MVMCore self.init(frame: .zero) } - required init?(coder: NSCoder) { + required public init?(coder: NSCoder) { super.init(coder: coder) fatalError("init(coder:) has not been implemented") } @@ -58,7 +70,7 @@ import MVMCore textField?.inputAccessoryView = toolbar } - // If you're using a MFViewController, you must set this to it + // If you're using a MFViewController, you must set this to it. public override weak var uiTextFieldDelegate: UITextFieldDelegate? { get { return textField?.delegate @@ -79,16 +91,17 @@ import MVMCore func hasValidMdn() -> Bool { - guard let mdn = getMdn() else { return true } + guard let MDN = mdn else { return true } - if mdn.isEmpty { + if MDN.isEmpty { return true - - } else if isNationalMdn { - return MVMCoreUIUtility.validateMDNString(mdn) } - return MVMCoreUIUtility.validateInternationalMDNString(mdn) + if isNationalMdn { + return MVMCoreUIUtility.validateMDNString(MDN) + } + + return MVMCoreUIUtility.validateInternationalMDNString(MDN) } func validateAndColor() -> Bool { @@ -114,18 +127,6 @@ import MVMCore return nil } - func getMdn() -> String? { - - return MVMCoreUIUtility.removeMdnFormat(text! as String) - } - - func setMdn(_ mdn: String?) { - - guard let MDN = mdn else { return } - - text = MVMCoreUIUtility.formatMdn(MDN) - } - @objc func dismissFieldInput(_ sender: Any?) { if let delegate = uiTextFieldDelegate { @@ -149,7 +150,7 @@ import MVMCore // MARK: - ContactPicker Delegate //-------------------------------------------------- - func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) { + public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) { if contactProperty.value != nil && (contactProperty.value is CNPhoneNumber) { @@ -180,37 +181,29 @@ import MVMCore //-------------------------------------------------- @discardableResult - @objc func textFieldShouldReturn(_ textField: UITextField) -> Bool { + @objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() - if let customDelegate = customDelegate { - return customDelegate.textFieldShouldReturn?(textField) ?? false - } - - return true + return customDelegate?.textFieldShouldReturn?(textField) ?? true } - @objc func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + @objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) { return false } - if let customDelegate = customDelegate { - return customDelegate.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true - } - - return true + return customDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true } - func textFieldDidBeginEditing(_ textField: UITextField) { + public func textFieldDidBeginEditing(_ textField: UITextField) { textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text) customDelegate?.textFieldDidBeginEditing?(textField) } - func textFieldDidEndEditing(_ textField: UITextField) { + public func textFieldDidEndEditing(_ textField: UITextField) { customDelegate?.textFieldDidEndEditing?(textField) @@ -223,30 +216,18 @@ import MVMCore // MARK: - Passed Along TextField delegate //-------------------------------------------------- - @objc func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { + @objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { - if let customDelegate = customDelegate { - return customDelegate.textFieldShouldBeginEditing?(textField) ?? true - } - - return true + return customDelegate?.textFieldShouldBeginEditing?(textField) ?? true } - @objc func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { + @objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { - if let customDelegate = customDelegate { - return customDelegate.textFieldShouldEndEditing?(textField) ?? true - } - - return true + return customDelegate?.textFieldShouldEndEditing?(textField) ?? true } - @objc func textFieldShouldClear(_ textField: UITextField) -> Bool { + @objc public func textFieldShouldClear(_ textField: UITextField) -> Bool { - if let customDelegate = customDelegate { - return customDelegate.textFieldShouldClear?(textField) ?? true - } - - return true + return customDelegate?.textFieldShouldClear?(textField) ?? true } } diff --git a/MVMCoreUI/Atoms/TextFields/TextField.swift b/MVMCoreUI/Atoms/TextFields/TextField.swift index ad0de57d..ef22419b 100644 --- a/MVMCoreUI/Atoms/TextFields/TextField.swift +++ b/MVMCoreUI/Atoms/TextFields/TextField.swift @@ -11,11 +11,11 @@ import UIKit @objc public protocol TextFieldDelegate: NSObjectProtocol { /// Called when the entered text becomes valid based on the validation block - @objc optional func isValid(_ textfield: TextField?) + @objc optional func isValid(textfield: TextField?) /// Called when the entered text becomes invalid based on the validation block - @objc optional func isInvalid(_ textfield: TextField?) + @objc optional func isInvalid(textfield: TextField?) /// Dismisses the keyboard. - @objc optional func dismissField(_ sender: Any?) + @objc optional func dismissField(sender: Any?) } @objcMembers open class TextField: ViewConstrainingView { @@ -31,6 +31,11 @@ import UIKit public var placeholderErrorLabel: Label? public var dashLine: DashLine? public var dropDownCarrotLabel: UILabel? + + //-------------------------------------------------- + // MARK: - Accessories + //-------------------------------------------------- + public weak var datePicker: UIDatePicker? private(set) weak var toolbar: UIToolbar? @@ -55,7 +60,7 @@ import UIKit } } - // If you're using a MFViewController, you must set this to it + /// If you're using a MFViewController, you must set this to it public weak var uiTextFieldDelegate: UITextFieldDelegate? { get { return textField?.delegate @@ -69,14 +74,21 @@ import UIKit // MARK: - Properties //-------------------------------------------------- - private var borderPath: UIBezierPath? private var calendar: Calendar? public var pickerView: UIPickerView? public var observingForChanges = false - public var errorShowing = false + public var showError = false public var hasDropDown = false - public var enabled = true - public var hideBorder = false + public var isEnabled = true + + private var borderPath: UIBezierPath? + + /// Determines if a border should be drawn. + public var hideBorder = false { + didSet { + setNeedsLayout() + } + } public var text: String? { get { @@ -100,6 +112,7 @@ import UIKit public var placeholderTextColor: UIColor = .black + /// Setgs placeholder text in the textField. public var placeholder: String? { get { guard let attributedPlaceholder = textField?.attributedPlaceholder else { return nil } @@ -113,7 +126,7 @@ import UIKit textField?.attributedPlaceholder = NSAttributedString(string: newPlaceholderText, attributes: [NSAttributedString.Key.foregroundColor: placeholderTextColor]) - if !errorShowing { + if !showError { placeholderErrorLabel?.text = (textField?.text?.count ?? 0) > 0 ? newPlaceholderText : "" } @@ -121,7 +134,7 @@ import UIKit } } - public var formatter: DateFormatter? { + public var formatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .medium @@ -130,7 +143,7 @@ import UIKit formatter.formatterBehavior = .default return formatter - } + }() public var isValid = false public var fieldKey: String? @@ -143,27 +156,7 @@ import UIKit public var enabledTextColor: UIColor? public var disabledTextColor: UIColor? - public var errorMessage: String? { - didSet { - - guard enabled else { return } - - self.separatorHeightConstraint?.constant = 4 - self.errorShowing = true - self.separatorView?.backgroundColor = UIColor.mfPumpkin() - - if let errorMessage = self.errorMessage { - self.placeholderErrorLabel?.text = errorMessage - self.placeholderErrorLabel?.numberOfLines = 0 - self.textField?.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", self.textField?.text ?? "", errorMessage) - } - - DispatchQueue.main.async { - self.setNeedsDisplay() - self.layoutIfNeeded() - } - } - } + public var errorMessage: String? //-------------------------------------------------- // MARK: - Constraints @@ -190,33 +183,32 @@ import UIKit public override init(frame: CGRect) { super.init(frame: frame) - setupView() } - required public init?(coder: NSCoder) { - super.init(coder: coder) - fatalError("init(coder:) has not been implemented") - } - /// Basic initializer. public convenience init() { self.init(frame: .zero) } + required public init?(coder: NSCoder) { + super.init(coder: coder) + fatalError("init(coder:) has not been implemented") + } + /// - parameter bothDelegates: Sets both MF/UI Text Field Delegates. - public convenience init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { - self.init(frame: .zero) - + public init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { + super.init(frame: .zero) + setupView() setBothTextFieldDelegates(bothDelegates) } /// - parameter hasDropDown: tbd /// - parameter map: Dictionary of values to setup this TextField /// - parameter bothDelegate: Sets both MF/UI Text Field Delegates. - public convenience init(hasDropDown: Bool = false, map: [AnyHashable: Any]?, bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { - self.init(frame: .zero) - + public init(hasDropDown: Bool = false, map: [AnyHashable: Any]?, bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { + super.init(frame: .zero) + setupView() dropDownCarrotLabel?.isHidden = hasDropDown self.hasDropDown = !hasDropDown setWithMap(map, bothDelegates: bothDelegates) @@ -367,15 +359,14 @@ import UIKit open override func updateView(_ size: CGFloat) { super.updateView(size) - DispatchQueue.main.async { [weak self] in - - self?.formLabel?.updateView(size) - self?.placeholderErrorLabel?.font = MFStyler.fontForTextFieldUnderLabel() - if let textField = self?.textField { - MFStyler.styleTextField(textField) - } - self?.dashLine?.updateView(size) + formLabel?.updateView(size) + placeholderErrorLabel?.font = MFStyler.fontForTextFieldUnderLabel() + if let textField = textField { + MFStyler.styleTextField(textField) } + dashLine?.updateView(size) + + layoutIfNeeded() } deinit { @@ -397,7 +388,7 @@ import UIKit borderPath?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y + frame.size.height)) borderPath?.lineWidth = 1 - let strokeColor = errorShowing ? UIColor.mfPumpkin() : UIColor.mfSilver() + let strokeColor = showError ? UIColor.mfPumpkin() : UIColor.mfSilver() strokeColor.setStroke() borderPath?.stroke() @@ -428,7 +419,7 @@ import UIKit if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) { text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string") } else { - self.text = formatter?.string(from: fromDate) + self.text = formatter.string(from: fromDate) } } @@ -442,7 +433,7 @@ import UIKit if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) { text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string") } else { - text = formatter?.string(from: fromDate) + text = formatter.string(from: fromDate) } } @@ -459,7 +450,7 @@ import UIKit if let calendar = calendar, calendar.isDate(pickedDate, inSameDayAs: Date()) { text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string") } else { - text = formatter?.string(from: pickedDate) + text = formatter.string(from: pickedDate) } } @@ -476,13 +467,43 @@ import UIKit // MARK: - Methods //-------------------------------------------------- + func showErrorDropdown(_ show: Bool) { + + DispatchQueue.main.async { [weak self] in + + self?.showError = show + self?.separatorHeightConstraint?.constant = show ? 4 : 1 + self?.separatorView?.backgroundColor = show ? UIColor.mfPumpkin() : .black + self?.setNeedsDisplay() + self?.layoutIfNeeded() + } + } + + func showErrorMessage(_ errorMessage: String?) { + + guard isEnabled else { return } + + DispatchQueue.main.async { [weak self] in + + self?.separatorHeightConstraint?.constant = 4 + self?.showError = true + self?.separatorView?.backgroundColor = UIColor.mfPumpkin() + self?.placeholderErrorLabel?.text = errorMessage + self?.placeholderErrorLabel?.numberOfLines = 0 + self?.textField?.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", self?.textField?.text ?? "", self?.errorMessage ?? "") + self?.setNeedsDisplay() + self?.layoutIfNeeded() + self?.showErrorDropdown(self?.showError ?? false) + } + } + public func hideError() { DispatchQueue.main.async { [weak self] in self?.separatorHeightConstraint?.constant = 1 self?.separatorView?.backgroundColor = .black self?.layoutIfNeeded() - self?.errorShowing = false + self?.showError = false self?.placeholderErrorLabel?.textColor = .black self?.placeholderErrorLabel?.text = "" self?.textField?.accessibilityValue = nil @@ -517,6 +538,10 @@ import UIKit self.errorMessage = errMessage } + if let hideBorder = map["hideBorder"] as? Bool { + self.hideBorder = hideBorder + } + // Key used to send text value to server if let fieldKey = map[KeyFieldKey] as? String { self.fieldKey = fieldKey @@ -595,7 +620,7 @@ import UIKit public func isEnabled(_ enable: Bool) { // Set outside the dispatch so that registerAnimations can know about it - enabled = enable + isEnabled = enable DispatchQueue.main.async { [weak self] in @@ -607,7 +632,7 @@ import UIKit self?.textField?.textColor = self?.enabledTextColor ?? .black self?.formLabel?.textColor = UIColor.mfBattleshipGrey() self?.placeholderErrorLabel?.textColor = .black - self?.separatorView?.backgroundColor = (self?.errorShowing ?? false) ? UIColor.mfPumpkin() : .black + self?.separatorView?.backgroundColor = (self?.showError ?? false) ? UIColor.mfPumpkin() : .black self?.showDropDown(true) } else { @@ -640,7 +665,7 @@ import UIKit func valueChanged() { // Update label for placeholder - if !errorShowing { + if !showError { placeholderErrorLabel?.text = "" } @@ -651,17 +676,17 @@ import UIKit if previousValidity && !isValid { if let errMessage = errorMessage { - self.errorMessage = errMessage + showErrorMessage(errMessage) } if let mfTextFieldDelegate = mfTextFieldDelegate { - mfTextFieldDelegate.isInvalid?(self) + mfTextFieldDelegate.isInvalid?(textfield: self) } } else if !previousValidity && isValid { hideError() if let mfTextFieldDelegate = mfTextFieldDelegate { - mfTextFieldDelegate.isValid?(self) + mfTextFieldDelegate.isValid?(textfield: self) } } } @@ -672,18 +697,14 @@ import UIKit hideError() separatorView?.backgroundColor = .black } else if let errMessage = errorMessage { - self.errorMessage = errMessage + showErrorMessage(errMessage) } } func startEditing() { textField?.becomeFirstResponder() - - if !errorShowing { - separatorView?.backgroundColor = .black - separatorHeightConstraint?.constant = 1 - } + showErrorDropdown(!showError) } class func getEnabledTextfields(_ textFieldToDetermine: [MFTextField]?) -> [AnyHashable]? { @@ -722,7 +743,7 @@ extension TextField { } } - override open class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 76 } } @@ -730,10 +751,6 @@ extension TextField { // MARK: - Accessibility extension TextField { - // open override class func accessibilityElements() -> [Any]? { - // return [self.textField] - // } - func pushAccessibilityNotification() { DispatchQueue.main.async { [weak self] in