latest. no errs.

This commit is contained in:
Kevin G Christiano 2019-10-24 13:51:19 -04:00
parent 15c2050c4e
commit 70a3ad2804
4 changed files with 206 additions and 404 deletions

View File

@ -23,7 +23,7 @@ import UIKit
// MARK: - Properties
//--------------------------------------------------
weak var textBoxDelegate: DigitTextBoxDelegate?
weak var textBoxDelegate: DigitBoxDelegate?
private var previousSize: CGFloat = 0.0

View File

@ -9,7 +9,7 @@
import UIKit
class DigitEntryField: TextEntryField, DigitBoxDelegate {
open class DigitEntryField: TextEntryField, DigitBoxDelegate {
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
@ -24,58 +24,68 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
private var switchedAutomatically = false
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? {
get {
var string = ""
for digitField in digitFields ?? [] {
if let placeholderText = digitField.attributedPlaceholder?.string {
string += placeholderText
if let digitext = digitField.attributedPlaceholder?.string {
string += digitext
}
}
return !string.isEmpty ? string : nil
}
set {
guard let placeholderValue = newValue else { return }
guard let fieldValue = newValue, let fields = digitFields 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: [
for (index, field) in fields.enumerated() {
if index < fieldValue.count {
let stringForIndex = (newValue as NSString?)?.substring(with: NSRange(location: index, length: 1))
field.attributedPlaceholder = NSAttributedString(string: stringForIndex ?? "", attributes: [
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? {
get {
var string = ""
@ -89,30 +99,42 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
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
guard let fields = self.digitFields else { return }
for (index, field) in fields.enumerated() {
if index < (text?.count ?? 0) {
let stringForIndex = (text as NSString?)?.substring(with: NSRange(location: index, length: 1))
field.text = stringForIndex
}
})
}
valueChanged()
}
}
public override var formText: String? {
get {
return formDescriptionLabel?.text
}
public override var descriptionText: String? {
get { return descriptionLabel?.text }
set {
if let formText = newValue, !formText.isEmpty > 0 {
if let formText = newValue, !formText.isEmpty {
messageToTextFieldPin?.constant = 10
} else {
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) {
super.init(frame: .zero)
setup()
self.numberOfDigits = numberOfDigits
buildTextFieldsView(size: MVMCoreUISplitViewController.getDetailViewWidth())
}
@ -142,29 +165,66 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
public init(numberOfDigits: Int, bothDelegates delegates: (UITextFieldDelegate & MFTextFieldDelegate)?) {
super.init(bothDelegates: delegates as? (TextFieldDelegate & UITextFieldDelegate))
setup()
self.numberOfDigits = numberOfDigits
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))
setup()
self.numberOfDigits = numberOfDigits
buildTextFieldsView(size: size)
}
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
//--------------------------------------------------
func createDigitField() -> DigitTextBox {
func createDigitField() -> DigitBox {
let textField = DigitTextBox()
let textField = DigitBox()
textField.delegate = self
textField.textBoxDelegate = self
@ -180,7 +240,7 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
if numberOfDigits > 0 {
let digitFields = [DigitTextBox](repeating: createDigitField(), count: numberOfDigits)
let digitFields = [DigitBox](repeating: createDigitField(), count: numberOfDigits)
for digitField in digitFields {
digitField.updateView(size)
@ -200,47 +260,31 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
if let placeholder = self.placeholder, !placeholder.isEmpty {
if let feedback = self.feedback, !feedback.isEmpty {
self.labelToTextFieldPin?.constant = 10
} else {
self.labelToTextFieldPin?.constant = 0
}
}
}
open override func updateView(_ size: CGFloat) {
super.updateView(size)
func setAsSecureTextEntry(_ secureEntry: Bool) {
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)
if let digitFields = self.digitFields, !digitFields.isEmpty {
for (index, field) in fields.enumerated() {
field.isSecureTextEntry = secureEntry
// Remove all current UI.
StackableViewController.remove(digitFields)
// Update text boxes.
for digitField in digitFields {
digitField.updateView(size)
}
// Accessibility - 33704 fix voice over will read what pin user is filling
field.accessibilityLabel = String(format: "PIN %lu of %lu", UInt(index) + 1, UInt(fields.count))
}
// 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(),
@ -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
//--------------------------------------------------
@ -282,106 +340,21 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
numberOfDigits = digits
}
if !dictionary.isEmpty{
for textField in digitFields ?? [] {
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: delegateObject as? UITextFieldDelegate)
}
}
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
//--------------------------------------------------
@ -390,56 +363,58 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
var selectNextField = false
(digitFields as NSArray?)?.enumerateObjects(options: .reverse, using: { obj, idx, stop in
if obj == currentTextField {
guard let fields = digitFields else { return }
for field in fields {
if field == currentTextField {
selectNextField = true
} else if selectNextField {
if !clear {
self.switchedAutomatically = true
switchedAutomatically = true
}
obj.becomeFirstResponder()
self.switchedAutomatically = false
stop = true
field.becomeFirstResponder()
switchedAutomatically = false
//accessibility
UIAccessibility.post(notification: .layoutChanged, argument: obj)
UIAccessibility.post(notification: .layoutChanged, argument: field)
}
})
}
}
func selectNextTextField(_ currentTextField: UITextField?, clear: Bool) {
var selectNextField = false
(digitFields as NSArray?)?.enumerateObjects({ obj, idx, stop in
if obj == currentTextField {
guard let fields = digitFields else { return }
for field in fields{
if field == currentTextField {
selectNextField = true
} else if selectNextField {
if !clear {
self.switchedAutomatically = true
}
obj.becomeFirstResponder()
field.becomeFirstResponder()
self.switchedAutomatically = false
stop = true
//accessibility
UIAccessibility.post(notification: .layoutChanged, argument: obj)
UIAccessibility.post(notification: .layoutChanged, argument: field)
}
})
}
}
//--------------------------------------------------
// MARK: - Accessinility
//--------------------------------------------------
open override var accessibilityElements: [Any]? {
if let digitFields = self.digitFields {
return [digitFields] //return [self.digitFields arrayByAddingObject:(DigitTextBox *)self.label];
} else {
return [placeholder]
}
open override class func accessibilityElements() -> [Any]? {
// self.digit
// if let digitFields = self.digitFields {
// return [digitFields] + [textField]
// }
//
return [textField]
}
//--------------------------------------------------
@ -464,9 +439,9 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
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
@ -474,21 +449,23 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
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
return false
}
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)
}
@ -504,7 +481,6 @@ class DigitEntryField: TextEntryField, DigitBoxDelegate {
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
uiTextFieldDelegate?.textFieldDidEndEditing?(textField)
}

View File

@ -21,21 +21,11 @@ import UIKit
//--------------------------------------------------
public var dropDownCaretLabel: UILabel?
private var borderPath: UIBezierPath?
public var dropDownIsDisplayed = false
public override var isEnabled: Bool {
didSet {
}
}
// The text of this textField.
public override var text: String? {
get { return textField?.text }
set {
textField?.text = newValue
valueChanged()
showDropDown(isEnabled)
}
}
@ -67,8 +57,11 @@ import UIKit
/// - parameter bothDelegates: Sets both MF/UI Text Field Delegates.
public override init(bothDelegates: (UITextFieldDelegate & TextFieldDelegate)?) {
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) {
guard let textField = textField else { return }
let dropDownCaretLabel = Label()
self.dropDownCaretLabel = dropDownCaretLabel
dropDownCaretLabel.setContentHuggingPriority(UILayoutPriority(900), for: .horizontal)
@ -97,169 +92,26 @@ import UIKit
dropDownCaretWidth?.isActive = true
}
open override func updateView(_ size: CGFloat) {
super.updateView(size)
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
public func showDropDown(_ show: Bool) {
if hasDropDown {
dropDownCaretLabel?.isHidden = !show
dropDownCarrotWidth?.isActive = !show
setNeedsLayout()
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)
dropDownCaretLabel?.isHidden = !show
dropDownCaretWidth?.isActive = !show
setNeedsLayout()
layoutIfNeeded()
}
//--------------------------------------------------
// MARK: - Observing for change
//--------------------------------------------------
func valueChanged() {
override func startEditing() {
super.startEditing()
// Update label for placeholder
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)
showDropDown(!showErrorMessage)
}
class func getEnabledTextfields(_ textFieldToDetermine: [TextEntryField]?) -> [AnyHashable]? {
@ -278,7 +130,7 @@ import UIKit
// MARK: - Date Picker
extension DropdownEntryField {
private func createDatePicker() {
guard let textField = textField else { return }
@ -337,11 +189,6 @@ extension DropdownEntryField {
textField?.resignFirstResponder()
return pickedDate
}
public func dismissPicker() {
textField?.resignFirstResponder()
}
}
// MARK: - Molecular
@ -350,46 +197,26 @@ extension DropdownEntryField {
override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
if let delegateObject = delegateObject {
FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol)
setWithMap(json)
if let formValidationProtocol = delegateObject.formValidationProtocol {
mfTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol)
}
uiTextFieldDelegate = delegateObject.uiTextFieldDelegate
if let textField = textField {
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate)
}
guard let dictionary = json,
!dictionary.isEmpty
else { return }
if let _ = dictionary[KeyType] as? String {
dropDownCaretLabel?.isHidden = false
}
}
override open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 76
}
}
// MARK: - Accessibility
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?) {
guard let textField = textField else { return }
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
} 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") ?? "")"
}
}

View File

@ -34,14 +34,14 @@ import UIKit
private var borderPath: UIBezierPath?
public var showErrorMessage = false
public var errorMessage: String? {
didSet {
feedback = errorMessage
}
}
public var showErrorMessage = false
public var isEnabled = true {
didSet {
DispatchQueue.main.async { [weak self] in