From cb34e70586ff3b5b65feab34d6695a77bdf32796 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 bec109a61c02102398d50a8387b1356ab67b949f 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,