accessibility fix
This commit is contained in:
parent
400b43b7ad
commit
63c793fe25
@ -25,12 +25,9 @@ import UIKit
|
|||||||
if numberOfDigits > 0 {
|
if numberOfDigits > 0 {
|
||||||
var digitBoxes = [DigitBox]()
|
var digitBoxes = [DigitBox]()
|
||||||
|
|
||||||
let ordinalFormatter = NumberFormatter()
|
|
||||||
ordinalFormatter.numberStyle = .ordinal
|
|
||||||
|
|
||||||
for i in 0..<numberOfDigits {
|
for i in 0..<numberOfDigits {
|
||||||
let newDigitBox = createDigitField()
|
let newDigitBox = createDigitField()
|
||||||
let accessibileLabel = ordinalFormatter.string(from: NSNumber(value: i + 1)) ?? ""
|
let accessibileLabel = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: i + 1)) ?? ""
|
||||||
newDigitBox.digitField.accessibilityLabel = "\(accessibileLabel) field of \(numberOfDigits) digit fields"
|
newDigitBox.digitField.accessibilityLabel = "\(accessibileLabel) field of \(numberOfDigits) digit fields"
|
||||||
digitBoxes.append(newDigitBox)
|
digitBoxes.append(newDigitBox)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,18 @@ open class RadioBox: Control {
|
|||||||
return model as? RadioBoxModel
|
return model as? RadioBoxModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override var isSelected: Bool {
|
||||||
|
didSet {
|
||||||
|
updateAccessibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var isEnabled: Bool {
|
||||||
|
didSet {
|
||||||
|
updateAccessibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
open override func updateView(_ size: CGFloat) {
|
||||||
@ -56,6 +68,8 @@ open class RadioBox: Control {
|
|||||||
subTextLabelHeightConstraint?.isActive = true
|
subTextLabelHeightConstraint?.isActive = true
|
||||||
|
|
||||||
addTarget(self, action: #selector(selectBox), for: .touchUpInside)
|
addTarget(self, action: #selector(selectBox), for: .touchUpInside)
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
@ -63,8 +77,6 @@ open class RadioBox: Control {
|
|||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
guard let model = model as? RadioBoxModel else { return }
|
guard let model = model as? RadioBoxModel else { return }
|
||||||
isSelected = model.selected
|
|
||||||
isEnabled = model.enabled
|
|
||||||
label.text = model.text
|
label.text = model.text
|
||||||
subTextLabel.text = model.subText
|
subTextLabel.text = model.subText
|
||||||
isOutOfStock = model.strikethrough
|
isOutOfStock = model.strikethrough
|
||||||
@ -72,6 +84,8 @@ open class RadioBox: Control {
|
|||||||
if let color = model.selectedAccentColor?.uiColor {
|
if let color = model.selectedAccentColor?.uiColor {
|
||||||
accentColor = color
|
accentColor = color
|
||||||
}
|
}
|
||||||
|
isSelected = model.selected
|
||||||
|
isEnabled = model.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
@ -91,7 +105,6 @@ open class RadioBox: Control {
|
|||||||
strikeLayer = line
|
strikeLayer = line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Draw the border
|
// Draw the border
|
||||||
borderLayer?.removeFromSuperlayer()
|
borderLayer?.removeFromSuperlayer()
|
||||||
if isSelected {
|
if isSelected {
|
||||||
@ -191,5 +204,25 @@ open class RadioBox: Control {
|
|||||||
mask.frame = bounds
|
mask.frame = bounds
|
||||||
return mask
|
return mask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Accessibility
|
||||||
|
public func updateAccessibility() {
|
||||||
|
var message = ""
|
||||||
|
if let labelText = label.text, label.hasText {
|
||||||
|
message += labelText + ", "
|
||||||
|
}
|
||||||
|
if let subLabelText = subTextLabel.text, subTextLabel.hasText {
|
||||||
|
message += subLabelText + ", "
|
||||||
|
}
|
||||||
|
accessibilityLabel = message
|
||||||
|
|
||||||
|
accessibilityTraits = .button
|
||||||
|
if isSelected {
|
||||||
|
accessibilityTraits.insert(.selected)
|
||||||
|
}
|
||||||
|
if !isEnabled {
|
||||||
|
accessibilityTraits.insert(.notEnabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ open class RadioBoxCollectionViewCell: CollectionViewCell {
|
|||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
isAccessibilityElement = true
|
||||||
addMolecule(radioBox)
|
addMolecule(radioBox)
|
||||||
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||||
}
|
}
|
||||||
@ -24,5 +25,12 @@ open class RadioBoxCollectionViewCell: CollectionViewCell {
|
|||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
guard let model = model as? RadioBoxModel else { return }
|
guard let model = model as? RadioBoxModel else { return }
|
||||||
radioBox.set(with: model, delegateObject, additionalData)
|
radioBox.set(with: model, delegateObject, additionalData)
|
||||||
|
updateAccessibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
open func updateAccessibility() {
|
||||||
|
accessibilityLabel = radioBox.accessibilityLabel
|
||||||
|
accessibilityHint = radioBox.accessibilityHint
|
||||||
|
accessibilityTraits = radioBox.accessibilityTraits
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,13 @@ open class RadioBoxes: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open func updateAccessibilityValue(collectionView: UICollectionView, cell: RadioBoxCollectionViewCell, indexPath: IndexPath) {
|
||||||
|
guard let format = MVMCoreUIUtility.hardcodedString(withKey: "index_string_of_total"),
|
||||||
|
let indexString = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: indexPath.row + 1)) else { return }
|
||||||
|
let total = self.collectionView(collectionView, numberOfItemsInSection: indexPath.section)
|
||||||
|
cell.accessibilityValue = String(format: format, indexString, total)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - MVMCoreViewProtocol
|
// MARK: - MVMCoreViewProtocol
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
@ -136,6 +143,7 @@ extension RadioBoxes: UICollectionViewDataSource {
|
|||||||
if molecule.selected {
|
if molecule.selected {
|
||||||
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
|
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
|
||||||
}
|
}
|
||||||
|
updateAccessibilityValue(collectionView: collectionView, cell: cell, indexPath: indexPath)
|
||||||
cell.layoutIfNeeded()
|
cell.layoutIfNeeded()
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
@ -151,11 +159,13 @@ extension RadioBoxes: UICollectionViewDelegate {
|
|||||||
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
|
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
|
||||||
cell.radioBox.selectBox()
|
cell.radioBox.selectBox()
|
||||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||||
|
cell.updateAccessibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||||
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
|
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
|
||||||
cell.radioBox.deselectBox()
|
cell.radioBox.deselectBox()
|
||||||
|
cell.updateAccessibility()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,18 @@ open class RadioSwatch: Control {
|
|||||||
return model as? RadioSwatchModel
|
return model as? RadioSwatchModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override var isSelected: Bool {
|
||||||
|
didSet {
|
||||||
|
updateAccessibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var isEnabled: Bool {
|
||||||
|
didSet {
|
||||||
|
updateAccessibility()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -45,9 +57,9 @@ open class RadioSwatch: Control {
|
|||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
guard let model = model as? RadioSwatchModel else { return }
|
guard let model = model as? RadioSwatchModel else { return }
|
||||||
|
bottomText.text = model.text
|
||||||
isSelected = model.selected
|
isSelected = model.selected
|
||||||
isEnabled = model.enabled
|
isEnabled = model.enabled
|
||||||
bottomText.text = model.text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func reset() {
|
public override func reset() {
|
||||||
@ -163,4 +175,17 @@ open class RadioSwatch: Control {
|
|||||||
mask.frame = bounds
|
mask.frame = bounds
|
||||||
return mask
|
return mask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Accessibility
|
||||||
|
public func updateAccessibility() {
|
||||||
|
accessibilityLabel = bottomText.accessibilityLabel ?? bottomText.text
|
||||||
|
|
||||||
|
accessibilityTraits = .button
|
||||||
|
if isSelected {
|
||||||
|
accessibilityTraits.insert(.selected)
|
||||||
|
}
|
||||||
|
if !isEnabled {
|
||||||
|
accessibilityTraits.insert(.notEnabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ open class RadioSwatchCollectionViewCell: CollectionViewCell {
|
|||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
|
isAccessibilityElement = true
|
||||||
addMolecule(radioSwatch)
|
addMolecule(radioSwatch)
|
||||||
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||||
}
|
}
|
||||||
@ -19,5 +20,24 @@ open class RadioSwatchCollectionViewCell: CollectionViewCell {
|
|||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
guard let model = model as? RadioSwatchModel else { return }
|
guard let model = model as? RadioSwatchModel else { return }
|
||||||
radioSwatch.set(with: model, delegateObject, additionalData)
|
radioSwatch.set(with: model, delegateObject, additionalData)
|
||||||
|
updateAccessibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
open func updateAccessibility() {
|
||||||
|
accessibilityLabel = radioSwatch.accessibilityLabel
|
||||||
|
accessibilityHint = radioSwatch.accessibilityHint
|
||||||
|
accessibilityTraits = radioSwatch.accessibilityTraits
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func accessibilityElementDidBecomeFocused() {
|
||||||
|
super.accessibilityElementDidBecomeFocused()
|
||||||
|
radioSwatch.bottomText.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func accessibilityElementDidLoseFocus() {
|
||||||
|
super.accessibilityElementDidLoseFocus()
|
||||||
|
if !radioSwatch.isSelected {
|
||||||
|
radioSwatch.bottomText.isHidden = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,6 +101,13 @@ open class RadioSwatches: View {
|
|||||||
}
|
}
|
||||||
collectionViewHeight?.constant = CGFloat(height)
|
collectionViewHeight?.constant = CGFloat(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open func updateAccessibilityValue(collectionView: UICollectionView, cell: RadioSwatchCollectionViewCell, indexPath: IndexPath) {
|
||||||
|
guard let format = MVMCoreUIUtility.hardcodedString(withKey: "index_string_of_total"),
|
||||||
|
let indexString = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: indexPath.row + 1)) else { return }
|
||||||
|
let total = self.collectionView(collectionView, numberOfItemsInSection: indexPath.section)
|
||||||
|
cell.accessibilityValue = String(format: format, indexString, total)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -128,6 +135,7 @@ extension RadioSwatches: UICollectionViewDataSource {
|
|||||||
if molecule.selected {
|
if molecule.selected {
|
||||||
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
|
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
|
||||||
}
|
}
|
||||||
|
updateAccessibilityValue(collectionView: collectionView, cell: cell, indexPath: indexPath)
|
||||||
cell.layoutIfNeeded()
|
cell.layoutIfNeeded()
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
@ -143,10 +151,12 @@ extension RadioSwatches: UICollectionViewDelegate {
|
|||||||
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
|
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
|
||||||
cell.radioSwatch.selectSwatch()
|
cell.radioSwatch.selectSwatch()
|
||||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||||
|
cell.updateAccessibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||||
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
|
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
|
||||||
cell.radioSwatch.deselectSwatch()
|
cell.radioSwatch.deselectSwatch()
|
||||||
|
cell.updateAccessibility()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,13 +110,10 @@ open class BarsIndicatorView: CarouselIndicator {
|
|||||||
|
|
||||||
var bars = [(View, NSLayoutConstraint)]()
|
var bars = [(View, NSLayoutConstraint)]()
|
||||||
|
|
||||||
let ordinalFormatter = NumberFormatter()
|
|
||||||
ordinalFormatter.numberStyle = .ordinal
|
|
||||||
|
|
||||||
for i in 0..<numberOfPages {
|
for i in 0..<numberOfPages {
|
||||||
let bar = View()
|
let bar = View()
|
||||||
bar.isAccessibilityElement = true
|
bar.isAccessibilityElement = true
|
||||||
if let accessibleValueFormat = accessibilityValueFormat, let accessibleIndex = ordinalFormatter.string(from: NSNumber(value: i + 1)) {
|
if let accessibleValueFormat = accessibilityValueFormat, let accessibleIndex = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: i + 1)) {
|
||||||
bar.accessibilityLabel = String(format: accessibleValueFormat, accessibleIndex, numberOfPages)
|
bar.accessibilityLabel = String(format: accessibleValueFormat, accessibleIndex, numberOfPages)
|
||||||
}
|
}
|
||||||
bar.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccTabHint")
|
bar.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccTabHint")
|
||||||
|
|||||||
@ -225,11 +225,8 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
|
|||||||
|
|
||||||
func formatAccessibilityValue(index: Int, total: Int) {
|
func formatAccessibilityValue(index: Int, total: Int) {
|
||||||
|
|
||||||
let ordinalFormatter = NumberFormatter()
|
|
||||||
ordinalFormatter.numberStyle = .ordinal
|
|
||||||
|
|
||||||
guard let accessibleFormat = accessibilityValueFormat,
|
guard let accessibleFormat = accessibilityValueFormat,
|
||||||
let accessibleIndex = ordinalFormatter.string(from: NSNumber(value: index))
|
let accessibleIndex = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: index))
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
accessibilityValue = String(format: accessibleFormat, accessibleIndex, total)
|
accessibilityValue = String(format: accessibleFormat, accessibleIndex, total)
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"AccCloseButton" = "Close";
|
"AccCloseButton" = "Close";
|
||||||
"swipe_to_select_with_action_hint" = "swipe up or down to select action, then double tap to select.";
|
"swipe_to_select_with_action_hint" = "swipe up or down to select action, then double tap to select.";
|
||||||
"AccDisabled" = "Disabled";
|
"AccDisabled" = "Disabled";
|
||||||
|
"index_string_of_total" = "%@ of %d";
|
||||||
|
|
||||||
// MARK: Tab
|
// MARK: Tab
|
||||||
"AccTab" = ", tab";
|
"AccTab" = ", tab";
|
||||||
@ -59,7 +60,6 @@
|
|||||||
"radio_not_selected_state" = "Not Selected";
|
"radio_not_selected_state" = "Not Selected";
|
||||||
"radio_desc_state" = "Option";
|
"radio_desc_state" = "Option";
|
||||||
|
|
||||||
|
|
||||||
// MARK: Switch / Toggle
|
// MARK: Switch / Toggle
|
||||||
"mfswitch_buttonlabel" = "Switch Button";
|
"mfswitch_buttonlabel" = "Switch Button";
|
||||||
"Toggle_buttonlabel" = "Toggle Button";
|
"Toggle_buttonlabel" = "Toggle Button";
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
// Accessibility
|
// Accessibility
|
||||||
"swipe_to_select_with_action_hint" = "deslízate hacia arriba o hacia abajo para seleccionar la acción, luego toca dos veces para seleccionar.";
|
"swipe_to_select_with_action_hint" = "deslízate hacia arriba o hacia abajo para seleccionar la acción, luego toca dos veces para seleccionar.";
|
||||||
"AccDisabled" = "desactivado";
|
"AccDisabled" = "desactivado";
|
||||||
|
"index_string_of_total" = "%@ de %d";
|
||||||
|
|
||||||
"AccCloseButton" = "Cerrar";
|
"AccCloseButton" = "Cerrar";
|
||||||
// Tab
|
// Tab
|
||||||
|
|||||||
@ -46,6 +46,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
// Removes any format.
|
// Removes any format.
|
||||||
+ (nullable NSString *)removeMdnFormat:(nullable NSString *)mdn;
|
+ (nullable NSString *)removeMdnFormat:(nullable NSString *)mdn;
|
||||||
|
|
||||||
|
/// Returns an ordinal formatted string for a number.
|
||||||
|
+ (nullable NSString *)getOrdinalStringForIndex:(nonnull NSNumber *)number;
|
||||||
|
|
||||||
#pragma mark - Validations
|
#pragma mark - Validations
|
||||||
|
|
||||||
// Will validate passed string on corresponding regular expression
|
// Will validate passed string on corresponding regular expression
|
||||||
|
|||||||
@ -113,6 +113,12 @@
|
|||||||
return mdn;
|
return mdn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (nullable NSString *)getOrdinalStringForIndex:(nonnull NSNumber *)number {
|
||||||
|
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
|
||||||
|
formatter.numberStyle = NSNumberFormatterOrdinalStyle;
|
||||||
|
return [formatter stringFromNumber:number];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Validations
|
#pragma mark - Validations
|
||||||
|
|
||||||
+ (BOOL)validateString:(nonnull NSString *)string withRegularExpression:(nonnull NSString *)regExpression {
|
+ (BOOL)validateString:(nonnull NSString *)string withRegularExpression:(nonnull NSString *)regExpression {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user