Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility on Cards. #86

Merged
merged 24 commits into from
Feb 23, 2021

Conversation

JulianAlonso
Copy link
Contributor

Hi!

Set card accessibilityElement to true when it has no buttons, if it has buttons isn't set because if we set the card as an unique accesible element for voiceover the buttons are not accesibles, like if them doesn't exists.

If a user uses the card as a button he must set the traits.

@JulianAlonso JulianAlonso requested a review from a team February 10, 2021 17:12
@JulianAlonso JulianAlonso self-assigned this Feb 10, 2021
@JulianAlonso JulianAlonso requested review from gonzalezreal and jmbrocal and removed request for a team February 10, 2021 17:12
Comment on lines 111 to 116
accessibilityLabel = [
title,
headline,
subtitle,
descriptionTitle
].compactMap { $0 }.joined(separator: " ")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in the future we should ask product for a good definition on how this accessibility label should be composed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following , they read all the items on their cards like we do in this case.

gonzalezreal
gonzalezreal previously approved these changes Feb 11, 2021
Copy link
Contributor

@gonzalezreal gonzalezreal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. Thanks for doing this!

@jmbrocal
Copy link
Contributor

Hi!

Set card accessibilityElement to true when it has no buttons, if it has buttons isn't set because if we set the card as an unique accesible element for voiceover the buttons are not accesibles, like if them doesn't exists.

If a user uses the card as a button he must set the traits.

I am not sure about the proposed implementation, I think that it is not the best voice over experience for elements like Card o List.

With the proposed implementation the voice over will handle a card like a unique element but what will happens with media cards or cards with fragments?

I was researching about how voice over works in other apps. For example the feed of the Apple Store app is built with a mix of cards and lists, the elements of the feed have different interactions with voice over.

For example, they have a card which interacts like a single element (for me this card is very similar to our HighlitedCard but without buttons)

They also have rows with texts and a buttons. This element interacts with voice in two steps: the texts and the button

They also have media cards: a video and texts, this elements interacts with the voice over for each subview

I think, we should try to replicate some of the above behaviours but always allowing to be customized.

@gonzalezreal
Copy link
Contributor

Hi!
Set card accessibilityElement to true when it has no buttons, if it has buttons isn't set because if we set the card as an unique accesible element for voiceover the buttons are not accesibles, like if them doesn't exists.
If a user uses the card as a button he must set the traits.

I am not sure about the proposed implementation, I think that it is not the best voice over experience for elements like Card o List.

With the proposed implementation the voice over will handle a card like a unique element but what will happens with media cards or cards with fragments?

I was researching about how voice over works in other apps. For example the feed of the Apple Store app is built with a mix of cards and lists, the elements of the feed have different interactions with voice over.

For example, they have a card which interacts like a single element (for me this card is very similar to our HighlitedCard but without buttons)

They also have rows with texts and a buttons. This element interacts with voice in two steps: the texts and the button

They also have media cards: a video and texts, this elements interacts with the voice over for each subview

I think, we should try to replicate some of the above behaviours but always allowing to be customized.

Where is the PRD? 😄
IMO product should define this behaviour. Maybe I am wrong, but I suspect that this issue is the result of the accessibility report made by O2, which has been translated to a set of JIRA tickets, without anyone in product checking whether or not it makes sense.

@JulianAlonso
Copy link
Contributor Author

Hi!
Set card accessibilityElement to true when it has no buttons, if it has buttons isn't set because if we set the card as an unique accesible element for voiceover the buttons are not accesibles, like if them doesn't exists.
If a user uses the card as a button he must set the traits.

I am not sure about the proposed implementation, I think that it is not the best voice over experience for elements like Card o List.

With the proposed implementation the voice over will handle a card like a unique element but what will happens with media cards or cards with fragments?

I was researching about how voice over works in other apps. For example the feed of the Apple Store app is built with a mix of cards and lists, the elements of the feed have different interactions with voice over.

For example, they have a card which interacts like a single element (for me this card is very similar to our HighlitedCard but without buttons)

Sure, currently, if we don't have buttons, the card works like a single element.

They also have rows with texts and a buttons. This element interacts with voice in two steps: the texts and the button

