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