latest. no errs.
This commit is contained in:
parent
15c2050c4e
commit
70a3ad2804
@ -23,7 +23,7 @@ import UIKit
|
|||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
weak var textBoxDelegate: DigitTextBoxDelegate?
|
weak var textBoxDelegate: DigitBoxDelegate?
|
||||||
|
|
||||||
private var previousSize: CGFloat = 0.0
|
private var previousSize: CGFloat = 0.0
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
open class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -24,58 +24,68 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
private var switchedAutomatically = false
|
private var switchedAutomatically = false
|
||||||
public var digitFields: [DigitBox]?
|
public var digitFields: [DigitBox]?
|
||||||
|
|
||||||
/// Setgs placeholder text in the textField.
|
public override var isEnabled: Bool {
|
||||||
|
didSet {
|
||||||
|
if isEnabled {
|
||||||
|
descriptionLabel?.styleB2(true)
|
||||||
|
} else {
|
||||||
|
descriptionLabel?.textColor = UIColor.mfBattleshipGrey()
|
||||||
|
}
|
||||||
|
|
||||||
|
for textField in digitFields ?? [] {
|
||||||
|
textField.isUserInteractionEnabled = isEnabled
|
||||||
|
textField.isEnabled = isEnabled
|
||||||
|
textField.textColor = isEnabled ? .black : UIColor.mfBattleshipGrey()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets placeholder text in the textField.
|
||||||
public override var feedback: String? {
|
public override var feedback: String? {
|
||||||
get {
|
get {
|
||||||
var string = ""
|
var string = ""
|
||||||
|
|
||||||
for digitField in digitFields ?? [] {
|
for digitField in digitFields ?? [] {
|
||||||
if let placeholderText = digitField.attributedPlaceholder?.string {
|
if let digitext = digitField.attributedPlaceholder?.string {
|
||||||
string += placeholderText
|
string += digitext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return !string.isEmpty ? string : nil
|
return !string.isEmpty ? string : nil
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
guard let placeholderValue = newValue else { return }
|
guard let fieldValue = newValue, let fields = digitFields else { return }
|
||||||
|
|
||||||
|
for (index, field) in fields.enumerated() {
|
||||||
|
if index < fieldValue.count {
|
||||||
(digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: index, length: 1))
|
||||||
|
field.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
|
||||||
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()])
|
NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()])
|
||||||
} else if stop != nil {
|
|
||||||
stop = true
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
//
|
||||||
|
// if feedback.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"))
|
||||||
|
//
|
||||||
|
// super.showErrorMessage(errorMessage)
|
||||||
|
//
|
||||||
|
// if self.showErrorMessage {
|
||||||
|
// self.labelToTextFieldPin?.constant = 10
|
||||||
|
// }
|
||||||
|
// for field in self.digitFields ?? [] {
|
||||||
|
// field.setAsError()
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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? {
|
public override var text: String? {
|
||||||
get {
|
get {
|
||||||
var string = ""
|
var string = ""
|
||||||
@ -89,30 +99,42 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
(digitFields as NSArray?)?.enumerateObjects( { obj, idx, stop in
|
guard let fields = self.digitFields else { return }
|
||||||
|
|
||||||
if idx < (text?.count ?? 0) {
|
for (index, field) in fields.enumerated() {
|
||||||
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: idx, length: 1))
|
if index < (text?.count ?? 0) {
|
||||||
obj.text = stringForIndex
|
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: index, length: 1))
|
||||||
} else if stop != nil {
|
field.text = stringForIndex
|
||||||
stop = true
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
valueChanged()
|
valueChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var formText: String? {
|
public override var descriptionText: String? {
|
||||||
get {
|
get { return descriptionLabel?.text }
|
||||||
return formDescriptionLabel?.text
|
|
||||||
}
|
|
||||||
set {
|
set {
|
||||||
if let formText = newValue, !formText.isEmpty > 0 {
|
if let formText = newValue, !formText.isEmpty {
|
||||||
messageToTextFieldPin?.constant = 10
|
messageToTextFieldPin?.constant = 10
|
||||||
} else {
|
} else {
|
||||||
messageToTextFieldPin?.constant = 0
|
messageToTextFieldPin?.constant = 0
|
||||||
}
|
}
|
||||||
super.formText = newValue
|
super.descriptionText = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var errorMessage: String? {
|
||||||
|
didSet {
|
||||||
|
if let errorMessage = errorMessage, !errorMessage.isEmpty {
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
for field in self.digitFields ?? [] {
|
||||||
|
field.hideError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +157,7 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
public init(numberOfDigits: Int) {
|
public init(numberOfDigits: Int) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
setup()
|
||||||
self.numberOfDigits = numberOfDigits
|
self.numberOfDigits = numberOfDigits
|
||||||
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||||
}
|
}
|
||||||
@ -142,29 +165,66 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) {
|
||||||
super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate))
|
super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate))
|
||||||
|
|
||||||
|
setup()
|
||||||
self.numberOfDigits = numberOfDigits
|
self.numberOfDigits = numberOfDigits
|
||||||
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(withNumberOfDigits numberOfDigits: Int, withBothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) {
|
public init(numberOfDigits: Int, bothDelegates delegate: (UITextFieldDelegate & MFTextFieldDelegate)?, size: CGFloat) {
|
||||||
super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
super.init(bothDelegates: delegate as? (TextFieldDelegate & UITextFieldDelegate))
|
||||||
|
|
||||||
|
setup()
|
||||||
self.numberOfDigits = numberOfDigits
|
self.numberOfDigits = numberOfDigits
|
||||||
buildTextFieldsView(size: size)
|
buildTextFieldsView(size: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func setupFieldContainerContent(_ container: UIView) {
|
open override func setupFieldContainerContent(_ container: UIView) {
|
||||||
|
|
||||||
setupTextFieldsView(forSize: numberOfDigits)
|
setupTextFieldsView(forSize: CGFloat(numberOfDigits))
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open func setup() {
|
||||||
|
|
||||||
|
descriptionLabel?.styleB2(true)
|
||||||
|
descriptionText = ""
|
||||||
|
alignCenterHorizontal()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
|
||||||
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.descriptionLabel?.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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
func createDigitField() -> DigitTextBox {
|
func createDigitField() -> DigitBox {
|
||||||
|
|
||||||
let textField = DigitTextBox()
|
let textField = DigitBox()
|
||||||
textField.delegate = self
|
textField.delegate = self
|
||||||
textField.textBoxDelegate = self
|
textField.textBoxDelegate = self
|
||||||
|
|
||||||
@ -180,7 +240,7 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
|
|
||||||
if numberOfDigits > 0 {
|
if numberOfDigits > 0 {
|
||||||
|
|
||||||
let digitFields = [DigitTextBox](repeating: createDigitField(), count: numberOfDigits)
|
let digitFields = [DigitBox](repeating: createDigitField(), count: numberOfDigits)
|
||||||
|
|
||||||
for digitField in digitFields {
|
for digitField in digitFields {
|
||||||
digitField.updateView(size)
|
digitField.updateView(size)
|
||||||
@ -200,47 +260,31 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
if let placeholder = self.placeholder, !placeholder.isEmpty {
|
if let feedback = self.feedback, !feedback.isEmpty {
|
||||||
self.labelToTextFieldPin?.constant = 10
|
self.labelToTextFieldPin?.constant = 10
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.labelToTextFieldPin?.constant = 0
|
self.labelToTextFieldPin?.constant = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
func setAsSecureTextEntry(_ secureEntry: Bool) {
|
||||||
super.updateView(size)
|
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self,
|
||||||
|
let fields = self.digitFields
|
||||||
|
else { return }
|
||||||
|
|
||||||
self.formDescriptionLabel?.updateView(size)
|
for (index, field) in fields.enumerated() {
|
||||||
|
field.isSecureTextEntry = secureEntry
|
||||||
if let digitFields = self.digitFields, !digitFields.isEmpty {
|
|
||||||
|
|
||||||
// Remove all current UI.
|
// Accessibility - 33704 fix voice over will read what pin user is filling
|
||||||
StackableViewController.remove(digitFields)
|
field.accessibilityLabel = String(format: "PIN %lu of %lu", UInt(index) + 1, UInt(fields.count))
|
||||||
|
|
||||||
// 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) {
|
func setupTextFieldsView(forSize size: CGFloat) {
|
||||||
|
|
||||||
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
guard let space = MFSizeObject(standardSize: 5, smalliPhoneSize: 3)?.getValueBasedOnScreenSize(),
|
||||||
@ -269,6 +313,20 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setDefaultValidationBlock() {
|
||||||
|
|
||||||
|
weak var weakSelf = self
|
||||||
|
|
||||||
|
validationBlock = { enteredValue in
|
||||||
|
|
||||||
|
if (enteredValue?.count ?? 0) > 0 && (enteredValue?.count ?? 0) == weakSelf?.digitFields?.count {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Molecule
|
// MARK: - Molecule
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -282,106 +340,21 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
numberOfDigits = digits
|
numberOfDigits = digits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !dictionary.isEmpty{
|
||||||
|
for textField in digitFields ?? [] {
|
||||||
|
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegateObject as? UITextFieldDelegate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
buildTextFieldsView(size: MVMCoreUIUtility.getWidth())
|
||||||
|
|
||||||
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
|
|
||||||
return 44
|
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
|
// MARK: - Helpers
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -390,56 +363,58 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
|
|
||||||
var selectNextField = false
|
var selectNextField = false
|
||||||
|
|
||||||
(digitFields as NSArray?)?.enumerateObjects(options: .reverse, using: { obj, idx, stop in
|
guard let fields = digitFields else { return }
|
||||||
if obj == currentTextField {
|
|
||||||
|
for field in fields {
|
||||||
|
|
||||||
|
if field == currentTextField {
|
||||||
selectNextField = true
|
selectNextField = true
|
||||||
|
|
||||||
} else if selectNextField {
|
} else if selectNextField {
|
||||||
if !clear {
|
if !clear {
|
||||||
self.switchedAutomatically = true
|
switchedAutomatically = true
|
||||||
}
|
}
|
||||||
obj.becomeFirstResponder()
|
field.becomeFirstResponder()
|
||||||
self.switchedAutomatically = false
|
switchedAutomatically = false
|
||||||
stop = true
|
|
||||||
|
|
||||||
//accessibility
|
UIAccessibility.post(notification: .layoutChanged, argument: field)
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: obj)
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectNextTextField(_ currentTextField: UITextField?, clear: Bool) {
|
func selectNextTextField(_ currentTextField: UITextField?, clear: Bool) {
|
||||||
|
|
||||||
var selectNextField = false
|
var selectNextField = false
|
||||||
(digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
|
|
||||||
|
guard let fields = digitFields else { return }
|
||||||
if obj == currentTextField {
|
|
||||||
|
for field in fields{
|
||||||
|
if field == currentTextField {
|
||||||
selectNextField = true
|
selectNextField = true
|
||||||
|
|
||||||
} else if selectNextField {
|
} else if selectNextField {
|
||||||
if !clear {
|
if !clear {
|
||||||
self.switchedAutomatically = true
|
self.switchedAutomatically = true
|
||||||
}
|
}
|
||||||
obj.becomeFirstResponder()
|
field.becomeFirstResponder()
|
||||||
self.switchedAutomatically = false
|
self.switchedAutomatically = false
|
||||||
stop = true
|
|
||||||
|
UIAccessibility.post(notification: .layoutChanged, argument: field)
|
||||||
//accessibility
|
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: obj)
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Accessinility
|
// MARK: - Accessinility
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override var accessibilityElements: [Any]? {
|
open override class func accessibilityElements() -> [Any]? {
|
||||||
|
// self.digit
|
||||||
if let digitFields = self.digitFields {
|
// if let digitFields = self.digitFields {
|
||||||
return [digitFields] //return [self.digitFields arrayByAddingObject:(DigitTextBox *)self.label];
|
// return [digitFields] + [textField]
|
||||||
} else {
|
// }
|
||||||
return [placeholder]
|
//
|
||||||
}
|
return [textField]
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -464,9 +439,9 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
let oldLength = textField.text?.count ?? 0
|
let oldLength = textField.text?.count ?? 0
|
||||||
let replacementLength = string.count
|
let replacementLength = string.count
|
||||||
if replacementLength > 1 {
|
if replacementLength > 1 {
|
||||||
|
|
||||||
// Too long (Check with AKQA if they want to allow pasting the digits.
|
// Too long (Check with AKQA if they want to allow pasting the digits.
|
||||||
return false
|
return false
|
||||||
|
|
||||||
} else if replacementLength == 1 && (oldLength == 1 || oldLength == 0) {
|
} else if replacementLength == 1 && (oldLength == 1 || oldLength == 0) {
|
||||||
|
|
||||||
// One character, switch old value with new, select next textfield
|
// One character, switch old value with new, select next textfield
|
||||||
@ -474,21 +449,23 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
selectNextTextField(textField, clear: false)
|
selectNextTextField(textField, clear: false)
|
||||||
valueChanged()
|
valueChanged()
|
||||||
return false
|
return false
|
||||||
|
|
||||||
} else if replacementLength == 0 && oldLength == 1 {
|
} else if replacementLength == 0 && oldLength == 1 {
|
||||||
// non empty cell, clear and stay.
|
// non empty cell, clear and stay.
|
||||||
textField.text = ""
|
textField.text = ""
|
||||||
valueChanged()
|
valueChanged()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func textFieldDidDelete(_ textField: UITextField?) {
|
func textFieldDidDelete(_ textField: UITextField?) {
|
||||||
|
|
||||||
// empty cell, go back to previous cell and clear.
|
// Empty cell, go back to previous cell and clear.
|
||||||
selectPreviousTextField(textField, clear: true)
|
selectPreviousTextField(textField, clear: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +481,6 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
|
|||||||
|
|
||||||
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
|
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||||
|
|
||||||
|
|
||||||
uiTextFieldDelegate?.textFieldDidEndEditing?(textField)
|
uiTextFieldDelegate?.textFieldDidEndEditing?(textField)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,21 +21,11 @@ import UIKit
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public var dropDownCaretLabel: UILabel?
|
public var dropDownCaretLabel: UILabel?
|
||||||
|
public var dropDownIsDisplayed = false
|
||||||
private var borderPath: UIBezierPath?
|
|
||||||
|
|
||||||
public override var isEnabled: Bool {
|
public override var isEnabled: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
|
showDropDown(isEnabled)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The text of this textField.
|
|
||||||
public override var text: String? {
|
|
||||||
get { return textField?.text }
|
|
||||||
set {
|
|
||||||
textField?.text = newValue
|
|
||||||
valueChanged()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +57,11 @@ import UIKit
|
|||||||
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
|
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
|
||||||
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
setupView()
|
|
||||||
setBothTextFieldDelegates(bothDelegates)
|
if let textField = textField {
|
||||||
|
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: bothDelegates)
|
||||||
|
}
|
||||||
|
setBothTextDelegates(bothDelegates)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -76,7 +69,9 @@ import UIKit
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func setupFieldContainerContent(_ container: UIView) {
|
open override func setupFieldContainerContent(_ container: UIView) {
|
||||||
|
|
||||||
|
guard let textField = textField else { return }
|
||||||
|
|
||||||
let dropDownCaretLabel = Label()
|
let dropDownCaretLabel = Label()
|
||||||
self.dropDownCaretLabel = dropDownCaretLabel
|
self.dropDownCaretLabel = dropDownCaretLabel
|
||||||
dropDownCaretLabel.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal)
|
dropDownCaretLabel.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal)
|
||||||
@ -97,169 +92,26 @@ import UIKit
|
|||||||
dropDownCaretWidth?.isActive = true
|
dropDownCaretWidth?.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
|
||||||
super.updateView(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public func showDropDown(_ show: Bool) {
|
public func showDropDown(_ show: Bool) {
|
||||||
|
|
||||||
if hasDropDown {
|
dropDownCaretLabel?.isHidden = !show
|
||||||
dropDownCaretLabel?.isHidden = !show
|
dropDownCaretWidth?.isActive = !show
|
||||||
dropDownCarrotWidth?.isActive = !show
|
setNeedsLayout()
|
||||||
setNeedsLayout()
|
layoutIfNeeded()
|
||||||
layoutIfNeeded()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func showErrorMessage(_ errorMessage: String?) {
|
|
||||||
super.showErrorMessage(errorMessage)
|
|
||||||
|
|
||||||
textField?.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", textField?.text ?? "", errorMessage ?? "")
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func hideError() {
|
|
||||||
super.hideError()
|
|
||||||
|
|
||||||
textField?.accessibilityValue = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
public func setBothTextFieldDelegates(_ delegate: (UITextFieldDelegate & TextFieldDelegate)?) {
|
|
||||||
|
|
||||||
mfTextFieldDelegate = delegate
|
|
||||||
uiTextFieldDelegate = delegate
|
|
||||||
}
|
|
||||||
|
|
||||||
public override func setWithMap(_ map: [AnyHashable: Any]?) {
|
|
||||||
super.setWithMap(map)
|
|
||||||
|
|
||||||
guard let map = map, !map.isEmpty else { return }
|
|
||||||
|
|
||||||
if let formText = map[KeyLabel] as? String {
|
|
||||||
self.formText = formText
|
|
||||||
}
|
|
||||||
|
|
||||||
if let text = map[KeyValue] as? String {
|
|
||||||
self.text = text
|
|
||||||
}
|
|
||||||
|
|
||||||
if let text = map[KeyDisable] as? String, text.isEqual(StringY) || map.boolForKey(KeyDisable) {
|
|
||||||
formIsDisabled()
|
|
||||||
}
|
|
||||||
|
|
||||||
if let dropDown = map[KeyType] as? String {
|
|
||||||
dropDownCaretLabel?.isHidden = false
|
|
||||||
self.hasDropDown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key used to send text value to server
|
|
||||||
if let fieldKey = map[KeyFieldKey] as? String {
|
|
||||||
self.fieldKey = fieldKey
|
|
||||||
}
|
|
||||||
|
|
||||||
switch map.stringForkey(KeyType) {
|
|
||||||
case "dropDown":
|
|
||||||
dropDownCaretLabel?.isHidden = false
|
|
||||||
self.hasDropDown = true
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
let regex = map.stringForkey("regex")
|
|
||||||
|
|
||||||
if !regex.isEmpty {
|
|
||||||
validationBlock = { enteredValue in
|
|
||||||
guard let value = enteredValue else { return false }
|
|
||||||
return MVMCoreUIUtility.validate(value, withRegularExpression: regex)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
defaultValidationBlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func setWithMap(_ map: [AnyHashable: Any]?, bothDelegates delegate: (UITextFieldDelegate & TextFieldDelegate)?) {
|
|
||||||
|
|
||||||
guard let textField = textField else { return }
|
|
||||||
|
|
||||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegate)
|
|
||||||
setBothTextFieldDelegates(delegate)
|
|
||||||
setWithMap(map)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func defaultValidationBlock() {
|
|
||||||
|
|
||||||
validationBlock = { enteredValue in
|
|
||||||
return (enteredValue?.count ?? 0) > 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func formIsEnabled() {
|
|
||||||
super.formIsEnabled()
|
|
||||||
|
|
||||||
textField?.isUserInteractionEnabled = true
|
|
||||||
textField?.isEnabled = true
|
|
||||||
showDropDown(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func formIsDisabled() {
|
|
||||||
super.formIsDisabled()
|
|
||||||
|
|
||||||
textField?.isUserInteractionEnabled = false
|
|
||||||
textField?.isEnabled = false
|
|
||||||
self.showDropDown(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Observing for change
|
// MARK: - Observing for change
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
func valueChanged() {
|
override func startEditing() {
|
||||||
|
super.startEditing()
|
||||||
|
|
||||||
// Update label for placeholder
|
showDropDown(!showErrorMessage)
|
||||||
if !showError {
|
|
||||||
feedbackLabel?.text = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
let previousValidity = isValid
|
|
||||||
|
|
||||||
// If validation not set, input will always be valid
|
|
||||||
isValid = validationBlock?(text) ?? true
|
|
||||||
|
|
||||||
if previousValidity && !isValid {
|
|
||||||
if let errMessage = errorMessage {
|
|
||||||
showErrorMessage(errMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let mfTextFieldDelegate = mfTextFieldDelegate {
|
|
||||||
mfTextFieldDelegate.isInvalid?(textfield: self)
|
|
||||||
}
|
|
||||||
} else if !previousValidity && isValid {
|
|
||||||
hideError()
|
|
||||||
|
|
||||||
if let mfTextFieldDelegate = mfTextFieldDelegate {
|
|
||||||
mfTextFieldDelegate.isValid?(textfield: self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func endInputing() {
|
|
||||||
|
|
||||||
if isValid {
|
|
||||||
hideError()
|
|
||||||
separatorView?.backgroundColor = .black
|
|
||||||
} else if let errMessage = errorMessage {
|
|
||||||
showErrorMessage(errMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func startEditing() {
|
|
||||||
|
|
||||||
textField?.becomeFirstResponder()
|
|
||||||
showErrorDropdown(!showError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {
|
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {
|
||||||
@ -278,7 +130,7 @@ import UIKit
|
|||||||
|
|
||||||
// MARK: - Date Picker
|
// MARK: - Date Picker
|
||||||
extension DropdownEntryField {
|
extension DropdownEntryField {
|
||||||
|
|
||||||
private func createDatePicker() {
|
private func createDatePicker() {
|
||||||
|
|
||||||
guard let textField = textField else { return }
|
guard let textField = textField else { return }
|
||||||
@ -337,11 +189,6 @@ extension DropdownEntryField {
|
|||||||
textField?.resignFirstResponder()
|
textField?.resignFirstResponder()
|
||||||
return pickedDate
|
return pickedDate
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dismissPicker() {
|
|
||||||
|
|
||||||
textField?.resignFirstResponder()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Molecular
|
// MARK: - Molecular
|
||||||
@ -350,46 +197,26 @@ extension DropdownEntryField {
|
|||||||
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)
|
||||||
|
|
||||||
if let delegateObject = delegateObject {
|
guard let dictionary = json,
|
||||||
FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol)
|
!dictionary.isEmpty
|
||||||
setWithMap(json)
|
else { return }
|
||||||
|
|
||||||
if let formValidationProtocol = delegateObject.formValidationProtocol {
|
if let _ = dictionary[KeyType] as? String {
|
||||||
mfTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol)
|
dropDownCaretLabel?.isHidden = false
|
||||||
}
|
|
||||||
|
|
||||||
uiTextFieldDelegate = delegateObject.uiTextFieldDelegate
|
|
||||||
|
|
||||||
if let textField = textField {
|
|
||||||
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
|
||||||
return 76
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Accessibility
|
// MARK: - Accessibility
|
||||||
extension DropdownEntryField {
|
extension DropdownEntryField {
|
||||||
|
|
||||||
open override func pushAccessibilityNotification() {
|
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
|
||||||
guard let self = self else { return }
|
|
||||||
|
|
||||||
UIAccessibility.post(notification: .layoutChanged, argument: self.textField)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setAccessibilityString(_ accessibilityString: String?) {
|
open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||||
|
|
||||||
guard let textField = textField else { return }
|
guard let textField = textField else { return }
|
||||||
|
|
||||||
var accessibilityString = accessibilityString ?? ""
|
var accessibilityString = accessibilityString ?? ""
|
||||||
|
|
||||||
if hasDropDown, let txtPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
if dropDownIsDisplayed, let txtPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||||
accessibilityString += txtPickerItem
|
accessibilityString += txtPickerItem
|
||||||
|
|
||||||
} else if let txtRegular = MVMCoreUIUtility.hardcodedString(withKey: "textfield_regular") {
|
} else if let txtRegular = MVMCoreUIUtility.hardcodedString(withKey: "textfield_regular") {
|
||||||
@ -398,5 +225,4 @@ extension DropdownEntryField {
|
|||||||
|
|
||||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,14 +34,14 @@ import UIKit
|
|||||||
|
|
||||||
private var borderPath: UIBezierPath?
|
private var borderPath: UIBezierPath?
|
||||||
|
|
||||||
|
public var showErrorMessage = false
|
||||||
|
|
||||||
public var errorMessage: String? {
|
public var errorMessage: String? {
|
||||||
didSet {
|
didSet {
|
||||||
feedback = errorMessage
|
feedback = errorMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var showErrorMessage = false
|
|
||||||
|
|
||||||
public var isEnabled = true {
|
public var isEnabled = true {
|
||||||
didSet {
|
didSet {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user