Yes, but (I don't know how  is doing that) if we put the card as an accessibility element like  does, we lose the interaction with the buttons. So we must threat each element as a unique element.
Even if we pass the buttons as accessibilityElements = [button], them still remain hided.

They also have media cards: a video and texts, this elements interacts with the voice over for each subview

I think, we should try to replicate some of the above behaviours but always allowing to be customized.

There are limits on the customisation, I mean, if we don't expose the views we don't allow the user to set the accessibility of them. In this case, all the views inside the cardds are private.
For the card, if the user doesn't have any button set and configure the card with a tapGesture the user still si able to set the accessibility traits of the view.

@jmbrocal
Copy link
Contributor

Sure, currently, if we don't have buttons, the card works like a single element.

But the proposed implementation is breaking a card with fragment but without buttons because the fragment view will be invisible for the voice over.

Yes, but (I don't know how  is doing that) if we put the card as an accessibility element like  does, we lose the interaction with the buttons. So we must threat each element as a unique element.
Even if we pass the buttons as accessibilityElements = [button], them still remain hided.

There are limits on the customisation, I mean, if we don't expose the views we don't allow the user to set the accessibility of them. In this case, all the views inside the cardds are private.
For the card, if the user doesn't have any button set and configure the card with a tapGesture the user still si able to set the accessibility traits of the view.

I think we can get something similar to what Apple does...

My point is, we evaluate a set of cards (only texts, buttons, fragments, media, etc) and try to define a behaviour for them but keeping the possibility to be customised by a user of it component.

Maybe as Guille says, we should move this topic with design core and other platforms (web and android).

@JulianAlonso
Copy link
Contributor Author

Update

Used UIAccessibilityElement on cards to improve accessibility.
Now cards are selected as an unique element, but also the user is able to focus the buttons.
If a fragment view is provided it will be also focusable so the user is responsible of the view's accessibility.
Did override accessibility traits of the Card to forward them to the accessibility element traits.

@@ -57,6 +58,18 @@ public class MediaCard: UIView {
}
}

override public var accessibilityElements: [Any]? {
get {
accessibilityElement.accessibilityFrameInContainerSpace = bounds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to have a commet describing why are we doing this here.

Comment on lines 139 to 146
override var accessibilityTraits: UIAccessibilityTraits {
get {
accessibilityElement.accessibilityTraits
}
set {
accessibilityElement.accessibilityTraits = newValue
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this override?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The card isn't accessible, because the accessibilityElement is what we are making accessible. So, if we want to update the trait of the card, usually as button, we need to set that trait to the accessibilityElement

Copy link
Contributor

@jmbrocal jmbrocal Feb 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, but why do we need this override? I mean, in my tests adding the traits to the custom accessibility element is good enough. Did you find some issue without overriding?

Also, if the accessibility element has a trait of type button, which action is fire after tap?

My fault, I was thinking that the trait was set to cardAccessibilityElement but it is not.

Comment on lines 225 to 230
accessibilityElement.accessibilityLabel = [
configuration.headline,
configuration.title,
configuration.subtitle,
configuration.descriptionTitle
].compactMap { $0 }.joined(separator: " ")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if we should use the headline text or the accessibilityLabel... My concern is that the accessibilityLabel of headline can be different from the text.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 True, the label could be different, I'll update it.

@@ -63,6 +63,7 @@ public class DataCard: UIView {
static let largeIconSize = CGFloat(24)
}

private lazy var accessibilityElement = UIAccessibilityElement(accessibilityContainer: self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would named it like: cardAccessibilityElement

@@ -31,6 +31,7 @@ public class HighlightedCard: UIView {
case secondary
}

private lazy var accessibilityElement = UIAccessibilityElement(accessibilityContainer: self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same than above

accessibilityElement.accessibilityFrameInContainerSpace = bounds
return [
accessibilityElement,
fragmentView as Any,
Copy link
Contributor

@jmbrocal jmbrocal Feb 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this cast?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid the Xcode warning about your implicitly casting from N to Any.

@jmbrocal
Copy link
Contributor

Good work improving the accessibility of cards! But I have some suggestions:

I am missing documentation about how the user can add support to voice over for the fragment view. I am thinking in documentation about how the user can make the fragment view as unique accessibility element or as multiple accessibility elements.

If I am not wrong, for the RichMedia card we are not adding the media as part of the accessibility element. I am thinking in a card with a video.

Copy link
Contributor

@jmbrocal jmbrocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

200

@JulianAlonso JulianAlonso merged commit 3bbe36b into main Feb 23, 2021
@JulianAlonso JulianAlonso deleted the apps/cards_as_unique_element_for_voiceover branch February 23, 2021 11:37
tuentisre pushed a commit that referenced this pull request Feb 24, 2021
## [9.0.1](v9.0.0...v9.0.1) (2021-02-24)

### Bug Fixes

* **Accessibility:** improve Accessibility on Cards. Update Cards docs ([#86](#86)) ([3bbe36b](3bbe36b))
@tuentisre
Copy link
Collaborator

🎉 This PR is included in version 9.0.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants