From f67392eb6981d84f53685e2a1a681778713a39b5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 10 Jul 2019 09:04:29 -0400 Subject: [PATCH 1/6] Beginning stages of accessibility. --- MVMCoreUI/Atoms/Views/Label.swift | 57 ++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 186c24c8..5a189cb5 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -14,7 +14,7 @@ public typealias ActionBlock = () -> Void @objcMembers open class Label: UILabel, MVMCoreViewProtocol, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol { //------------------------------------------------------ - // MARK: - General Properties + // MARK: - Properties //------------------------------------------------------ public var makeWholeViewClickable = false @@ -63,6 +63,7 @@ public typealias ActionBlock = () -> Void numberOfLines = 0 lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false + isAccessibilityElement = false let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:))) tapGesture.numberOfTapsRequired = 1 @@ -152,7 +153,7 @@ public typealias ActionBlock = () -> Void } //------------------------------------------------------ - // MARK: - Functions + // MARK: - Style //------------------------------------------------------ @objc public static func setLabel(_ label: UILabel?, withHTML html: String?) { @@ -272,12 +273,6 @@ public typealias ActionBlock = () -> Void } } - - - //------------------------------------------------------ - // MARK: - Methods - //------------------------------------------------------ - @objc public func styleH1(_ scale: Bool) { MFStyler.styleLabelH1(self, genericScaling: false) setScale(scale) @@ -567,3 +562,49 @@ extension UITapGestureRecognizer { return NSLocationInRange(indexOfGlyph, targetRange) } } + +// MARK: - Accessibility +extension Label { + + override open func accessibilityActivate() -> Bool { + let point = accessibilityActivationPoint + + return true + } + + open override func accessibilityElementDidBecomeFocused() { + <#code#> + } + + open override func accessibilityElementCount() -> Int { + return accessibleClauses.count + } + + open override func accessibilityElement(at index: Int) -> Any? { + return accessibleClauses[index] + } + + open override func index(ofAccessibilityElement element: Any) -> Int { + return accessibleClauses.firstIndex(of: element as! UIAccessibilityElement)! + } + + var accessibleClauses: [UIAccessibilityElement] { + + var elements = [UIAccessibilityElement]() + + for clause in clauses { + + let element = UIAccessibilityElement(accessibilityContainer: self) + let rect = CGRect(x: 10, y: 10, width: 100, height: 30) + element.accessibilityFrame = rect +// element.accessibilityFrame = convert(conceptualSize(range: clause.range)!, to: nil) + element.accessibilityFrameInContainerSpace = rect + element.accessibilityLabel = "Testing" + element.accessibilityTraits = .button + element.isAccessibilityElement = true + elements.append(element) + } + accessibilityElements = elements + return elements + } +} From 244e3c0df3146c90f686dd42db58c9ef4acb1cd4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 10 Jul 2019 13:15:35 -0400 Subject: [PATCH 2/6] Generally functioning. A ways to go. --- MVMCoreUI/Atoms/Views/Label.swift | 61 +++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 5a189cb5..38fef66f 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -40,7 +40,16 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var clauses: [ActionableClause] = [] { - didSet { isUserInteractionEnabled = !clauses.isEmpty } + didSet { + isUserInteractionEnabled = !clauses.isEmpty + + // Accessibility + let element = UIAccessibilityElement(accessibilityContainer: self) + element.accessibilityFrameInContainerSpace = convert(boundingRect(forCharacterRange: clauses.last!.range!), to: nil) //CGRect(x: 10, y: 10, width: 100, height: 30) + element.accessibilityLabel = "Testing" + element.accessibilityTraits = .button + accessibilityElements?.append(element) + } } /// Used for tappable links in the text. @@ -64,10 +73,7 @@ public typealias ActionBlock = () -> Void lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false isAccessibilityElement = false - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:))) - tapGesture.numberOfTapsRequired = 1 - addGestureRecognizer(tapGesture) + accessibilityElements = [] } @objc public init() { @@ -410,6 +416,7 @@ extension Label { originalAttributedString = nil hasAttachmentImage = false styleB2(true) + accessibilityElements = [] } @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -450,6 +457,7 @@ extension Label { } self.attributedText = mutableAttributedString +// accessibleClauses = [] clauses = [] } @@ -567,38 +575,36 @@ extension UITapGestureRecognizer { extension Label { override open func accessibilityActivate() -> Bool { - let point = accessibilityActivationPoint - +// let point = accessibilityActivationPoint return true } open override func accessibilityElementDidBecomeFocused() { - <#code#> + } open override func accessibilityElementCount() -> Int { - return accessibleClauses.count + return accessibilityElements?.count ?? 0 } open override func accessibilityElement(at index: Int) -> Any? { - return accessibleClauses[index] + return accessibilityElements?[index] } open override func index(ofAccessibilityElement element: Any) -> Int { - return accessibleClauses.firstIndex(of: element as! UIAccessibilityElement)! + return 0//accessibilityElements?.firstIndex(of: element as! UIAccessibilityElement)! } + /* var accessibleClauses: [UIAccessibilityElement] { var elements = [UIAccessibilityElement]() - for clause in clauses { - let element = UIAccessibilityElement(accessibilityContainer: self) - let rect = CGRect(x: 10, y: 10, width: 100, height: 30) - element.accessibilityFrame = rect +// let rect = CGRect(x: 10, y: 10, width: 100, height: 30) + element.accessibilityFrame = convert(self.frame, to: nil) // element.accessibilityFrame = convert(conceptualSize(range: clause.range)!, to: nil) - element.accessibilityFrameInContainerSpace = rect +// element.accessibilityFrameInContainerSpace = rect element.accessibilityLabel = "Testing" element.accessibilityTraits = .button element.isAccessibilityElement = true @@ -607,4 +613,27 @@ extension Label { accessibilityElements = elements return elements } + */ + + func boundingRect(forCharacterRange range: NSRange) -> CGRect? { + + guard let attributedText = attributedText else { return nil } + + let textStorage = NSTextStorage(attributedString: attributedText) + let layoutManager = NSLayoutManager() + + textStorage.addLayoutManager(layoutManager) + + let textContainer = NSTextContainer(size: bounds.size) + textContainer.lineFragmentPadding = 0.0 + + layoutManager.addTextContainer(textContainer) + + var glyphRange = NSRange() + + // Convert the range for glyphs. + layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) + + return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) + } } From 67754676067cbb02e70839804ea37654d2f94b09 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 11 Jul 2019 11:43:33 -0400 Subject: [PATCH 3/6] Accessibility update for Label and LabelWithInternalButton. --- MVMCoreUI/Atoms/Views/Label.swift | 118 ++++++------------ .../Atoms/Views/LabelWithInternalButton.swift | 6 +- .../Strings/en.lproj/Localizable.strings | 1 + 3 files changed, 45 insertions(+), 80 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 38fef66f..1b1d622e 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -40,22 +40,15 @@ public typealias ActionBlock = () -> Void //------------------------------------------------------ public var clauses: [ActionableClause] = [] { - didSet { - isUserInteractionEnabled = !clauses.isEmpty - - // Accessibility - let element = UIAccessibilityElement(accessibilityContainer: self) - element.accessibilityFrameInContainerSpace = convert(boundingRect(forCharacterRange: clauses.last!.range!), to: nil) //CGRect(x: 10, y: 10, width: 100, height: 30) - element.accessibilityLabel = "Testing" - element.accessibilityTraits = .button - accessibilityElements?.append(element) - } + didSet { isUserInteractionEnabled = !clauses.isEmpty } } /// Used for tappable links in the text. public struct ActionableClause { var range: NSRange? var actionBlock: ActionBlock? + var text: String? + var hash: Int = 0 func performAction() { actionBlock?() @@ -72,8 +65,7 @@ public typealias ActionBlock = () -> Void numberOfLines = 0 lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false - isAccessibilityElement = false - accessibilityElements = [] + accessibilityCustomActions = [] } @objc public init() { @@ -267,10 +259,14 @@ public typealias ActionBlock = () -> Void 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 accessibleAction = actionLabel.customAccessibilityAction(range: range) + let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate) + let actionableClause = ActionableClause(range: range, + actionBlock: actionBlock, + text: accessibleAction?.name ?? "", + hash: accessibleAction?.hash ?? -1) + actionLabel.clauses.append(actionableClause) + default: continue } @@ -416,7 +412,7 @@ extension Label { originalAttributedString = nil hasAttachmentImage = false styleB2(true) - accessibilityElements = [] + accessibilityCustomActions = [] } @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -457,7 +453,7 @@ extension Label { } self.attributedText = mutableAttributedString -// accessibleClauses = [] + accessibilityElements = [] clauses = [] } @@ -495,7 +491,9 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { setActionAttributes(range: range) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock)) + let actionText = NSString(string: text!).substring(with: range) + let accessibleAction = customAccessibilityAction(range: range) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) } /** @@ -511,10 +509,10 @@ 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 actionText = NSString(string: text!).substring(with: range) + let accessibleAction = customAccessibilityAction(range: range) + let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) } @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { @@ -574,66 +572,28 @@ extension UITapGestureRecognizer { // MARK: - Accessibility extension Label { - override open func accessibilityActivate() -> Bool { -// let point = accessibilityActivationPoint - return true - } - - open override func accessibilityElementDidBecomeFocused() { + func customAccessibilityAction(range: NSRange) -> UIAccessibilityCustomAction? { - } - - open override func accessibilityElementCount() -> Int { - return accessibilityElements?.count ?? 0 - } - - open override func accessibilityElement(at index: Int) -> Any? { - return accessibilityElements?[index] - } - - open override func index(ofAccessibilityElement element: Any) -> Int { - return 0//accessibilityElements?.firstIndex(of: element as! UIAccessibilityElement)! - } - - /* - var accessibleClauses: [UIAccessibilityElement] { - - var elements = [UIAccessibilityElement]() - for clause in clauses { - let element = UIAccessibilityElement(accessibilityContainer: self) -// let rect = CGRect(x: 10, y: 10, width: 100, height: 30) - element.accessibilityFrame = convert(self.frame, to: nil) -// element.accessibilityFrame = convert(conceptualSize(range: clause.range)!, to: nil) -// element.accessibilityFrameInContainerSpace = rect - element.accessibilityLabel = "Testing" - element.accessibilityTraits = .button - element.isAccessibilityElement = true - elements.append(element) + guard let text = text else { return nil } + + if accessibilityHint == nil { + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") } - accessibilityElements = elements - return elements + + let actionText = NSString(string: text).substring(with: range) + let accessibleAction = UIAccessibilityCustomAction(name: actionText, target: self, selector: #selector(accessibilityCustomAction(_:))) + accessibilityCustomActions?.append(accessibleAction) + + return accessibleAction } - */ - func boundingRect(forCharacterRange range: NSRange) -> CGRect? { + @objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) { - guard let attributedText = attributedText else { return nil } - - let textStorage = NSTextStorage(attributedString: attributedText) - let layoutManager = NSLayoutManager() - - textStorage.addLayoutManager(layoutManager) - - let textContainer = NSTextContainer(size: bounds.size) - textContainer.lineFragmentPadding = 0.0 - - layoutManager.addTextContainer(textContainer) - - var glyphRange = NSRange() - - // Convert the range for glyphs. - layoutManager.characterRange(forGlyphRange: range, actualGlyphRange: &glyphRange) - - return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) + for clause in clauses { + if action.hash == clause.hash { + clause.performAction() + return + } + } } } diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 5cc6d50b..c8a83862 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -64,7 +64,11 @@ 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, text: actionText ?? "", hash: accessibleAction.hash)] + label.accessibilityCustomActions = [accessibleAction] } } } diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 96088cab..bbf3f6d8 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -8,6 +8,7 @@ //// Accessibility "AccCloseButton" = "Close"; +"plan_selector_int_swipe_action_hint" = "swipe up or down to select action, then double tap to select."; // Tab "AccTab" = ", tab"; "AccTabHint" = "Double tap to select."; From 80c6e7e74ff283debbb9a92b2aaca036a93d4094 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 11 Jul 2019 12:00:49 -0400 Subject: [PATCH 4/6] Removed text from ActionableClause; unneeded. --- MVMCoreUI/Atoms/Views/Label.swift | 13 ++++--------- MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift | 6 +++++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 1b1d622e..b46f8ac7 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -47,7 +47,7 @@ public typealias ActionBlock = () -> Void public struct ActionableClause { var range: NSRange? var actionBlock: ActionBlock? - var text: String? +// var text: String? var hash: Int = 0 func performAction() { @@ -261,10 +261,7 @@ public typealias ActionBlock = () -> Void actionLabel.addActionAttributes(range: range, string: attributedString) let accessibleAction = actionLabel.customAccessibilityAction(range: range) let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate) - let actionableClause = ActionableClause(range: range, - actionBlock: actionBlock, - text: accessibleAction?.name ?? "", - hash: accessibleAction?.hash ?? -1) + let actionableClause = ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1) actionLabel.clauses.append(actionableClause) default: @@ -491,9 +488,8 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { setActionAttributes(range: range) - let actionText = NSString(string: text!).substring(with: range) let accessibleAction = customAccessibilityAction(range: range) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) } /** @@ -509,10 +505,9 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { setActionAttributes(range: range) - let actionText = NSString(string: text!).substring(with: range) let accessibleAction = customAccessibilityAction(range: range) let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, text: actionText, hash: accessibleAction!.hash)) + clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) } @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index c8a83862..39b996a2 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -67,8 +67,12 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt 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, text: actionText ?? "", hash: accessibleAction.hash)] + label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, hash: accessibleAction.hash)] label.accessibilityCustomActions = [accessibleAction] + + if label.accessibilityHint == nil { + label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") + } } } } From c2a432fd25ae60cfe4f45be2fd042bc6cb57cc02 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 29 Aug 2019 14:58:02 -0400 Subject: [PATCH 5/6] Updated localizable strings to include spanish. Renamed the variable to be more in line with its generic purpose. --- MVMCoreUI/Atoms/Views/Label.swift | 2 +- MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings | 2 +- .../SupportingFiles/Strings/es-MX.lproj/Localizable.strings | 3 +++ MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 635c45a9..36843803 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -584,7 +584,7 @@ extension Label { guard let text = text else { return nil } if accessibilityHint == nil { - accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint") } let actionText = NSString(string: text).substring(with: range) diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 54b09109..4812d697 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -8,7 +8,7 @@ //// Accessibility "AccCloseButton" = "Close"; -"plan_selector_int_swipe_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."; // Tab "AccTab" = ", tab"; "AccTabHint" = "Double tap to select."; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index bf4f4e47..d6505503 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -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"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index bf4f4e47..d6505503 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -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"; From 33754802bb7aac8d27503fc8a773dfdfc5657dfb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 5 Sep 2019 11:20:55 -0400 Subject: [PATCH 6/6] Latest changes. Now including clause changes. --- MVMCoreUI/Atoms/Views/Label.swift | 36 +++++++++++++------ .../Atoms/Views/LabelWithInternalButton.swift | 4 +-- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 5624bb20..ed99fcac 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -56,13 +56,22 @@ public typealias ActionBlock = () -> () public struct ActionableClause { var range: NSRange? var actionBlock: ActionBlock? - var hash: Int = 0 + 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 //------------------------------------------------------ @@ -73,6 +82,7 @@ public typealias ActionBlock = () -> () numberOfLines = 0 lineBreakMode = .byWordWrapping translatesAutoresizingMaskIntoConstraints = false + clauses = [] accessibilityCustomActions = [] let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped(_:))) @@ -295,9 +305,8 @@ public typealias ActionBlock = () -> () guard let actionLabel = label as? Label else { continue } actionLabel.addActionAttributes(range: range, string: attributedString) - let accessibleAction = actionLabel.customAccessibilityAction(range: range) let actionBlock = actionLabel.createActionBlockFrom(actionMap: json, additionalData: additionalData, delegateObject: delegate) - actionLabel.clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) + actionLabel.appendActionableClause(range: range, actionBlock: actionBlock) default: continue @@ -402,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() { @@ -419,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) { @@ -487,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 @@ -499,6 +514,7 @@ extension Label { originalAttributedString = nil styleB2(true) accessibilityCustomActions = [] + clauses = [] } @objc public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -527,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 } @@ -576,8 +592,7 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionBlock: @escaping ActionBlock) { setActionAttributes(range: range) - let accessibleAction = customAccessibilityAction(range: range) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) + appendActionableClause(range: range, actionBlock: actionBlock) } /** @@ -592,9 +607,8 @@ extension Label { @objc public func addTappableLinkAttribute(range: NSRange, actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) { setActionAttributes(range: range) - let accessibleAction = customAccessibilityAction(range: range) let actionBlock = createActionBlockFrom(actionMap: actionMap, additionalData: additionalData, delegateObject: delegateObject) - clauses.append(ActionableClause(range: range, actionBlock: actionBlock, hash: accessibleAction?.hash ?? -1)) + appendActionableClause(range: range, actionBlock: actionBlock) } @objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) { @@ -668,7 +682,7 @@ extension Label { @objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) { for clause in clauses { - if action.hash == clause.hash { + if action.hash == clause.accessibilityID { clause.performAction() return } diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index 39b996a2..bc1c2219 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -67,11 +67,11 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt 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, hash: accessibleAction.hash)] + label.clauses = [Label.ActionableClause(range: actionRange, actionBlock: newActionBlock, accessibilityID: accessibleAction.hash)] label.accessibilityCustomActions = [accessibleAction] if label.accessibilityHint == nil { - label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "plan_selector_int_swipe_action_hint") + label.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint") } } }