Merge branch 'feature/label_accessibility' into 'develop'

Label Accessibility

See merge request BPHV_MIPS/mvm_core_ui!96
This commit is contained in:
Pfeil, Scott Robert 2019-09-05 13:53:56 -04:00
commit 814d470775
5 changed files with 77 additions and 15 deletions

View File

@ -14,7 +14,7 @@ public typealias ActionBlock = () -> ()
@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol {
//------------------------------------------------------
// MARK: - General Properties
// MARK: - Properties
//------------------------------------------------------
public var makeWholeViewClickable = false
@ -56,12 +56,22 @@ public typealias ActionBlock = () -> ()
public struct ActionableClause {
var range: NSRange?
var actionBlock: ActionBlock?
var accessibilityID: Int = 0
func performAction() {
actionBlock?()
}
}
//------------------------------------------------------
// MARK: - Convenience Setter For objective-C
//------------------------------------------------------
/// Sets the clauses array to empty.
@objc public func setEmptyClauses() {
clauses = []
}
//------------------------------------------------------
// MARK: - Initialization
//------------------------------------------------------
@ -72,6 +82,8 @@ public typealias ActionBlock = () -> ()
numberOfLines = 0
lineBreakMode = .byWordWrapping
translatesAutoresizingMaskIntoConstraints = false
clauses = []
accessibilityCustomActions = []
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:)))
tapGesture.numberOfTapsRequired = 1
@ -164,7 +176,7 @@ public typealias ActionBlock = () -> ()
}
//------------------------------------------------------
// MARK: - Functions
// MARK: - Style
//------------------------------------------------------
@objc public static func setLabel(_ label: UILabel?, withHTML html: String?) {
@ -293,10 +305,9 @@ public typealias ActionBlock = () -> ()
guard let actionLabel = label as? Label else { continue }
actionLabel.addActionAttributes(range: range, string: attributedString)
actionLabel.clauses.append(ActionableClause(range: range,
actionBlock: actionLabel.createActionBlockFrom(actionMap: json,
additionalData: additionalData,
delegateObject: delegate)))
let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate)
actionLabel.appendActionableClause(range: range, actionBlock: actionBlock)
default:
continue
}
@ -400,7 +411,7 @@ public typealias ActionBlock = () -> ()
/**
Appends an external link image to the end of the attributed string.
Will provide one whitespace to the left of the icon
Will provide one whitespace to the left of the icon; adds 2 chars to the end of the string.
*/
@objc public func appendExternalLinkIcon() {
@ -417,7 +428,7 @@ public typealias ActionBlock = () -> ()
Insert external link icon anywhere within text of Label.
- Note: Each icon insertion adds 1 additional characters to the overall text length.
Therefore, you MUST insert icons and links in the order they would appear.
Therefore, you **MUST** insert icons and links in the order they would appear.
- parameter index: Location within the associated text to insert an external Link Icon
*/
public func insertExternalLinkIcon(at index: Int) {
@ -485,6 +496,12 @@ public typealias ActionBlock = () -> ()
return containsAttachment
}
func appendActionableClause(range: NSRange, actionBlock: @escaping ActionBlock) {
let accessibleAction = customAccessibilityAction(range: range)
clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1))
}
}
// MARK: - Atomization
@ -496,6 +513,8 @@ extension Label {
textAlignment = .left
originalAttributedString = nil
styleB2(true)
accessibilityCustomActions = []
clauses = []
}
@objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
@ -524,7 +543,7 @@ extension Label {
// MARK: - Multi-Action Functionality
extension Label {
/// Reseting to default Label values.
/// Applied to existing text. Removes underlines of tappable links and assoated actionable clauses.
@objc public func clearActionableClauses() {
guard let attributedText = attributedText else { return }
@ -536,6 +555,7 @@ extension Label {
}
self.attributedText = mutableAttributedString
accessibilityElements = []
clauses = []
}
@ -572,7 +592,7 @@ extension Label {
@objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) {
setActionAttributes(range: range)
clauses.append(ActionableClause(range: range, actionBlock: actionBlock))
appendActionableClause(range: range, actionBlock: actionBlock)
}
/**
@ -587,10 +607,8 @@ extension Label {
@objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
setActionAttributes(range: range)
clauses.append(ActionableClause(range: range,
actionBlock: createActionBlockFrom(actionMap: actionMap,
additionalData: additionalData,
delegateObject: delegateObject)))
let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject)
appendActionableClause(range: range, actionBlock: actionBlock)
}
@objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) {
@ -642,3 +660,32 @@ extension UITapGestureRecognizer {
return NSLocationInRange(indexOfGlyph, targetRange)
}
}
// MARK: - Accessibility
extension Label {
func customAccessibilityAction(range: NSRange) -> UIAccessibilityCustomAction? {
guard let text = text else { return nil }
if accessibilityHint == nil {
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint")
}
let actionText = NSString(string: text).substring(with: range)
let accessibleAction = UIAccessibilityCustomAction(name: actionText, target: self, selector: #selector(accessibilityCustomAction(_:)))
accessibilityCustomActions?.append(accessibleAction)
return accessibleAction
}
@objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) {
for clause in clauses {
if action.hash == clause.accessibilityID {
clause.performAction()
return
}
}
}
}

View File

@ -64,7 +64,15 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt
if newActionBlock == nil {
label?.clearActionableClauses()
} else {
label?.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock)]
guard let label = label else { return }
let accessibleAction = UIAccessibilityCustomAction(name: actionText ?? "", target: label, selector: #selector(label.accessibilityCustomAction(_:)))
label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, accessibilityID: accessibleAction.hash)]
label.accessibilityCustomActions = [accessibleAction]
if label.accessibilityHint == nil {
label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint")
}
}
}
}

View File

@ -8,6 +8,7 @@
//// Accessibility
"AccCloseButton" = "Close";
"swipe_to_select_with_action_hint" = "swipe up or down to select action, then double tap to select.";
// Tab
"AccTab" = ", tab";
"AccTabHint" = "Double tap to select.";

View File

@ -6,6 +6,9 @@
Copyright © 2017 myverizon. All rights reserved.
*/
// 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.";
"AccCloseButton" = "Cerrar";
// Tab
"AccTab" = ", pestaña";

View File

@ -6,6 +6,9 @@
Copyright © 2017 myverizon. All rights reserved.
*/
// 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.";
"AccCloseButton" = "Cerrar";
// Tab
"AccTab" = ", pestaña";