Further development of Entry Field.

This commit is contained in:
Kevin G Christiano 2019-12-13 12:54:43 -05:00
parent 59008f87d0
commit 44ff5e9d3c
7 changed files with 86 additions and 69 deletions

View File

@ -22,7 +22,6 @@ import UIKit
return calendar return calendar
}() }()
// TODO: Pull this out into Styler or some class akin to it.
public var formatter: DateFormatter = { public var formatter: DateFormatter = {
let formatter = DateFormatter() let formatter = DateFormatter()
formatter.dateStyle = .medium formatter.dateStyle = .medium
@ -38,7 +37,6 @@ import UIKit
@objc public override init(frame: CGRect) { @objc public override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setup()
} }
@objc public convenience init() { @objc public convenience init() {
@ -58,7 +56,8 @@ import UIKit
// MARK: - Methods // MARK: - Methods
//-------------------------------------------------- //--------------------------------------------------
@objc private func setup() { public override func setupFieldContainerContent(_ container: UIView) {
super.setupFieldContainerContent(container)
datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField) datePicker = MVMCoreUICommonViewsUtility.addDatePicker(to: textField)
datePicker?.addTarget(self, action: #selector(pickerValueChanged), for: .valueChanged) datePicker?.addTarget(self, action: #selector(pickerValueChanged), for: .valueChanged)
@ -81,7 +80,7 @@ import UIKit
let pickedDate = datePicker?.date let pickedDate = datePicker?.date
setTextWith(date: pickedDate) setTextWith(date: pickedDate)
textField.resignFirstResponder() resignFirstResponder()
return pickedDate return pickedDate
} }

View File

@ -34,6 +34,9 @@ import UIKit
private var previousSize: CGFloat = 0.0 private var previousSize: CGFloat = 0.0
// Default dimensions of the DigitBox
static let size: CGSize = CGSize(width: 39, height: 44)
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Computed Properties // MARK: - Computed Properties
//-------------------------------------------------- //--------------------------------------------------
@ -97,7 +100,7 @@ import UIKit
guard constraints.isEmpty else { return } guard constraints.isEmpty else { return }
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .white backgroundColor = .clear
addSubview(digitField) addSubview(digitField)
digitField.delegate = self digitField.delegate = self
@ -112,9 +115,9 @@ import UIKit
digitField.centerYAnchor.constraint(equalTo: centerYAnchor), digitField.centerYAnchor.constraint(equalTo: centerYAnchor),
digitField.centerXAnchor.constraint(equalTo: centerXAnchor)]) digitField.centerXAnchor.constraint(equalTo: centerXAnchor)])
widthConstraint = widthAnchor.constraint(equalToConstant: 39) widthConstraint = widthAnchor.constraint(equalToConstant: DigitBox.size.width)
widthConstraint?.isActive = true widthConstraint?.isActive = true
heightConstraint = heightAnchor.constraint(equalToConstant: 44) heightConstraint = heightAnchor.constraint(equalToConstant: DigitBox.size.height)
heightConstraint?.isActive = true heightConstraint?.isActive = true
if let bottomBar = bottomBar { if let bottomBar = bottomBar {

View File

@ -105,7 +105,7 @@ import UIKit
} }
} }
} }
/// Sets the text of titleLabel /// Sets the text of titleLabel
public var title: String? { public var title: String? {
get { return titleLabel.text } get { return titleLabel.text }
@ -177,10 +177,10 @@ import UIKit
/// Initial configuration of class and view. /// Initial configuration of class and view.
@objc final public override func setupView() { @objc final public override func setupView() {
super.setupView()
guard subviews.isEmpty else { return } guard subviews.isEmpty else { return }
translatesAutoresizingMaskIntoConstraints = false
isAccessibilityElement = false isAccessibilityElement = false
setContentCompressionResistancePriority(.required, for: .vertical) setContentCompressionResistancePriority(.required, for: .vertical)
accessibilityElements = [titleLabel, feedbackLabel] accessibilityElements = [titleLabel, feedbackLabel]

View File

@ -97,23 +97,22 @@ import MVMCore
return MVMCoreUIUtility.validateInternationalMDNString(MDN) return MVMCoreUIUtility.validateInternationalMDNString(MDN)
} }
@objc public func validate() -> Bool { @objc public override func validateTextField() -> Bool {
if !shouldValidateMDN { guard !shouldValidateMDN else { return true }
let isValid = hasValidMDN()
let isValid = hasValidMDN()
if isValid {
showError = false
if isValid { } else {
showError = false errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
} else { showError = true
errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message") UIAccessibility.post(notification: .layoutChanged, argument: textField)
showError = true
UIAccessibility.post(notification: .layoutChanged, argument: textField)
}
return isValid
} }
return true return isValid
} }
@objc public func getContacts(_ sender: Any?) { @objc public func getContacts(_ sender: Any?) {
@ -183,7 +182,7 @@ import MVMCore
proprietorTextDelegate?.textFieldDidEndEditing?(textField) proprietorTextDelegate?.textFieldDidEndEditing?(textField)
if validate() && isNationalMDN { if validateTextField() && isNationalMDN {
textField.text = MVMCoreUIUtility.formatMdn(textField.text) textField.text = MVMCoreUIUtility.formatMdn(textField.text)
} }
} }

View File

@ -42,7 +42,13 @@ import UIKit
/// Set enabled and disabled colors to be utilized when setting this texfield's isEnabled property. /// Set enabled and disabled colors to be utilized when setting this texfield's isEnabled property.
public var textColor: (enabled: UIColor?, disabled: UIColor?) = (.black, .mfSilver()) public var textColor: (enabled: UIColor?, disabled: UIColor?) = (.black, .mfSilver())
public var observingForChange: Bool = false private var observingForChange: Bool = false
/// Validate on each entry in the textField. Default: false
public var validateEachCharacter: Bool = false
/// Validate when user resigns editing. Default: true
public var validateWhenDoneEditing: Bool = true
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Computed Properties // MARK: - Computed Properties
@ -75,7 +81,6 @@ import UIKit
get { return textField.text } get { return textField.text }
set { set {
textField.text = newValue textField.text = newValue
valueChanged()
} }
} }
@ -101,7 +106,7 @@ import UIKit
// MARK: - Delegate Properties // MARK: - Delegate Properties
//-------------------------------------------------- //--------------------------------------------------
/// The delegate and block for validation. Validates if the text that the user has entered is valid or not. Checked after each change if there is a delegate. /// The delegate and block for validation. Validates if the text that the user has entered.
public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? { public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? {
didSet { didSet {
if observingTextFieldDelegate != nil && !observingForChange { if observingTextFieldDelegate != nil && !observingForChange {
@ -193,33 +198,30 @@ import UIKit
// MARK: - Observing for Change (TextFieldDelegate) // MARK: - Observing for Change (TextFieldDelegate)
//-------------------------------------------------- //--------------------------------------------------
public func defaultValidationBlock() {
validationBlock = { enteredValue in
guard let enteredValue = enteredValue else { return false }
return enteredValue.count > 0
}
}
@discardableResult
@objc override open func resignFirstResponder() -> Bool { @objc override open func resignFirstResponder() -> Bool {
if validateWhenDoneEditing {
validateTextField()
}
textField.resignFirstResponder() textField.resignFirstResponder()
isSelected = false isSelected = false
return true return true
} }
@objc func dismissFieldInput(_ sender: Any?) { /// Validates the text of the entry field.
@discardableResult
_ = resignFirstResponder() @objc public func validateTextField() -> Bool {
}
public func defaultValidationBlock() {
validationBlock = { enteredValue in
return (enteredValue?.count ?? 0) > 0
}
}
/// Executes on UITextField.textDidChangeNotification
@objc func valueChanged() {
if !showError {
feedback = ""
}
// If validation not set, input will always be valid
isValid = validationBlock?(text) ?? true isValid = validationBlock?(text) ?? true
if !isValid { if !isValid {
@ -227,22 +229,10 @@ import UIKit
observingTextFieldDelegate?.isInvalid?(textfield: self) observingTextFieldDelegate?.isInvalid?(textfield: self)
} else if isValid { } else if isValid {
if showError == true {
showError = false
}
isSelected = true
observingTextFieldDelegate?.isValid?(textfield: self) observingTextFieldDelegate?.isValid?(textfield: self)
} }
}
/// Executes on UITextField.textDidEndEditingNotification
@objc func endInputing() {
if isValid { return isValid
showError = false
entryFieldContainer.bottomBar?.backgroundColor = UIColor.black.cgColor
}
} }
/// Executes on UITextField.textDidBeginEditingNotification /// Executes on UITextField.textDidBeginEditingNotification
@ -251,9 +241,33 @@ import UIKit
isSelected = true isSelected = true
textField.becomeFirstResponder() textField.becomeFirstResponder()
} }
/// Executes on UITextField.textDidChangeNotification (every character entry)
@objc func valueChanged() {
guard validateEachCharacter else { return }
validateTextField()
}
/// Executes on UITextField.textDidEndEditingNotification
@objc func endInputing() {
if isValid {
showError = false
entryFieldContainer.bottomBar?.backgroundColor = UIColor.black.cgColor
}
resignFirstResponder()
}
@objc func dismissFieldInput(_ sender: Any?) {
resignFirstResponder()
}
} }
// MARK: - Molecular // MARK: - MVMCoreUIMoleculeViewProtocol
extension TextEntryField { extension TextEntryField {
@objc open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @objc open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {

View File

@ -44,7 +44,7 @@ import UIKit
} }
} }
/// MARK:- MVMCoreViewProtocol // MARK:- MVMCoreViewProtocol
extension View: MVMCoreViewProtocol { extension View: MVMCoreViewProtocol {
open func updateView(_ size: CGFloat) {} open func updateView(_ size: CGFloat) {}
@ -56,7 +56,7 @@ extension View: MVMCoreViewProtocol {
} }
} }
/// MARK:- MVMCoreUIMoleculeViewProtocol // MARK:- MVMCoreUIMoleculeViewProtocol
extension View: MVMCoreUIMoleculeViewProtocol { extension View: MVMCoreUIMoleculeViewProtocol {
open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {

View File

@ -33,8 +33,9 @@ import UIKit
private(set) var fieldState: FieldState = .original { private(set) var fieldState: FieldState = .original {
didSet (oldState) { didSet (oldState) {
// Will not update if new state is the same as old. // Will not update if new state is the same as old.
guard fieldState != oldState else { return } if fieldState != oldState {
fieldState.setStateUI(for: self) fieldState.setStateUI(for: self)
}
} }
} }
@ -100,8 +101,8 @@ import UIKit
_isLocked = false _isLocked = false
_isEnabled = true _isEnabled = true
if selected && showError { if _showError {
fieldState = .selectedError fieldState = selected ? .selectedError : .error
} else { } else {
fieldState = selected ? .selected : .original fieldState = selected ? .selected : .original
} }
@ -174,6 +175,7 @@ import UIKit
_showError = false _showError = false
subviews.forEach { $0.removeFromSuperview() } subviews.forEach { $0.removeFromSuperview() }
borderPath.removeAllPoints()
} }
//-------------------------------------------------- //--------------------------------------------------
@ -277,10 +279,10 @@ import UIKit
layoutIfNeeded() layoutIfNeeded()
} }
} }
}
//--------------------------------------------------
// MARK: - Molecular // MARK:- MVMCoreUIMoleculeViewProtocol
//-------------------------------------------------- extension EntryFieldContainer {
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)