latest textfield development.

This commit is contained in:
Kevin G Christiano 2019-10-17 11:42:34 -04:00
parent d0264d45eb
commit d2fddaf769
6 changed files with 238 additions and 178 deletions

View File

@ -21,6 +21,8 @@
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; };
0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.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 */; }; 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 */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
0A8321C523563D3500CB7F00 /* MFTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24221E6A176003B2FB9 /* MFTextField.m */; }; 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, ); }; }; 0A8321C623563D3800CB7F00 /* MFTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24C21E6A177003B2FB9 /* MFTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -1109,6 +1111,7 @@
D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */,
DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */,
0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */,
0A52C1492357B5380051AECD /* MdnTextField.swift in Sources */,
0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */,
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */,
@ -1117,6 +1120,7 @@
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
0A52C14A2358B57E0051AECD /* DigitTextBox.swift in Sources */,
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */, B8200E192281DC1A007245F4 /* CornerLabels.swift in Sources */,
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,

View File

@ -8,7 +8,7 @@
import UIKit import UIKit
@objc protocol MFDigitTextBoxDelegate: NSObjectProtocol { @objc protocol DigitTextBoxDelegate: NSObjectProtocol {
@objc optional func textFieldDidDelete(_ textField: UITextField?) @objc optional func textFieldDidDelete(_ textField: UITextField?)
} }
@ -23,7 +23,7 @@ import UIKit
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
weak var mfTextBoxDelegate: MFDigitTextBoxDelegate? weak var textBoxDelegate: DigitTextBoxDelegate?
private var previousSize: CGFloat = 0.0 private var previousSize: CGFloat = 0.0
@ -85,18 +85,18 @@ import UIKit
override open func deleteBackward() { override open func deleteBackward() {
super.deleteBackward() super.deleteBackward()
if let delegate = mfTextBoxDelegate { textBoxDelegate?.textFieldDidDelete?(self)
delegate.textFieldDidDelete?(self)
}
} }
public func updateView(_ size: CGFloat) { public func updateView(_ size: CGFloat) {
DispatchQueue.main.async { DispatchQueue.main.async { [weak self] in
if !MVMCoreGetterUtility.fequal(a: Float(size), b: Float(self.previousSize)) { guard let wSelf = self else { return }
MFStyler.styleTextField(self)
self.font = MFFonts.mfFont55Rg(28) if !MVMCoreGetterUtility.fequal(a: Float(size), b: Float(wSelf.previousSize)) {
MFStyler.styleTextField(wSelf)
self?.font = MFFonts.mfFont55Rg(28)
var digitWidth: CGFloat = 0 var digitWidth: CGFloat = 0
var digitHeight: CGFloat = 0 var digitHeight: CGFloat = 0
@ -115,9 +115,9 @@ import UIKit
}) })
sizeObject?.performBlockBase(onSize: size) sizeObject?.performBlockBase(onSize: size)
self.widthConstraint?.constant = digitWidth self?.widthConstraint?.constant = digitWidth
self.heightConstraint?.constant = digitHeight self?.heightConstraint?.constant = digitHeight
self.previousSize = size self?.previousSize = size
} }
} }
} }
@ -130,6 +130,7 @@ import UIKit
} }
func hideError() { func hideError() {
layer.borderColor = UIColor.mfSilver().cgColor layer.borderColor = UIColor.mfSilver().cgColor
bottomBar?.setAsMedium() bottomBar?.setAsMedium()
} }

View File

