From 44940fc0933fdea2aa19b77364dc05aec44770c6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 19 Jun 2025 17:08:05 +0200 Subject: [PATCH 1/2] a11y: improve accessibility on grouped state events header. --- .../components/TimelineItemGroupedEventsRow.kt | 12 ------------ .../timeline/components/group/GroupHeaderView.kt | 14 +++++++++++++- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt index 45ff052ee6..c98cf24426 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt @@ -14,8 +14,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.res.pluralStringResource -import androidx.compose.ui.semantics.clearAndSetSemantics -import androidx.compose.ui.semantics.contentDescription import io.element.android.features.messages.impl.R import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineRoomInfo @@ -27,7 +25,6 @@ import io.element.android.features.messages.impl.timeline.components.layout.Cont import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState import io.element.android.features.messages.impl.timeline.protection.aTimelineProtectionState @@ -143,16 +140,7 @@ private fun TimelineItemGroupedEventsRowContent( }, ) { Column(modifier = modifier.animateContentSize()) { - val groupedEventsTitle = pluralStringResource( - id = R.plurals.screen_room_timeline_state_changes, - count = timelineItem.events.size, - timelineItem.events.size - ) GroupHeaderView( - modifier = Modifier.clearAndSetSemantics { - val groupedEventsContent = timelineItem.events.reversed().joinToString(separator = "\n") { (it.content as TimelineItemStateContent).body } - contentDescription = groupedEventsTitle + groupedEventsContent - }, text = pluralStringResource( id = R.plurals.screen_room_timeline_state_changes, count = timelineItem.events.size, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt index 0a8662eab4..22825b532c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -24,6 +25,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons @@ -49,7 +53,15 @@ fun GroupHeaderView( Box( modifier = modifier - .fillMaxWidth(), + .fillMaxWidth() + .toggleable( + value = isExpanded, + onValueChange = { onClick() }, + role = Role.DropdownList, + ) + .clearAndSetSemantics { + contentDescription = text + }, contentAlignment = Alignment.Center ) { Surface( From be62f2cd692fccd27e1c4b50b608ddb9ac349328 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 20 Jun 2025 09:34:38 +0200 Subject: [PATCH 2/2] a11y: now that the grouped events are read one by one, we also need to reverse the order because the timeline is last message at the top when screen reader is enabled. --- .../timeline/components/TimelineItemGroupedEventsRow.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt index c98cf24426..a32f36ced6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt @@ -32,6 +32,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.ui.utils.time.isTalkbackActive import io.element.android.wysiwyg.link.Link @Composable @@ -152,7 +153,13 @@ private fun TimelineItemGroupedEventsRowContent( ) if (isExpanded) { Column { - timelineItem.events.forEach { subGroupEvent -> + timelineItem.events.let { + if (isTalkbackActive()) { + it.reversed() + } else { + it + } + }.forEach { subGroupEvent -> TimelineItemRow( timelineItem = subGroupEvent, timelineRoomInfo = timelineRoomInfo,