From 4ed12bb2d346ccabee46a0b5a65d21ef5c2fce55 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 13 Jun 2025 15:05:42 +0200 Subject: [PATCH] A11Y: improve accessibility on event reactions. --- .../components/MessagesReactionButton.kt | 59 ++++++++++++++++++- .../impl/src/main/res/values/localazy.xml | 11 +++- .../messages/impl/MessagesViewTest.kt | 10 +++- .../src/main/res/values/localazy.xml | 1 + 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt index 46133b69a7..30f48d7662 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/MessagesReactionButton.kt @@ -28,7 +28,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.onClick import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -47,6 +51,7 @@ import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.ui.media.MediaRequestData +import io.element.android.libraries.ui.strings.CommonStrings @Composable @Suppress("ModifierClickableOrder") // This is needed to display the right ripple shape @@ -68,6 +73,47 @@ fun MessagesReactionButton( buttonColor } + val a11yText = when (content) { + is MessagesReactionsButtonContent.Icon -> stringResource(id = R.string.screen_room_timeline_add_reaction) + is MessagesReactionsButtonContent.Text -> content.text + is MessagesReactionsButtonContent.Reaction -> { + val reaction = if (content.reaction.key.startsWith("mxc://")) { + stringResource(CommonStrings.common_an_image) + } else { + content.reaction.key + } + if (content.isHighlighted) { + if (content.reaction.count == 1) { + stringResource(R.string.screen_room_timeline_reaction_you_a11y, reaction) + } else { + pluralStringResource( + R.plurals.screen_room_timeline_reaction_including_you_a11y, + content.reaction.count - 1, + content.reaction.count - 1, + reaction, + ) + } + } else { + pluralStringResource( + R.plurals.screen_room_timeline_reaction_a11y, + content.reaction.count, + content.reaction.count, + reaction, + ) + } + } + } + + val a11yClickLabel = if (content is MessagesReactionsButtonContent.Reaction) { + if (content.isHighlighted) { + stringResource(id = CommonStrings.a11y_remove_reaction_with, content.reaction.key) + } else { + stringResource(id = CommonStrings.a11y_react_with, content.reaction.key) + } + } else { + "" + } + Surface( modifier = modifier .background(Color.Transparent) @@ -86,7 +132,18 @@ fun MessagesReactionButton( // Inner border, to highlight when selected .border(BorderStroke(1.dp, borderColor), RoundedCornerShape(corner = CornerSize(12.dp))) .background(buttonColor, RoundedCornerShape(corner = CornerSize(12.dp))) - .padding(vertical = 4.dp, horizontal = 10.dp), + .padding(vertical = 4.dp, horizontal = 10.dp) + .clearAndSetSemantics { + contentDescription = a11yText + if (content is MessagesReactionsButtonContent.Reaction) { + onClick( + label = a11yClickLabel + ) { + onClick() + true + } + } + }, color = buttonColor ) { when (content) { diff --git a/features/messages/impl/src/main/res/values/localazy.xml b/features/messages/impl/src/main/res/values/localazy.xml index 73d266f799..704ba6ed05 100644 --- a/features/messages/impl/src/main/res/values/localazy.xml +++ b/features/messages/impl/src/main/res/values/localazy.xml @@ -28,13 +28,22 @@ "Everyone" "Send again" "Your message failed to send" - "Add emoji" + "Add a reaction" "This is the beginning of %1$s." "This is the beginning of this conversation." "Unsupported call. Ask if the caller can use the new Element X app." "Show less" "Message copied" "You do not have permission to post to this room" + + "%1$d member reacted with %2$s" + "%1$d members reacted with %2$s" + + + "You and %1$d member reacted with %2$s" + "You and %1$d members reacted with %2$s" + + "You reacted with %1$s" "Show less" "Show more" "New" diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt index 4f6ac91890..d433614537 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt @@ -391,7 +391,10 @@ class MessagesViewTest { rule.setMessagesView( state = state, ) - rule.onAllNodesWithText("👍️").onFirst().performClick() + rule.onAllNodesWithText( + text = "👍️", + useUnmergedTree = true, + ).onFirst().performClick() eventsRecorder.assertSingle(MessagesEvents.ToggleReaction("👍️", timelineItem.eventOrTransactionId)) } @@ -411,7 +414,10 @@ class MessagesViewTest { rule.setMessagesView( state = state, ) - rule.onAllNodesWithText("👍️").onFirst().performTouchInput { longClick() } + rule.onAllNodesWithText( + text = "👍️", + useUnmergedTree = true, + ).onFirst().performTouchInput { longClick() } eventsRecorder.assertSingle(ReactionSummaryEvents.ShowReactionSummary(timelineItem.eventId!!, timelineItem.reactionsState.reactions, "👍️")) } diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 21004580f1..1a2052eb51 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -144,6 +144,7 @@ "Acceptable use policy" "Adding caption" "Advanced settings" + "an image" "Analytics" "Appearance" "Audio"