@ -8,7 +8,8 @@
import UIKit import UIKit
@objcMembers open class DigitTextField: TextField, UITextFieldDelegate, MFDigitTextBoxDelegate {
@objcMembers open class DigitTextField: TextField, UITextFieldDelegate, DigitTextBoxDelegate {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Outlets // MARK: - Outlets
//-------------------------------------------------- //--------------------------------------------------
@ -21,6 +22,7 @@ import UIKit
private var numberOfDigits = 0 private var numberOfDigits = 0
private var switchedAutomatically = false private var switchedAutomatically = false
public var textFields: [DigitTextBox]?
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Constraints // MARK: - Constraints
@ -33,43 +35,49 @@ import UIKit
// MARK: - Initializers // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
func digitField() -> MFDigitTextBox? { required public init?(coder: NSCoder) {
let textField = MFDigitTextBox() super.init(coder: coder)
textField.delegate = self fatalError("init(coder:) has not been implemented")
textField.mfTextBoxDelegate = self
return textField
} }
class func withNumberOfDigits(_ numberOfDigits: Int) -> Self? { public init(dinumberOfDigits: Int) {
let field = self.mf() super.init(frame: .zero)
field?.numberOfDigits = numberOfDigits
field?.buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth()) numberOfDigits = dinumberOfDigits
return field buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth())
} }
class func withNumberOfDigits(_ numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) -> Self? { public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) {
let field = self.mfTextField(withBothDelegates: delegate) super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate))
field?.numberOfDigits = numberOfDigits
field?.buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth()) self.numberOfDigits = numberOfDigits
return field buildTextFieldsView(forSize: MVMCoreUISplitViewController.getDetailViewWidth())
} }
class func withNumberOfDigits(_ numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) -> Self? { public init(withNumberOfDigits numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) {
let field = self.mfTextField(withBothDelegates: delegate) super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
field?.numberOfDigits = numberOfDigits
field?.buildTextFieldsView(forSize: size) self.numberOfDigits = numberOfDigits
return field buildTextFieldsView(forSize: size)
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Methods // MARK: - Methods
//-------------------------------------------------- //--------------------------------------------------
func digitField() -> DigitTextBox? {
let textField = DigitTextBox()
textField.delegate = self
textField.textBoxDelegate = self
return textField
}
func buildTextFieldsView(forSize size: CGFloat) { func buildTextFieldsView(forSize size: CGFloat) {
// Remove all current UI. // Remove all current UI.
if let textFields = textFields, !textFields.isEmpt { if let textFields = textFields, !textFields.isEmpty {
StackableViewController.removeUIViews(self.textFields) StackableViewController.remove(textFields)
} }
if numberOfDigits > 0 { if numberOfDigits > 0 {
@ -85,9 +93,7 @@ import UIKit
textFields.append(textField) textFields.append(textField)
} }
} }
self.textFields = textFields as? [UITextField] self.textFields = textFields as? [DigitTextBox]
// Layout text boxes.
setupTextFieldsView(forSize: size) setupTextFieldsView(forSize: size)
} else { } else {
@ -97,11 +103,16 @@ import UIKit
func setupTextFieldsView(forSize size: CGFloat) { 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 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 { if self.textFields?.count == 1 {
inset.left = 0 inset.left = 0
@ -113,21 +124,67 @@ import UIKit
} else if (object as? UITextField) == self.textFields?.last { } else if (object as? UITextField) == self.textFields?.last {
inset.right = 0 inset.right = 0
} }
return inset return inset
}) })
} }
func valueChanged() { override func valueChanged() {
super.valueChanged() super.valueChanged()
DispatchQueue.main.async { DispatchQueue.main.async { [weak self] in
if self.label.text.length > 0 { if self.label.text.length > 0 {
self.labelToTextFieldPin.constant = 10 self?.labelToTextFieldPin?.constant = 10
} else { } 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
}
} }

View File

@ -118,8 +118,6 @@
}]; }];
} }
// CONTINUE
- (void)updateView:(CGFloat)size { - (void)updateView:(CGFloat)size {
[super updateView:size]; [super updateView:size];
[MVMCoreDispatchUtility performBlockOnMainThread:^{ [MVMCoreDispatchUtility performBlockOnMainThread:^{
@ -163,6 +161,8 @@
return 44; return 44;
} }
// CONTINUE
#pragma mark - Getters #pragma mark - Getters
- (NSString *)placeholder { - (NSString *)placeholder {

View File

@ -21,11 +21,23 @@ import MVMCore
public var isNationalMdn = false public var isNationalMdn = false
public var shouldValidateMDN = 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 // MARK: - Initializers
//-------------------------------------------------- //--------------------------------------------------
open override init(frame: CGRect) { public override init(frame: CGRect) {
super.init(frame: .zero) super.init(frame: .zero)
setup() setup()
} }
@ -34,7 +46,7 @@ import MVMCore
self.init(frame: .zero) self.init(frame: .zero)
} }
required init?(coder: NSCoder) { required public init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@ -58,7 +70,7 @@ import MVMCore
textField?.inputAccessoryView = toolbar 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? { public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
get { get {
return textField?.delegate return textField?.delegate
@ -79,16 +91,17 @@ import MVMCore
func hasValidMdn() -> Bool { 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 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 { func validateAndColor() -> Bool {
@ -114,18 +127,6 @@ import MVMCore
return nil 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?) { @objc func dismissFieldInput(_ sender: Any?) {
if let delegate = uiTextFieldDelegate { if let delegate = uiTextFieldDelegate {
@ -149,7 +150,7 @@ import MVMCore
// MARK: - ContactPicker Delegate // 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) { if contactProperty.value != nil && (contactProperty.value is CNPhoneNumber) {
@ -180,37 +181,29 @@ import MVMCore
//-------------------------------------------------- //--------------------------------------------------
@discardableResult @discardableResult
@objc func textFieldShouldReturn(_ textField: UITextField) -> Bool { @objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder() textField.resignFirstResponder()
if let customDelegate = customDelegate { return customDelegate?.textFieldShouldReturn?(textField) ?? true
return customDelegate.textFieldShouldReturn?(textField) ?? false
}
return 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) { if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
return false return false
} }
if let customDelegate = customDelegate { return customDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
return customDelegate.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
}
return true
} }
func textFieldDidBeginEditing(_ textField: UITextField) { public func textFieldDidBeginEditing(_ textField: UITextField) {
textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text) textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text)
customDelegate?.textFieldDidBeginEditing?(textField) customDelegate?.textFieldDidBeginEditing?(textField)
} }
func textFieldDidEndEditing(_ textField: UITextField) { public func textFieldDidEndEditing(_ textField: UITextField) {
customDelegate?.textFieldDidEndEditing?(textField) customDelegate?.textFieldDidEndEditing?(textField)
@ -223,30 +216,18 @@ import MVMCore
// MARK: - Passed Along TextField delegate // 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 customDelegate.textFieldShouldBeginEditing?(textField) ?? true
}
return true
} }
@objc func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { @objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if let customDelegate = customDelegate { return customDelegate?.textFieldShouldEndEditing?(textField) ?? true
return customDelegate.textFieldShouldEndEditing?(textField) ?? true
}
return true
} }
@objc func textFieldShouldClear(_ textField: UITextField) -> Bool { @objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
if let customDelegate = customDelegate { return customDelegate?.textFieldShouldClear?(textField) ?? true
return customDelegate.textFieldShouldClear?(textField) ?? true
}
return true
} }
} }

View File

@ -11,11 +11,11 @@ import UIKit
@objc public protocol TextFieldDelegate: NSObjectProtocol { @objc public protocol TextFieldDelegate: NSObjectProtocol {
/// Called when the entered text becomes valid based on the validation block /// 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 /// 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. /// Dismisses the keyboard.
@objc optional func dismissField(_ sender: Any?) @objc optional func dismissField(sender: Any?)
} }
@objcMembers open class TextField: ViewConstrainingView { @objcMembers open class TextField: ViewConstrainingView {
@ -31,6 +31,11 @@ import UIKit
public var placeholderErrorLabel: Label? public var placeholderErrorLabel: Label?
public var dashLine: DashLine? public var dashLine: DashLine?
public var dropDownCarrotLabel: UILabel? public var dropDownCarrotLabel: UILabel?
//--------------------------------------------------
// MARK: - Accessories
//--------------------------------------------------
public weak var datePicker: UIDatePicker? public weak var datePicker: UIDatePicker?
private(set) weak var toolbar: UIToolbar? 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? { public weak var uiTextFieldDelegate: UITextFieldDelegate? {
get { get {
return textField?.delegate return textField?.delegate
@ -69,14 +74,21 @@ import UIKit
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
private var borderPath: UIBezierPath?
private var calendar: Calendar? private var calendar: Calendar?
public var pickerView: UIPickerView? public var pickerView: UIPickerView?
public var observingForChanges = false public var observingForChanges = false
public var errorShowing = false public var showError = false
public var hasDropDown = false public var hasDropDown = false
public var enabled = true public var isEnabled = true
public var hideBorder = false
private var borderPath: UIBezierPath?
/// Determines if a border should be drawn.
public var hideBorder = false {
didSet {
setNeedsLayout()
}
}
public var text: String? { public var text: String? {
get { get {
@ -100,6 +112,7 @@ import UIKit
public var placeholderTextColor: UIColor = .black public var placeholderTextColor: UIColor = .black
/// Setgs placeholder text in the textField.
public var placeholder: String? { public var placeholder: String? {
get { get {
guard let attributedPlaceholder = textField?.attributedPlaceholder else { return nil } guard let attributedPlaceholder = textField?.attributedPlaceholder else { return nil }
@ -113,7 +126,7 @@ import UIKit
textField?.attributedPlaceholder = NSAttributedString(string: newPlaceholderText, attributes: [NSAttributedString.Key.foregroundColor: placeholderTextColor]) textField?.attributedPlaceholder = NSAttributedString(string: newPlaceholderText, attributes: [NSAttributedString.Key.foregroundColor: placeholderTextColor])
if !errorShowing { if !showError {
placeholderErrorLabel?.text = (textField?.text?.count ?? 0) > 0 ? newPlaceholderText : "" 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() let formatter = DateFormatter()
formatter.dateStyle = .medium formatter.dateStyle = .medium
@ -130,7 +143,7 @@ import UIKit
formatter.formatterBehavior = .default formatter.formatterBehavior = .default
return formatter return formatter
} }()
public var isValid = false public var isValid = false
public var fieldKey: String? public var fieldKey: String?
@ -143,27 +156,7 @@ import UIKit
public var enabledTextColor: UIColor? public var enabledTextColor: UIColor?
public var disabledTextColor: UIColor? public var disabledTextColor: UIColor?
public var errorMessage: String? { 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()
}
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Constraints // MARK: - Constraints
@ -190,33 +183,32 @@ import UIKit
public override init(frame: CGRect) { public override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setupView() setupView()
} }
required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("init(coder:) has not been implemented")
}
/// Basic initializer. /// Basic initializer.
public convenience init() { public convenience init() {
self.init(frame: .zero) 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. /// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
public convenience init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { public init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
self.init(frame: .zero) super.init(frame: .zero)
setupView()
setBothTextFieldDelegates(bothDelegates) setBothTextFieldDelegates(bothDelegates)
} }
/// - parameter hasDropDown: tbd /// - parameter hasDropDown: tbd
/// - parameter map: Dictionary of values to setup this TextField /// - parameter map: Dictionary of values to setup this TextField
/// - parameter bothDelegate: Sets both MF/UI Text Field Delegates. /// - parameter bothDelegate: Sets both MF/UI Text Field Delegates.
public convenience init(hasDropDown: Bool = false, map: [AnyHashable: Any]?, bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) { public init(hasDropDown: Bool = false, map: [AnyHashable: Any]?, bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
self.init(frame: .zero) super.init(frame: .zero)
setupView()
dropDownCarrotLabel?.isHidden = hasDropDown dropDownCarrotLabel?.isHidden = hasDropDown
self.hasDropDown = !hasDropDown self.hasDropDown = !hasDropDown
setWithMap(map, bothDelegates: bothDelegates) setWithMap(map, bothDelegates: bothDelegates)
@ -367,15 +359,14 @@ import UIKit
open override func updateView(_ size: CGFloat) { open override func updateView(_ size: CGFloat) {
super.updateView(size) super.updateView(size)
DispatchQueue.main.async { [weak self] in formLabel?.updateView(size)
placeholderErrorLabel?.font = MFStyler.fontForTextFieldUnderLabel()
self?.formLabel?.updateView(size) if let textField = textField {
self?.placeholderErrorLabel?.font = MFStyler.fontForTextFieldUnderLabel() MFStyler.styleTextField(textField)
if let textField = self?.textField {
MFStyler.styleTextField(textField)
}
self?.dashLine?.updateView(size)
} }
dashLine?.updateView(size)
layoutIfNeeded()
} }
deinit { 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?.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y + frame.size.height))
borderPath?.lineWidth = 1 borderPath?.lineWidth = 1
let strokeColor = errorShowing ? UIColor.mfPumpkin() : UIColor.mfSilver() let strokeColor = showError ? UIColor.mfPumpkin() : UIColor.mfSilver()
strokeColor.setStroke() strokeColor.setStroke()
borderPath?.stroke() borderPath?.stroke()
@ -428,7 +419,7 @@ import UIKit
if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) { if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string") text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
} else { } 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()) { if let calendar = calendar, calendar.isDate(fromDate, inSameDayAs: Date()) {
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string") text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
} else { } 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()) { if let calendar = calendar, calendar.isDate(pickedDate, inSameDayAs: Date()) {
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string") text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
} else { } else {
text = formatter?.string(from: pickedDate) text = formatter.string(from: pickedDate)
} }
} }
@ -476,13 +467,43 @@ import UIKit
// MARK: - Methods // 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() { public func hideError() {
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
self?.separatorHeightConstraint?.constant = 1 self?.separatorHeightConstraint?.constant = 1
self?.separatorView?.backgroundColor = .black self?.separatorView?.backgroundColor = .black
self?.layoutIfNeeded() self?.layoutIfNeeded()
self?.errorShowing = false self?.showError = false
self?.placeholderErrorLabel?.textColor = .black self?.placeholderErrorLabel?.textColor = .black
self?.placeholderErrorLabel?.text = "" self?.placeholderErrorLabel?.text = ""
self?.textField?.accessibilityValue = nil self?.textField?.accessibilityValue = nil
@ -517,6 +538,10 @@ import UIKit
self.errorMessage = errMessage self.errorMessage = errMessage
} }
if let hideBorder = map["hideBorder"] as? Bool {
self.hideBorder = hideBorder
}
// Key used to send text value to server // Key used to send text value to server
if let fieldKey = map[KeyFieldKey] as? String { if let fieldKey = map[KeyFieldKey] as? String {
self.fieldKey = fieldKey self.fieldKey = fieldKey
@ -595,7 +620,7 @@ import UIKit
public func isEnabled(_ enable: Bool) { public func isEnabled(_ enable: Bool) {
// Set outside the dispatch so that registerAnimations can know about it // Set outside the dispatch so that registerAnimations can know about it
enabled = enable isEnabled = enable
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
@ -607,7 +632,7 @@ import UIKit
self?.textField?.textColor = self?.enabledTextColor ?? .black self?.textField?.textColor = self?.enabledTextColor ?? .black
self?.formLabel?.textColor = UIColor.mfBattleshipGrey() self?.formLabel?.textColor = UIColor.mfBattleshipGrey()
self?.placeholderErrorLabel?.textColor = .black 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) self?.showDropDown(true)
} else { } else {
@ -640,7 +665,7 @@ import UIKit
func valueChanged() { func valueChanged() {
// Update label for placeholder // Update label for placeholder
if !errorShowing { if !showError {
placeholderErrorLabel?.text = "" placeholderErrorLabel?.text = ""
} }
@ -651,17 +676,17 @@ import UIKit
if previousValidity && !isValid { if previousValidity && !isValid {
if let errMessage = errorMessage { if let errMessage = errorMessage {
self.errorMessage = errMessage showErrorMessage(errMessage)
} }
if let mfTextFieldDelegate = mfTextFieldDelegate { if let mfTextFieldDelegate = mfTextFieldDelegate {
mfTextFieldDelegate.isInvalid?(self) mfTextFieldDelegate.isInvalid?(textfield: self)
} }
} else if !previousValidity && isValid { } else if !previousValidity && isValid {
hideError() hideError()
if let mfTextFieldDelegate = mfTextFieldDelegate { if let mfTextFieldDelegate = mfTextFieldDelegate {
mfTextFieldDelegate.isValid?(self) mfTextFieldDelegate.isValid?(textfield: self)
} }
} }
} }
@ -672,18 +697,14 @@ import UIKit
hideError() hideError()
separatorView?.backgroundColor = .black separatorView?.backgroundColor = .black
} else if let errMessage = errorMessage { } else if let errMessage = errorMessage {
self.errorMessage = errMessage showErrorMessage(errMessage)
} }
} }
func startEditing() { func startEditing() {
textField?.becomeFirstResponder() textField?.becomeFirstResponder()
showErrorDropdown(!showError)
if !errorShowing {
separatorView?.backgroundColor = .black
separatorHeightConstraint?.constant = 1
}
} }
class func getEnabledTextfields(_ textFieldToDetermine: [MFTextField]?) -> [AnyHashable]? { 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 return 76
} }
} }
@ -730,10 +751,6 @@ extension TextField {
// MARK: - Accessibility // MARK: - Accessibility
extension TextField { extension TextField {
// open override class func accessibilityElements() -> [Any]? {
// return [self.textField]
// }
func pushAccessibilityNotification() { func pushAccessibilityNotification() {
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in