Improve accessibility of the timeline (#4579)

* Make whole messages selectable and readable as a single unit when possible.
* Make most UI components not clickable when talkback is enabled.
* Make voice messages work with talkback too.
* Read grouped state events even if the events are collapsed.
* Move image and video item actions to the timeline item.
* Improve accessibility in the message context menu too
* Fix a11y issue on add attachment button.
* Add `contentDescription` to file icon so it's read aloud

---------

Co-authored-by: Benoit Marty <benoit@matrix.org>
This commit is contained in:
Jorge Martin Espinosa 2025-04-15 17:28:29 +02:00 committed by GitHub
parent f9c00ac99d
commit 740c28eda9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 226 additions and 70 deletions

View file

@ -24,7 +24,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.traversalIndex
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@ -58,7 +60,7 @@ fun InReplyToView(
senderId = inReplyTo.senderId,
senderProfile = inReplyTo.senderProfile,
metadata = inReplyTo.metadata(hideImage),
modifier = modifier
modifier = modifier,
)
}
is InReplyToDetails.Error ->
@ -96,13 +98,18 @@ private fun ReplyToReadyContent(
Spacer(modifier = Modifier.width(8.dp))
}
val a11InReplyToText = stringResource(CommonStrings.common_in_reply_to, senderProfile.getDisambiguatedDisplayName(senderId))
Column(verticalArrangement = Arrangement.SpaceBetween) {
Column(
modifier = Modifier.semantics(mergeDescendants = false) { isTraversalGroup = true },
verticalArrangement = Arrangement.SpaceBetween
) {
SenderName(
senderId = senderId,
senderProfile = senderProfile,
senderNameMode = SenderNameMode.Reply,
modifier = Modifier.semantics {
contentDescription = a11InReplyToText
isTraversalGroup = true
traversalIndex = 1f
},
)
ReplyToContentText(metadata)
@ -169,6 +176,10 @@ private fun ReplyToContentText(metadata: InReplyToMetadata?) {
else -> FontStyle.Normal
}
Row(
modifier = Modifier.semantics(mergeDescendants = false) {
isTraversalGroup = true
traversalIndex = -1f
},
verticalAlignment = Alignment.CenterVertically,
) {
if (iconResourceId != null) {