Further development of Entry Field.
This commit is contained in:
parent
59008f87d0
commit
44ff5e9d3c
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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]
|
||||||
|
|||||||
@ -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()
|
|
||||||
|
|
||||||
if isValid {
|
let isValid = hasValidMDN()
|
||||||
showError = false
|
|
||||||
} else {
|
|
||||||
errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
|
|
||||||
showError = true
|
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: textField)
|
|
||||||
}
|
|
||||||
|
|
||||||
return isValid
|
if isValid {
|
||||||
|
showError = false
|
||||||
|
|
||||||
|
} else {
|
||||||
|
errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
|
||||||
|
showError = true
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: textField)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
@objc public func validateTextField() -> Bool {
|
||||||
|
|
||||||
_ = resignFirstResponder()
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
return isValid
|
||||||
@objc func endInputing() {
|
|
||||||
|
|
||||||
if 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]?) {
|
||||||
|
|||||||
@ -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]?) {
|
||||||
|
|||||||
@ -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:- MVMCoreUIMoleculeViewProtocol
|
||||||
// MARK: - Molecular
|
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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user