moar texht.
This commit is contained in:
parent
4742eace6b
commit
2ce41ad74b
@ -19,7 +19,7 @@
|
|||||||
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
01E569D3223FFFA500327251 /* ThreeLayerViewController.swift in Headers */ = {isa = PBXBuildFile; fileRef = D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||||
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; };
|
0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; };
|
||||||
0A21DB7F235DECC500C160A2 /* FieldEntryFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB7E235DECC500C160A2 /* FieldEntryFormView.swift */; };
|
0A21DB7F235DECC500C160A2 /* FormEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB7E235DECC500C160A2 /* FormEntryField.swift */; };
|
||||||
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */; };
|
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */; };
|
||||||
0A21DB84235E06EF00C160A2 /* MFTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24C21E6A177003B2FB9 /* MFTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
0A21DB84235E06EF00C160A2 /* MFTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF24C21E6A177003B2FB9 /* MFTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24221E6A176003B2FB9 /* MFTextField.m */; };
|
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24221E6A176003B2FB9 /* MFTextField.m */; };
|
||||||
@ -33,6 +33,7 @@
|
|||||||
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24821E6A177003B2FB9 /* MFDigitTextField.m */; };
|
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF24821E6A177003B2FB9 /* MFDigitTextField.m */; };
|
||||||
0A21DB8E235E06EF00C160A2 /* MFDigitTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = D29DF24A21E6A177003B2FB9 /* MFDigitTextField.xib */; };
|
0A21DB8E235E06EF00C160A2 /* MFDigitTextField.xib in Resources */ = {isa = PBXBuildFile; fileRef = D29DF24A21E6A177003B2FB9 /* MFDigitTextField.xib */; };
|
||||||
0A21DB91235E0EDB00C160A2 /* DigitTextBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */; };
|
0A21DB91235E0EDB00C160A2 /* DigitTextBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */; };
|
||||||
|
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB93235E24ED00C160A2 /* DigitEntryField.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 /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; };
|
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; };
|
||||||
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
|
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
|
||||||
@ -210,9 +211,10 @@
|
|||||||
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
01DF55DF21F8FAA800CC099B /* MFTextFieldListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MFTextFieldListView.swift; sourceTree = "<group>"; };
|
||||||
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
01DF566F21FA5AB300CC099B /* TextFieldListFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldListFormViewController.swift; sourceTree = "<group>"; };
|
||||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||||
0A21DB7E235DECC500C160A2 /* FieldEntryFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldEntryFormView.swift; sourceTree = "<group>"; };
|
0A21DB7E235DECC500C160A2 /* FormEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormEntryField.swift; sourceTree = "<group>"; };
|
||||||
0A21DB80235DF87300C160A2 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
0A21DB80235DF87300C160A2 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||||
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryField.swift; sourceTree = "<group>"; };
|
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryField.swift; sourceTree = "<group>"; };
|
||||||
|
0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitEntryField.swift; sourceTree = "<group>"; };
|
||||||
0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = "<group>"; };
|
0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = "<group>"; };
|
||||||
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
|
||||||
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
||||||
@ -764,9 +766,10 @@
|
|||||||
0A8321A72355062F00CB7F00 /* MdnTextField.swift */,
|
0A8321A72355062F00CB7F00 /* MdnTextField.swift */,
|
||||||
0A8321AC2355FC2600CB7F00 /* DigitTextField.swift */,
|
0A8321AC2355FC2600CB7F00 /* DigitTextField.swift */,
|
||||||
0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */,
|
0A8321AE2355FE9500CB7F00 /* DigitTextBox.swift */,
|
||||||
0A21DB7E235DECC500C160A2 /* FieldEntryFormView.swift */,
|
0A21DB7E235DECC500C160A2 /* FormEntryField.swift */,
|
||||||
0A21DB80235DF87300C160A2 /* TextField.swift */,
|
0A21DB80235DF87300C160A2 /* TextField.swift */,
|
||||||
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */,
|
0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */,
|
||||||
|
0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */,
|
||||||
);
|
);
|
||||||
path = TextFields;
|
path = TextFields;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1045,7 +1048,7 @@
|
|||||||
D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */,
|
D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */,
|
||||||
D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */,
|
D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */,
|
||||||
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
|
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
|
||||||
0A21DB7F235DECC500C160A2 /* FieldEntryFormView.swift in Sources */,
|
0A21DB7F235DECC500C160A2 /* FormEntryField.swift in Sources */,
|
||||||
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */,
|
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */,
|
||||||
D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */,
|
D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */,
|
||||||
D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */,
|
D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */,
|
||||||
@ -1112,6 +1115,7 @@
|
|||||||
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */,
|
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */,
|
||||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
||||||
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
|
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
|
||||||
|
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */,
|
||||||
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */,
|
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */,
|
||||||
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
|
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
|
||||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
|
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
|
||||||
|
|||||||
528
MVMCoreUI/Atoms/TextFields/DigitEntryField.swift
Normal file
528
MVMCoreUI/Atoms/TextFields/DigitEntryField.swift
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
//
|
||||||
|
// DigitEntryField.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 10/21/19.
|
||||||
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
class DigitEntryField: TextEntryField, UITextFieldDelegate, DigitTextBoxDelegate {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private weak var digitFieldsView: UIView?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private var numberOfDigits = 0
|
||||||
|
private var switchedAutomatically = false
|
||||||
|
public var digitFields: [DigitTextBox]?
|
||||||
|
|
||||||
|
/// Setgs placeholder text in the textField.
|
||||||
|
public override var placeholder: String? {
|
||||||
|
get {
|
||||||
|
var string = ""
|
||||||
|
|
||||||
|
for digitField in digitFields ?? [] {
|
||||||
|
if let placeholderText = digitField.attributedPlaceholder?.string {
|
||||||
|
string += placeholderText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !string.isEmpty ? string : nil
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
guard let placeholderValue = newValue else { return }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||||
|
|
||||||
|
if idx < (newValue?.count ?? 0) {
|
||||||
|
|
||||||
|
let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
||||||
|
obj.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
|
||||||
|
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()])
|
||||||
|
} else if stop != nil {
|
||||||
|
stop = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is already text in the textfield, set the place holder label below.
|
||||||
|
if placeholderErrorLabel.length > 0 && !showError {
|
||||||
|
placeholderErrorLabel.text = newValue
|
||||||
|
|
||||||
|
} else if !showError {
|
||||||
|
placeholderErrorLabel.text = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if label.text.length > 0 {
|
||||||
|
labelToTextFieldPin?.constant = 10
|
||||||
|
} else {
|
||||||
|
labelToTextFieldPin?.constant = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// adding missing accessibilityLabel value
|
||||||
|
// if we have some value in accessibilityLabel,
|
||||||
|
// then only can append regular and picker item
|
||||||
|
textField.accessibilityLabel() = newValue ?? "" + (MVMCoreUIUtility.hardcodedString(withKey: "mfdigittextfield_regular"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var text: String? {
|
||||||
|
get {
|
||||||
|
var string = ""
|
||||||
|
|
||||||
|
for digitField in digitFields ?? [] {
|
||||||
|
if let digitText = digitField.text {
|
||||||
|
string += digitText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
(digitFields as NSArray?)?.enumerateObjects( { obj, idx, stop in
|
||||||
|
|
||||||
|
if idx < (text?.count ?? 0) {
|
||||||
|
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
||||||
|
obj.text = stringForIndex
|
||||||
|
} else if stop != nil {
|
||||||
|
stop = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
valueChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var formText: String? {
|
||||||
|
get {
|
||||||
|
return formDescriptionLabel?.text
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if let formText = newValue, !formText.isEmpty > 0 {
|
||||||
|
messageToTextFieldPin?.constant = 10
|
||||||
|
} else {
|
||||||
|
messageToTextFieldPin?.constant = 0
|
||||||
|
}
|
||||||
|
super.formText = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private weak var messageToTextFieldPin: NSLayoutConstraint?
|
||||||
|
private weak var labelToTextFieldPin: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
required public init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(numberOfDigits: Int) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
self.numberOfDigits = numberOfDigits
|
||||||
|
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||||
|
super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate))
|
||||||
|
|
||||||
|
self.numberOfDigits = numberOfDigits
|
||||||
|
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(withNumberOfDigits numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) {
|
||||||
|
super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
||||||
|
|
||||||
|
self.numberOfDigits = numberOfDigits
|
||||||
|
buildTextFieldsView(size: size)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setupFieldContainerContent(_ container: UIView) {
|
||||||
|
|
||||||
|
setupTextFieldsView(forSize: numberOfDigits)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func createDigitField() -> DigitTextBox {
|
||||||
|
|
||||||
|
let textField = DigitTextBox()
|
||||||
|
textField.delegate = self
|
||||||
|
textField.textBoxDelegate = self
|
||||||
|
|
||||||
|
return textField
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildTextFieldsView(size: CGFloat) {
|
||||||
|
|
||||||
|
// Remove all current UI.
|
||||||
|
if let digitFields = digitFields, !digitFields.isEmpty {
|
||||||
|
StackableViewController.remove(digitFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
if numberOfDigits > 0 {
|
||||||
|
|
||||||
|
let digitFields = [DigitTextBox](repeating: createDigitField(), count: numberOfDigits)
|
||||||
|
|
||||||
|
for digitField in digitFields {
|
||||||
|
digitField.updateView(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.digitFields = digitFields
|
||||||
|
setupTextFieldsView(forSize: size)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
digitFields = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func valueChanged() {
|
||||||
|
super.valueChanged()
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
if let placeholder = self.placeholder, !placeholder.isEmpty {
|
||||||
|
self.labelToTextFieldPin?.constant = 10
|
||||||
|
|
||||||
|
} else {
|
||||||
|
self.labelToTextFieldPin?.constant = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.formDescriptionLabel?.updateView(size)
|
||||||
|
|
||||||
|
if let digitFields = self.digitFields, !digitFields.isEmpty {
|
||||||
|
|
||||||
|
// Remove all current UI.
|
||||||
|
StackableViewController.remove(digitFields)
|
||||||
|
|
||||||
|
// Update text boxes.
|
||||||
|
for digitField in digitFields {
|
||||||
|
digitField.updateView(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout text boxes.
|
||||||
|
self.setupTextFieldsView(forSize: size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
formDescriptionLabel?.styleB2(true)
|
||||||
|
self.formText = ""
|
||||||
|
alignCenterHorizontal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTextFieldsView(forSize size: CGFloat) {
|
||||||
|
|
||||||
|
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
||||||
|
let digitFieldsView = digitFieldsView,
|
||||||
|
let digitFields = digitFields
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
StackableViewController.populateViewHorizontally(digitFieldsView, withUIArray: digitFields, withSpacingBlock: { object in
|
||||||
|
|
||||||
|
var inset = UIEdgeInsets(top: 0, left: space, bottom: 0, right: space)
|
||||||
|
|
||||||
|
guard let digitFields = self.digitFields else { return inset }
|
||||||
|
|
||||||
|
if digitFields.count == 1 {
|
||||||
|
inset.left = 0
|
||||||
|
inset.right = 0
|
||||||
|
|
||||||
|
} else if let field = object as? UITextField, field == digitFields.first {
|
||||||
|
inset.left = 0
|
||||||
|
|
||||||
|
} else if let field = object as? UITextField, field == digitFields.last {
|
||||||
|
inset.right = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return inset
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Molecule
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
|
|
||||||
|
guard let dictionary = json else { return }
|
||||||
|
|
||||||
|
let digits = dictionary["digits"] as? Int ?? 4
|
||||||
|
if digits != numberOfDigits {
|
||||||
|
numberOfDigits = digits
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
||||||
|
|
||||||
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
|
||||||
|
return 44
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Setters
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func setAsSecureTextEntry(_ secureEntry: Bool) {
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
(self.digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||||
|
obj.isSecureTextEntry = secureEntry
|
||||||
|
|
||||||
|
//accessibility - 33704 fix voice over will read what pin user is filling
|
||||||
|
obj.accessibilityLabel() = String(format: "PIN %lu of %lu", UInt(idx) + 1, UInt(self.digitFields?.count ?? 0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func showErrorMessage(_ errorMessage: String?) {
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
super.showErrorMessage (errorMessage)
|
||||||
|
|
||||||
|
if self.showError {
|
||||||
|
self.labelToTextFieldPin?.constant = 10
|
||||||
|
}
|
||||||
|
for field in self.digitFields ?? [] {
|
||||||
|
field.setAsError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func hideError() {
|
||||||
|
super.hideError()
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
for field in self.digitFields ?? [] {
|
||||||
|
field.hideError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setWithMap(_ map: [AnyHashable : Any]?, bothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||||
|
super.setWithMap(map, bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
||||||
|
|
||||||
|
if (map?.count ?? 0) > 0 {
|
||||||
|
for textField in digitFields ?? [] {
|
||||||
|
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefaultValidationBlock() {
|
||||||
|
|
||||||
|
weak var weakSelf = self
|
||||||
|
|
||||||
|
self.validationBlock = { enteredValue in
|
||||||
|
if (enteredValue?.count ?? 0) > 0 && (enteredValue?.count ?? 0) == weakSelf?.digitFields?.count {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func enable(_ enable: Bool) {
|
||||||
|
super.enable(enable)
|
||||||
|
|
||||||
|
if enable {
|
||||||
|
formDescriptionLabel?.styleB2(true)
|
||||||
|
} else {
|
||||||
|
formDescriptionLabel?.textColor = UIColor.mfBattleshipGrey()
|
||||||
|
}
|
||||||
|
|
||||||
|
for textField in digitFields ?? [] {
|
||||||
|
textField.isUserInteractionEnabled = enable
|
||||||
|
textField.isEnabled = enable
|
||||||
|
|
||||||
|
if enable {
|
||||||
|
textField.textColor = UIColor.black
|
||||||
|
} else {
|
||||||
|
textField.textColor = UIColor.mfBattleshipGrey()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Helpers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func selectPreviousTextField(_ currentTextField: UITextField?, clear: Bool) {
|
||||||
|
|
||||||
|
var selectNextField = false
|
||||||
|
|
||||||
|
(digitFields as NSArray?)?.enumerateObjects(options: .reverse, using: { obj, idx, stop in
|
||||||
|
if obj == currentTextField {
|
||||||
|
selectNextField = true
|
||||||
|
} else if selectNextField {
|
||||||
|
if !clear {
|
||||||
|
self.switchedAutomatically = true
|
||||||
|
}
|
||||||
|
obj.becomeFirstResponder()
|
||||||
|
self.switchedAutomatically = false
|
||||||
|
stop = true
|
||||||
|
|
||||||
|
//accessibility
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectNextTextField(_ currentTextField: UITextField?, clear: Bool) {
|
||||||
|
|
||||||
|
var selectNextField = false
|
||||||
|
(digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
||||||
|
|
||||||
|
if obj == currentTextField {
|
||||||
|
selectNextField = true
|
||||||
|
|
||||||
|
} else if selectNextField {
|
||||||
|
if !clear {
|
||||||
|
self.switchedAutomatically = true
|
||||||
|
}
|
||||||
|
obj.becomeFirstResponder()
|
||||||
|
self.switchedAutomatically = false
|
||||||
|
stop = true
|
||||||
|
|
||||||
|
//accessibility
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Accessinility
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override var accessibilityElements: [Any]? {
|
||||||
|
|
||||||
|
if let digitFields = self.digitFields {
|
||||||
|
return [digitFields] //return [self.digitFields arrayByAddingObject:(DigitTextBox *)self.label];
|
||||||
|
} else {
|
||||||
|
return [placeholder]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - TextFieldDelegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
textField.resignFirstResponder()
|
||||||
|
|
||||||
|
return uiTextFieldDelegate?.textFieldShouldReturn?(textField) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
|
|
||||||
|
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textField.text?.count ?? 0) >= range.length + range.location {
|
||||||
|
|
||||||
|
let oldLength = textField.text?.count ?? 0
|
||||||
|
let replacementLength = string.count
|
||||||
|
if replacementLength > 1 {
|
||||||
|
|
||||||
|
// Too long (Check with AKQA if they want to allow pasting the digits.
|
||||||
|
return false
|
||||||
|
} else if replacementLength == 1 && (oldLength == 1 || oldLength == 0) {
|
||||||
|
|
||||||
|
// One character, switch old value with new, select next textfield
|
||||||
|
textField.text = string
|
||||||
|
selectNextTextField(textField, clear: false)
|
||||||
|
valueChanged()
|
||||||
|
return false
|
||||||
|
} else if replacementLength == 0 && oldLength == 1 {
|
||||||
|
// non empty cell, clear and stay.
|
||||||
|
textField.text = ""
|
||||||
|
valueChanged()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func textFieldDidDelete(_ textField: UITextField?) {
|
||||||
|
|
||||||
|
// empty cell, go back to previous cell and clear.
|
||||||
|
selectPreviousTextField(textField, clear: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
|
|
||||||
|
if !switchedAutomatically {
|
||||||
|
textField.text = ""
|
||||||
|
valueChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
uiTextFieldDelegate?.textFieldDidBeginEditing?(textField)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||||
|
|
||||||
|
|
||||||
|
uiTextFieldDelegate?.textFieldDidEndEditing?(textField)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
selectPreviousTextField(textField, clear: false)
|
||||||
|
|
||||||
|
return uiTextFieldDelegate?.textFieldShouldClear?(textField) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Passed Along TextField delegate
|
||||||
|
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
return uiTextFieldDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
return uiTextFieldDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -151,10 +151,6 @@ import UIKit
|
|||||||
buildTextFieldsView(size: size)
|
buildTextFieldsView(size: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setup() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// FieldEntryForm.swift
|
// FormEntryField.swift
|
||||||
// MVMCoreUI
|
// MVMCoreUI
|
||||||
//
|
//
|
||||||
// Created by Kevin Christiano on 10/21/19.
|
// Created by Kevin Christiano on 10/21/19.
|
||||||
@ -13,7 +13,7 @@ import UIKit
|
|||||||
* This class is intended to be subclassed by a class that will add views subclassed under UIControl.
|
* This class is intended to be subclassed by a class that will add views subclassed under UIControl.
|
||||||
* The FieldEntryForm provides the base logic for the description label, placeholder/error label and field container.
|
* The FieldEntryForm provides the base logic for the description label, placeholder/error label and field container.
|
||||||
*/
|
*/
|
||||||
@objcMembers open class FieldEntryFormView: ViewConstrainingView {
|
@objcMembers open class FormEntryField: ViewConstrainingView {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -203,7 +203,7 @@ import UIKit
|
|||||||
/// Method to override.
|
/// Method to override.
|
||||||
/// Intended to add the interactive content (textField) to the fieldContainer.
|
/// Intended to add the interactive content (textField) to the fieldContainer.
|
||||||
open func setupFieldContainerContent(_ container: UIView) {
|
open func setupFieldContainerContent(_ container: UIView) {
|
||||||
|
// To Be Overridden
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration logic for the text container view.
|
/// Configuration logic for the text container view.
|
||||||
@ -288,12 +288,13 @@ import UIKit
|
|||||||
open func showErrorDropdown(_ show: Bool) {
|
open func showErrorDropdown(_ show: Bool) {
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
self?.showError = show
|
self.showError = show
|
||||||
self?.separatorHeightConstraint?.constant = show ? 4 : 1
|
self.separatorHeightConstraint?.constant = show ? 4 : 1
|
||||||
self?.separatorView?.backgroundColor = show ? UIColor.mfPumpkin() : .black
|
self.separatorView?.backgroundColor = show ? UIColor.mfPumpkin() : .black
|
||||||
self?.setNeedsDisplay()
|
self.setNeedsDisplay()
|
||||||
self?.layoutIfNeeded()
|
self.layoutIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,29 +303,32 @@ import UIKit
|
|||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
self?.separatorHeightConstraint?.constant = 4
|
self.separatorHeightConstraint?.constant = 4
|
||||||
self?.showError = true
|
self.showError = true
|
||||||
self?.separatorView?.backgroundColor = UIColor.mfPumpkin()
|
self.separatorView?.backgroundColor = UIColor.mfPumpkin()
|
||||||
self?.placeholderErrorLabel?.text = errorMessage
|
self.placeholderErrorLabel?.text = errorMessage
|
||||||
self?.placeholderErrorLabel?.numberOfLines = 0
|
self.placeholderErrorLabel?.numberOfLines = 0
|
||||||
self?.setNeedsDisplay()
|
self.setNeedsDisplay()
|
||||||
self?.layoutIfNeeded()
|
self.layoutIfNeeded()
|
||||||
self?.showErrorDropdown(self?.showError ?? false)
|
self.showErrorDropdown(self.showError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open func hideError() {
|
open func hideError() {
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.separatorHeightConstraint?.constant = 1
|
guard let self = self else { return }
|
||||||
self?.separatorView?.backgroundColor = .black
|
|
||||||
self?.layoutIfNeeded()
|
self.separatorHeightConstraint?.constant = 1
|
||||||
self?.showError = false
|
self.separatorView?.backgroundColor = .black
|
||||||
self?.placeholderErrorLabel?.textColor = .black
|
self.layoutIfNeeded()
|
||||||
self?.placeholderErrorLabel?.text = ""
|
self.showError = false
|
||||||
self?.setNeedsDisplay()
|
self.placeholderErrorLabel?.textColor = .black
|
||||||
self?.layoutIfNeeded()
|
self.placeholderErrorLabel?.text = ""
|
||||||
|
self.setNeedsDisplay()
|
||||||
|
self.layoutIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,11 +388,13 @@ import UIKit
|
|||||||
isEnabled = true
|
isEnabled = true
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.isUserInteractionEnabled = true
|
guard let self = self else { return }
|
||||||
self?.formDescriptionLabel?.textColor = UIColor.mfBattleshipGrey()
|
|
||||||
self?.placeholderErrorLabel?.textColor = .black
|
self.isUserInteractionEnabled = true
|
||||||
self?.separatorView?.backgroundColor = (self?.showError ?? false) ? UIColor.mfPumpkin() : .black
|
self.formDescriptionLabel?.textColor = UIColor.mfBattleshipGrey()
|
||||||
self?.showDropDown(true)
|
self.placeholderErrorLabel?.textColor = .black
|
||||||
|
self.separatorView?.backgroundColor = (self.showError) ? UIColor.mfPumpkin() : .black
|
||||||
|
self.showDropDown(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,12 +404,14 @@ import UIKit
|
|||||||
isEnabled = false
|
isEnabled = false
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.isUserInteractionEnabled = false
|
guard let self = self else { return }
|
||||||
self?.formDescriptionLabel?.textColor = UIColor.mfSilver()
|
|
||||||
self?.placeholderErrorLabel?.textColor = UIColor.mfSilver()
|
self.isUserInteractionEnabled = false
|
||||||
self?.showDropDown(false)
|
self.formDescriptionLabel?.textColor = UIColor.mfSilver()
|
||||||
self?.hideError() // Should not have error if the field is disabled
|
self.placeholderErrorLabel?.textColor = UIColor.mfSilver()
|
||||||
self?.separatorView?.backgroundColor = UIColor.mfSilver()
|
self.showDropDown(false)
|
||||||
|
self.hideError() // Should not have error if the field is disabled
|
||||||
|
self.separatorView?.backgroundColor = UIColor.mfSilver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +429,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Molecular
|
// MARK: - Molecular
|
||||||
extension FieldEntryFormView {
|
extension FormEntryField {
|
||||||
|
|
||||||
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)
|
||||||
@ -434,7 +442,7 @@ extension FieldEntryFormView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Form Validation
|
// MARK: - Form Validation
|
||||||
extension FieldEntryFormView: FormValidationProtocol {
|
extension FormEntryField: FormValidationProtocol {
|
||||||
|
|
||||||
public func isValidField() -> Bool {
|
public func isValidField() -> Bool {
|
||||||
return isValid
|
return isValid
|
||||||
@ -450,7 +458,7 @@ extension FieldEntryFormView: FormValidationProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Accessibility
|
// MARK: - Accessibility
|
||||||
extension FieldEntryFormView {
|
extension FormEntryField {
|
||||||
|
|
||||||
@objc open func pushAccessibilityNotification() {
|
@objc open func pushAccessibilityNotification() {
|
||||||
// To Be Overriden
|
// To Be Overriden
|
||||||
@ -12,221 +12,214 @@ import UIKit
|
|||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
class MdnEntryField: TextEntryField, UITextFieldDelegate, ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate {
|
class MdnEntryField: TextEntryField, UITextFieldDelegate, ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public weak var customDelegate: UITextFieldDelegate?
|
|
||||||
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
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
|
||||||
super.init(frame: .zero)
|
|
||||||
setup()
|
|
||||||
}
|
|
||||||
|
|
||||||
public convenience init() {
|
|
||||||
self.init(frame: .zero)
|
|
||||||
}
|
|
||||||
|
|
||||||
required public init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Setup
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
private func setup() {
|
|
||||||
|
|
||||||
textField?.delegate = self
|
public weak var customDelegate: UITextFieldDelegate?
|
||||||
customDelegate = uiTextFieldDelegate
|
public var isNationalMdn = false
|
||||||
isNationalMdn = true
|
public var shouldValidateMDN = false
|
||||||
textField?.keyboardType = .numberPad
|
|
||||||
|
|
||||||
let toolbar = MVMCoreUICommonViewsUtility.makeEmptyToolbar()
|
public var mdn: String? {
|
||||||
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
get { return MVMCoreUIUtility.removeMdnFormat(text) }
|
||||||
let contacts = UIBarButtonItem(title: MVMCoreUIUtility.hardcodedString(withKey: "textfield_contacts_barbutton"), style: .plain, target: self, action: #selector(getContacts(_:)))
|
set {
|
||||||
let dismissButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissFieldInput(_:)))
|
text = MVMCoreUIUtility.formatMdn(newValue)
|
||||||
toolbar.items = [contacts, space, dismissButton]
|
|
||||||
textField?.inputAccessoryView = toolbar
|
|
||||||
}
|
|
||||||
|
|
||||||
// If you're using a MFViewController, you must set this to it.
|
|
||||||
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
|
||||||
get {
|
|
||||||
return textField?.delegate
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
super.uiTextFieldDelegate = newValue
|
|
||||||
customDelegate = uiTextFieldDelegate
|
|
||||||
|
|
||||||
if newValue != nil {
|
|
||||||
textField?.delegate = self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Methods
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
func hasValidMdn() -> Bool {
|
|
||||||
|
|
||||||
guard let MDN = mdn else { return true }
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
if MDN.isEmpty {
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
public convenience init() {
|
||||||
|
self.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
fatalError("MdnEntryField xib not supported.")
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Setup
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private func setup() {
|
||||||
|
|
||||||
|
textField?.delegate = self
|
||||||
|
customDelegate = uiTextFieldDelegate
|
||||||
|
isNationalMdn = true
|
||||||
|
textField?.keyboardType = .numberPad
|
||||||
|
|
||||||
|
let toolbar = MVMCoreUICommonViewsUtility.makeEmptyToolbar()
|
||||||
|
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
||||||
|
let contacts = UIBarButtonItem(title: MVMCoreUIUtility.hardcodedString(withKey: "textfield_contacts_barbutton"), style: .plain, target: self, action: #selector(getContacts(_:)))
|
||||||
|
let dismissButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissFieldInput(_:)))
|
||||||
|
toolbar.items = [contacts, space, dismissButton]
|
||||||
|
textField?.inputAccessoryView = toolbar
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you're using a MFViewController, you must set this to it.
|
||||||
|
public override weak var uiTextFieldDelegate: UITextFieldDelegate? {
|
||||||
|
get { return textField?.delegate }
|
||||||
|
set {
|
||||||
|
super.uiTextFieldDelegate = newValue
|
||||||
|
customDelegate = uiTextFieldDelegate
|
||||||
|
|
||||||
|
if newValue != nil {
|
||||||
|
textField?.delegate = self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
func hasValidMdn() -> Bool {
|
||||||
|
|
||||||
|
guard let MDN = mdn else { return true }
|
||||||
|
|
||||||
|
if MDN.isEmpty {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isNationalMdn {
|
||||||
|
return MVMCoreUIUtility.validateMDNString(MDN)
|
||||||
|
}
|
||||||
|
|
||||||
|
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateAndColor() -> Bool {
|
||||||
|
|
||||||
|
if !shouldValidateMDN {
|
||||||
|
let isValid = hasValidMdn()
|
||||||
|
|
||||||
|
if isValid {
|
||||||
|
hideError()
|
||||||
|
} else {
|
||||||
|
self.errorMessage = getErrorMessage() ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
|
||||||
|
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField)
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if isNationalMdn {
|
func getErrorMessage() -> String? {
|
||||||
return MVMCoreUIUtility.validateMDNString(MDN)
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
|
@objc func dismissFieldInput(_ sender: Any?) {
|
||||||
}
|
|
||||||
|
|
||||||
func validateAndColor() -> Bool {
|
|
||||||
|
|
||||||
if !shouldValidateMDN {
|
|
||||||
let isValid = hasValidMdn()
|
|
||||||
|
|
||||||
if isValid {
|
if let delegate = uiTextFieldDelegate {
|
||||||
hideError()
|
delegate.perform(#selector(dismissFieldInput(_:)), with: textField)
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = getErrorMessage() ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
|
textField?.resignFirstResponder()
|
||||||
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return isValid
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
func getContacts(_ sender: Any?) {
|
||||||
}
|
|
||||||
|
let picker = CNContactPickerViewController()
|
||||||
func getErrorMessage() -> String? {
|
picker.delegate = self
|
||||||
|
picker.displayedPropertyKeys = ["phoneNumbers"]
|
||||||
return nil
|
picker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.@count > 0")
|
||||||
}
|
picker.predicateForSelectionOfProperty = NSPredicate(format: "key == 'phoneNumbers'")
|
||||||
|
MVMCoreNavigationHandler.shared()?.present(picker, animated: true)
|
||||||
@objc func dismissFieldInput(_ sender: Any?) {
|
|
||||||
|
|
||||||
if let delegate = uiTextFieldDelegate {
|
|
||||||
delegate.perform(#selector(dismissFieldInput(_:)), with: textField)
|
|
||||||
} else {
|
|
||||||
textField?.resignFirstResponder()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func getContacts(_ sender: Any?) {
|
|
||||||
|
|
||||||
let picker = CNContactPickerViewController()
|
//--------------------------------------------------
|
||||||
picker.delegate = self
|
// MARK: - ContactPicker Delegate
|
||||||
picker.displayedPropertyKeys = ["phoneNumbers"]
|
//--------------------------------------------------
|
||||||
picker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.@count > 0")
|
|
||||||
picker.predicateForSelectionOfProperty = NSPredicate(format: "key == 'phoneNumbers'")
|
|
||||||
MVMCoreNavigationHandler.shared()?.present(picker, animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - ContactPicker Delegate
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
|
|
||||||
|
|
||||||
if contactProperty.value != nil && (contactProperty.value is CNPhoneNumber) {
|
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
|
||||||
|
|
||||||
let phoneNumber = contactProperty.value as? CNPhoneNumber
|
if contactProperty.value != nil && (contactProperty.value is CNPhoneNumber) {
|
||||||
let MDN = phoneNumber?.stringValue
|
|
||||||
var unformattedMDN = MVMCoreUIUtility.removeMdnFormat(MDN)
|
|
||||||
|
|
||||||
// Sometimes user add extra 1 in front of mdn in their address book
|
|
||||||
if isNationalMdn,
|
|
||||||
let unformedMDN = unformattedMDN,
|
|
||||||
unformedMDN.count == 11,
|
|
||||||
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
|
||||||
|
|
||||||
unformattedMDN = (unformedMDN as NSString).substring(from: 1)
|
let phoneNumber = contactProperty.value as? CNPhoneNumber
|
||||||
}
|
let MDN = phoneNumber?.stringValue
|
||||||
|
var unformattedMDN = MVMCoreUIUtility.removeMdnFormat(MDN)
|
||||||
text = unformattedMDN
|
|
||||||
|
// Sometimes user add extra 1 in front of mdn in their address book
|
||||||
if let textField = textField {
|
if isNationalMdn,
|
||||||
textFieldShouldReturn(textField)
|
let unformedMDN = unformattedMDN,
|
||||||
textFieldDidEndEditing(textField)
|
unformedMDN.count == 11,
|
||||||
|
unformedMDN[(unformedMDN.index(unformedMDN.startIndex, offsetBy: 0))] == "1" {
|
||||||
|
|
||||||
|
unformattedMDN = (unformedMDN as NSString).substring(from: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
text = unformattedMDN
|
||||||
|
|
||||||
|
if let textField = textField {
|
||||||
|
textFieldShouldReturn(textField)
|
||||||
|
textFieldDidEndEditing(textField)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - ImplementedTextField Delegate
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
|
||||||
|
|
||||||
textField.resignFirstResponder()
|
//--------------------------------------------------
|
||||||
|
// MARK: - ImplementedTextField Delegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
return customDelegate?.textFieldShouldReturn?(textField) ?? true
|
@discardableResult
|
||||||
}
|
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
@objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
textField.resignFirstResponder()
|
||||||
|
|
||||||
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
|
return customDelegate?.textFieldShouldReturn?(textField) ?? true
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return customDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
|
@objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
}
|
|
||||||
|
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
|
||||||
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return customDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text)
|
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
customDelegate?.textFieldDidBeginEditing?(textField)
|
|
||||||
}
|
textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text)
|
||||||
|
customDelegate?.textFieldDidBeginEditing?(textField)
|
||||||
public func textFieldDidEndEditing(_ textField: UITextField) {
|
}
|
||||||
|
|
||||||
customDelegate?.textFieldDidEndEditing?(textField)
|
public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||||
|
|
||||||
|
customDelegate?.textFieldDidEndEditing?(textField)
|
||||||
|
|
||||||
|
if validateAndColor() && isNationalMdn {
|
||||||
|
textField.text = MVMCoreUIUtility.formatMdn(textField.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if validateAndColor() && isNationalMdn {
|
//--------------------------------------------------
|
||||||
textField.text = MVMCoreUIUtility.formatMdn(textField.text)
|
// MARK: - Passed Along TextField delegate
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
return customDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
return customDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||||
|
|
||||||
|
return customDelegate?.textFieldShouldClear?(textField) ?? true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Passed Along TextField delegate
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
|
||||||
|
|
||||||
return customDelegate?.textFieldShouldBeginEditing?(textField) ?? true
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
|
||||||
|
|
||||||
return customDelegate?.textFieldShouldEndEditing?(textField) ?? true
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
|
||||||
|
|
||||||
return customDelegate?.textFieldShouldClear?(textField) ?? true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import UIKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class TextEntryField: FieldEntryFormView {
|
@objcMembers open class TextEntryField: FormEntryField {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -500,7 +500,9 @@ extension TextEntryField {
|
|||||||
open override func pushAccessibilityNotification() {
|
open override func pushAccessibilityNotification() {
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: self?.textField)
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: self.textField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user