From d7f4efed7316b6ae430af0749fbc33e40fa5c514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 10:24:59 +0100 Subject: [PATCH 01/12] Announce a verb on the Create Poll button StreamButton's clickable was set with no onClickLabel, so TalkBack defaulted to the generic "double-tap to activate" hint. Add an optional `onClickLabel` parameter to StreamButton and pass it through to clickable. PollCreationHeader's create button now provides "create poll" as the verb, so TalkBack reads "Create Poll, button. Double-tap to create poll." instead of the generic hint. --- .../api/stream-chat-android-compose.api | 28 +++++++++---------- .../ui/components/button/StreamButton.kt | 2 ++ .../attachments/poll/PollCreationHeader.kt | 1 + .../src/main/res/values-es/strings.xml | 1 + .../src/main/res/values-fr/strings.xml | 1 + .../src/main/res/values-hi/strings.xml | 1 + .../src/main/res/values-in/strings.xml | 1 + .../src/main/res/values-it/strings.xml | 1 + .../src/main/res/values-ja/strings.xml | 1 + .../src/main/res/values-ko/strings.xml | 1 + .../src/main/res/values/strings.xml | 1 + 11 files changed, 25 insertions(+), 14 deletions(-) diff --git a/stream-chat-android-compose/api/stream-chat-android-compose.api b/stream-chat-android-compose/api/stream-chat-android-compose.api index 67ec9635600..c4d12fa5b1b 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -576,13 +576,13 @@ public final class io/getstream/chat/android/compose/ui/attachments/preview/Comp public static final field INSTANCE Lio/getstream/chat/android/compose/ui/attachments/preview/ComposableSingletons$MediaGalleryPreviewScreenKt; public fun ()V public final fun getLambda$-1186868066$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function7; + public final fun getLambda$-1317756983$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1613254346$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-177774698$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-1899518912$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-2102393707$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-210669840$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-244397814$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-49086904$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-357715190$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-52298206$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-563857596$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-822354111$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; @@ -591,10 +591,10 @@ public final class io/getstream/chat/android/compose/ui/attachments/preview/Comp public final fun getLambda$1327866271$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1331114327$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1375691933$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1465472073$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1549246429$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1672511429$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1672603643$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1711218079$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1880503530$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1902056283$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$19148184$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; @@ -763,14 +763,14 @@ public final class io/getstream/chat/android/compose/ui/channel/info/ComposableS public fun ()V public final fun getLambda$-1114359326$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1207226509$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-1284495299$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1330176946$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-1754400971$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-2125016004$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-572168236$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1139087319$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1302953779$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$2046556554$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$217368988$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$756179806$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$ChannelInfoMemberInfoModalSheetKt { @@ -820,10 +820,10 @@ public final class io/getstream/chat/android/compose/ui/channel/info/ComposableS public static final field INSTANCE Lio/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$GroupChannelEditScreenKt; public fun ()V public final fun getLambda$-1290011797$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-1600862874$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1839460112$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1996460951$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-949819074$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-952635417$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1273794324$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1411993017$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1947836857$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; @@ -870,9 +870,9 @@ public final class io/getstream/chat/android/compose/ui/channels/header/Composab public final fun getLambda$-1782552518$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-39363265$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-903354658$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1125356903$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1371852185$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$318691263$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$423422310$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$621281156$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } @@ -1400,7 +1400,7 @@ public final class io/getstream/chat/android/compose/ui/components/messageaction public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/messageactions/ComposableSingletons$MessageActionsHeaderKt; public fun ()V public final fun getLambda$-1164493217$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1304549080$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$746565017$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/components/messageactions/ComposableSingletons$MessageActionsKt { @@ -1614,8 +1614,8 @@ public final class io/getstream/chat/android/compose/ui/components/moderatedmess public final class io/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollAnswersKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollAnswersKt; public fun ()V - public final fun getLambda$-1411166830$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1780669891$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-1805570669$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1980307438$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$-232122758$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-49181804$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; @@ -1877,7 +1877,7 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/pol public static final field INSTANCE Lio/getstream/chat/android/compose/ui/messages/attachments/poll/ComposableSingletons$PollCreationHeaderKt; public fun ()V public final fun getLambda$1291237378$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1775632701$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$2011802524$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$226546083$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } @@ -2028,11 +2028,11 @@ public final class io/getstream/chat/android/compose/ui/messages/composer/intern public static final field INSTANCE Lio/getstream/chat/android/compose/ui/messages/composer/internal/ComposableSingletons$AudioRecordingContentKt; public fun ()V public final fun getLambda$-129303699$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-1855012696$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-2139230466$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-630641788$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$491551885$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-744252283$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$2045550761$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$545156019$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$549534158$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/messages/composer/internal/ComposableSingletons$MessageComposerEditIndicatorKt { @@ -3772,7 +3772,7 @@ public final class io/getstream/chat/android/compose/ui/theme/ComposableSingleto public static final field INSTANCE Lio/getstream/chat/android/compose/ui/theme/ComposableSingletons$ChatComponentFactoryKt; public fun ()V public final fun getLambda$-845861723$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1812629511$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1301617352$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$69070923$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/button/StreamButton.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/button/StreamButton.kt index b54935d70e1..7de6a8e1cb7 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/button/StreamButton.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/button/StreamButton.kt @@ -83,6 +83,7 @@ internal fun StreamButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, + onClickLabel: String? = null, style: StreamButtonStyle = StreamButtonStyleDefaults.primarySolid, size: StreamButtonSize = StreamButtonSize.Medium, content: @Composable () -> Unit, @@ -95,6 +96,7 @@ internal fun StreamButton( .ifNotNull(style.borderColor(enabled)) { border(1.dp, it, CircleShape) } .clickable( onClick = onClick, + onClickLabel = onClickLabel, enabled = enabled, role = Role.Button, interactionSource = remember(::MutableInteractionSource), diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt index 2d243c09013..5ed724f7625 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt @@ -125,6 +125,7 @@ internal fun DefaultPollOptionsHeaderTrailingContent( StreamButton( onClick = onPollCreateClicked, enabled = enabled, + onClickLabel = stringResource(R.string.stream_compose_poll_create_action), style = StreamButtonStyleDefaults.primarySolid, ) { Icon( diff --git a/stream-chat-android-compose/src/main/res/values-es/strings.xml b/stream-chat-android-compose/src/main/res/values-es/strings.xml index 583506bb733..6b57ce69576 100644 --- a/stream-chat-android-compose/src/main/res/values-es/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-es/strings.xml @@ -199,6 +199,7 @@ "Pregunta" "Resultados de la encuesta" "Sugerir opción" + "crear encuesta" "Crear encuesta" "Ver todo" "Ver resultados" diff --git a/stream-chat-android-compose/src/main/res/values-fr/strings.xml b/stream-chat-android-compose/src/main/res/values-fr/strings.xml index 166533c2038..e882cc253eb 100644 --- a/stream-chat-android-compose/src/main/res/values-fr/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-fr/strings.xml @@ -199,6 +199,7 @@ "Question" "Résultats du sondage" "Suggérer une option" + "créer un sondage" "Créer un sondage" "Tout voir" "Voir les résultats" diff --git a/stream-chat-android-compose/src/main/res/values-hi/strings.xml b/stream-chat-android-compose/src/main/res/values-hi/strings.xml index 06feb0d75d1..32d9938546b 100644 --- a/stream-chat-android-compose/src/main/res/values-hi/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-hi/strings.xml @@ -259,6 +259,7 @@ "प्रश्न" "पोल परिणाम" "विकल्प सुझाएँ" + "पोल बनाएँ" "पोल बनाएँ" "सभी देखें" "परिणाम देखें" diff --git a/stream-chat-android-compose/src/main/res/values-in/strings.xml b/stream-chat-android-compose/src/main/res/values-in/strings.xml index e6761d4c916..ad19b540b8b 100644 --- a/stream-chat-android-compose/src/main/res/values-in/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-in/strings.xml @@ -199,6 +199,7 @@ "Pertanyaan" "Hasil Polling" "Sarankan Opsi" + "buat polling" "Buat Polling" "Lihat semua" "Lihat Hasil" diff --git a/stream-chat-android-compose/src/main/res/values-it/strings.xml b/stream-chat-android-compose/src/main/res/values-it/strings.xml index 745853a71ed..ed4476ca85a 100644 --- a/stream-chat-android-compose/src/main/res/values-it/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-it/strings.xml @@ -259,6 +259,7 @@ "Domanda" "Risultati sondaggio" "Suggerisci opzione" + "crea sondaggio" "Crea sondaggio" "Vedi tutti" "Vedi risultati" diff --git a/stream-chat-android-compose/src/main/res/values-ja/strings.xml b/stream-chat-android-compose/src/main/res/values-ja/strings.xml index 684598109c5..518e72052f4 100644 --- a/stream-chat-android-compose/src/main/res/values-ja/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-ja/strings.xml @@ -220,6 +220,7 @@ "質問" "投票結果" "選択肢を提案" + "投票を作成" "投票を作成" "合計%d票" diff --git a/stream-chat-android-compose/src/main/res/values-ko/strings.xml b/stream-chat-android-compose/src/main/res/values-ko/strings.xml index 43a5c27df6f..b8b1c232be7 100644 --- a/stream-chat-android-compose/src/main/res/values-ko/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-ko/strings.xml @@ -220,6 +220,7 @@ "질문" "투표 결과" "옵션 제안" + "투표 만들기" "투표 만들기" "총 %d표" diff --git a/stream-chat-android-compose/src/main/res/values/strings.xml b/stream-chat-android-compose/src/main/res/values/strings.xml index e9d2c1be3a0..f3838844e35 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -306,6 +306,7 @@ Create Poll + create poll Question Ask a question Options From e9faff77bee0182e941d06363a57253492224965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 10:35:33 +0100 Subject: [PATCH 02/12] Make poll switch rows toggleable and merged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each switch row in `PollSwitchList` (top-level options and the inner limit-votes row) wraps a title, description and a `StreamSwitch` — TalkBack focused each as its own node, so a user had to swipe three times to learn what one switch controlled. Wrap each row in `Modifier.toggleable(role = Role.Switch) + semantics(mergeDescendants = true) {}` so the row becomes a single focus stop announced as "{title}, {description}, switch, on/off", with the row's onValueChange firing on tap or double-tap. The inner `StreamSwitch` now takes `onCheckedChange = null` (the pattern its KDoc already documents), which makes the visual switch decorative while the parent row owns the toggle action. Sighted users also gain a larger hit target. --- .../attachments/poll/PollSwitchList.kt | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt index 3c52cc9d025..f45498278a9 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardOptions @@ -43,6 +44,7 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.KeyboardType @@ -167,7 +169,14 @@ private fun PollSwitchHeader( onCheckedChange: (Boolean) -> Unit, ) { Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .toggleable( + value = enabled, + role = Role.Switch, + onValueChange = onCheckedChange, + ) + .semantics(mergeDescendants = true) {}, verticalAlignment = Alignment.CenterVertically, ) { Column( @@ -190,7 +199,7 @@ private fun PollSwitchHeader( StreamSwitch( checked = enabled, - onCheckedChange = onCheckedChange, + onCheckedChange = null, ) } } @@ -209,7 +218,14 @@ private fun LimitVotesPerPerson( .padding(top = StreamTokens.spacingMd), ) { Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .toggleable( + value = enabled, + role = Role.Switch, + onValueChange = onCheckedChange, + ) + .semantics(mergeDescendants = true) {}, verticalAlignment = Alignment.CenterVertically, ) { Column( @@ -230,7 +246,7 @@ private fun LimitVotesPerPerson( StreamSwitch( checked = enabled, - onCheckedChange = onCheckedChange, + onCheckedChange = null, ) } From 07db76c5fed3f0ee0eeb92b2131ad491bfe00331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 10:44:36 +0100 Subject: [PATCH 03/12] Announce poll option errors via a polite live region `PollOptionErrorRow` mounts conditionally when an option has an error (currently only the duplicate-title case). Sighted users see the icon and message appear inline; TalkBack users had no signal until they swiped to the row. Add `Modifier.semantics(mergeDescendants = true) { liveRegion = LiveRegionMode.Polite }` so TalkBack announces the existing error message the moment the row enters the tree. --- .../compose/ui/messages/attachments/poll/PollOptionList.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt index 2da1fd6d774..ca86b045552 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt @@ -44,6 +44,9 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.LiveRegionMode +import androidx.compose.ui.semantics.liveRegion +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import io.getstream.chat.android.compose.R @@ -187,7 +190,8 @@ private fun PollOptionErrorRow(pollOptionError: PollOptionError) { start = StreamTokens.spacingMd, end = StreamTokens.spacingMd, bottom = StreamTokens.spacingSm, - ), + ) + .semantics(mergeDescendants = true) { liveRegion = LiveRegionMode.Polite }, horizontalArrangement = Arrangement.spacedBy(StreamTokens.spacingXs), verticalAlignment = Alignment.CenterVertically, ) { From 4b3b8fb563dc0ae523019fffd1a11492d679955d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 11:39:35 +0100 Subject: [PATCH 04/12] Expose poll option reordering via TalkBack custom actions The reorder UX relies on dragging a handle, which isn't a gesture TalkBack supports natively. Expose two `CustomAccessibilityAction`s ("Move up" / "Move down") on each option's drag handle so TalkBack users can reorder via the local context menu. Each action is wired to a shared `move` lambda used by both the gesture's `onSettle` callback and the new accessibility actions, and the action list is built per row so the top option doesn't offer Move up and the bottom option doesn't offer Move down. --- .../attachments/poll/PollOptionList.kt | 39 +++++++++++++++---- .../src/main/res/values-es/strings.xml | 2 + .../src/main/res/values-fr/strings.xml | 2 + .../src/main/res/values-hi/strings.xml | 2 + .../src/main/res/values-in/strings.xml | 2 + .../src/main/res/values-it/strings.xml | 2 + .../src/main/res/values-ja/strings.xml | 2 + .../src/main/res/values-ko/strings.xml | 2 + .../src/main/res/values/strings.xml | 2 + 9 files changed, 48 insertions(+), 7 deletions(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt index ca86b045552..aff43918135 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt @@ -44,7 +44,9 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.LiveRegionMode +import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.liveRegion import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview @@ -75,6 +77,10 @@ public fun PollOptionList( val context = LocalContext.current val colors = ChatTheme.colors var optionItemList by remember(optionItems) { mutableStateOf(optionItems) } + val move: (Int, Int) -> Unit = { from, to -> + optionItemList = optionItemList.moveItem(from, to) + onQuestionsChanged(optionItemList) + } Column( modifier = modifier @@ -91,12 +97,7 @@ public fun PollOptionList( ReorderableColumn( list = optionItemList, - onSettle = { fromIndex, toIndex -> - optionItemList = optionItemList.toMutableList().apply { - add(toIndex, removeAt(fromIndex)) - } - onQuestionsChanged(optionItemList) - }, + onSettle = move, verticalArrangement = Arrangement.spacedBy(StreamTokens.spacingXs), ) { index, item, _ -> key(item.key) { @@ -110,6 +111,8 @@ public fun PollOptionList( optionItemList = optionItemList.toMutableList().apply { removeAt(index) } onQuestionsChanged(optionItemList) }, + onMoveUp = if (index > 0) { { move(index, index - 1) } } else null, + onMoveDown = if (index < optionItemList.lastIndex) { { move(index, index + 1) } } else null, ) } } @@ -132,8 +135,26 @@ private fun ReorderableScope.PollOptionRow( item: PollOptionItem, onTitleChange: (String) -> Unit, onRemove: () -> Unit, + onMoveUp: (() -> Unit)?, + onMoveDown: (() -> Unit)?, ) { val colors = ChatTheme.colors + val moveUpLabel = stringResource(R.string.stream_compose_poll_option_move_up) + val moveDownLabel = stringResource(R.string.stream_compose_poll_option_move_down) + val moveActions = listOfNotNull( + onMoveUp?.let { move -> + CustomAccessibilityAction(moveUpLabel) { + move() + true + } + }, + onMoveDown?.let { move -> + CustomAccessibilityAction(moveDownLabel) { + move() + true + } + }, + ) Column( modifier = Modifier .fillMaxWidth() @@ -147,7 +168,8 @@ private fun ReorderableScope.PollOptionRow( Box( modifier = Modifier .draggableHandle() - .minimumInteractiveComponentSize(), + .minimumInteractiveComponentSize() + .semantics(mergeDescendants = true) { customActions = moveActions }, ) { Icon( painter = painterResource(id = R.drawable.stream_design_ic_reorder), @@ -240,6 +262,9 @@ private fun AddPollOptionButton(onClick: () -> Unit) { internal val PollInputMinHeight @Composable get() = LocalMinimumInteractiveComponentSize.current internal val PollInputShape = RoundedCornerShape(StreamTokens.radiusLg) +private fun List.moveItem(fromIndex: Int, toIndex: Int): List = + toMutableList().apply { add(toIndex, removeAt(fromIndex)) } + private fun List.updateOnTitleChange( context: Context, affectedIndex: Int, diff --git a/stream-chat-android-compose/src/main/res/values-es/strings.xml b/stream-chat-android-compose/src/main/res/values-es/strings.xml index 6b57ce69576..dba3dcaabb0 100644 --- a/stream-chat-android-compose/src/main/res/values-es/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-es/strings.xml @@ -182,6 +182,8 @@ "Aumentar votos por persona" "Votos por persona" "Eliminar opción de la encuesta" + "Mover abajo" + "Mover arriba" "Reordenar opción de la encuesta" "Se produjo un error al cargar los resultados de la opción de la encuesta. Inténtalo de nuevo más tarde." "Añadir un comentario" diff --git a/stream-chat-android-compose/src/main/res/values-fr/strings.xml b/stream-chat-android-compose/src/main/res/values-fr/strings.xml index e882cc253eb..c38981b9677 100644 --- a/stream-chat-android-compose/src/main/res/values-fr/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-fr/strings.xml @@ -182,6 +182,8 @@ "Augmenter les votes par personne" "Votes par personne" "Supprimer l\'option du sondage" + "Déplacer vers le bas" + "Déplacer vers le haut" "Réorganiser l\'option du sondage" "Une erreur est survenue lors du chargement des résultats de l\'option du sondage. Veuillez réessayer plus tard." "Ajouter un commentaire" diff --git a/stream-chat-android-compose/src/main/res/values-hi/strings.xml b/stream-chat-android-compose/src/main/res/values-hi/strings.xml index 32d9938546b..f3bdbe8496e 100644 --- a/stream-chat-android-compose/src/main/res/values-hi/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-hi/strings.xml @@ -240,6 +240,8 @@ "प्रति व्यक्ति वोट बढ़ाएँ" "प्रति व्यक्ति वोट" "पोल विकल्प हटाएँ" + "नीचे ले जाएँ" + "ऊपर ले जाएँ" "पोल विकल्प क्रम बदलें" "टिप्पणी जोड़ें" "दूसरों को टिप्पणी जोड़ने दें" diff --git a/stream-chat-android-compose/src/main/res/values-in/strings.xml b/stream-chat-android-compose/src/main/res/values-in/strings.xml index ad19b540b8b..93479cdbfcd 100644 --- a/stream-chat-android-compose/src/main/res/values-in/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-in/strings.xml @@ -182,6 +182,8 @@ "Tambah suara per orang" "Suara per orang" "Hapus opsi polling" + "Pindahkan ke bawah" + "Pindahkan ke atas" "Urutkan ulang opsi polling" "Terjadi kesalahan saat memuat hasil opsi polling. Silakan coba lagi nanti." "Tambahkan komentar" diff --git a/stream-chat-android-compose/src/main/res/values-it/strings.xml b/stream-chat-android-compose/src/main/res/values-it/strings.xml index ed4476ca85a..0576f397fa4 100644 --- a/stream-chat-android-compose/src/main/res/values-it/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-it/strings.xml @@ -240,6 +240,8 @@ "Aumenta voti per persona" "Voti per persona" "Rimuovi opzione sondaggio" + "Sposta giù" + "Sposta su" "Riordina opzione sondaggio" "Aggiungi un commento" "Permetti ad altri di aggiungere commenti" diff --git a/stream-chat-android-compose/src/main/res/values-ja/strings.xml b/stream-chat-android-compose/src/main/res/values-ja/strings.xml index 518e72052f4..9619e66506c 100644 --- a/stream-chat-android-compose/src/main/res/values-ja/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-ja/strings.xml @@ -203,6 +203,8 @@ "1人あたりの投票数を増やす" "1人あたりの投票数" "投票の選択肢を削除" + "下に移動" + "上に移動" "投票の選択肢を並べ替え" "投票の選択肢の結果の読み込み中にエラーが発生しました。後でもう一度お試しください。" "コメントを追加" diff --git a/stream-chat-android-compose/src/main/res/values-ko/strings.xml b/stream-chat-android-compose/src/main/res/values-ko/strings.xml index b8b1c232be7..6757007c6ce 100644 --- a/stream-chat-android-compose/src/main/res/values-ko/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-ko/strings.xml @@ -203,6 +203,8 @@ "1인당 투표 수 늘리기" "1인당 투표 수" "투표 옵션 삭제" + "아래로 이동" + "위로 이동" "투표 옵션 재정렬" "투표 옵션 결과를 불러오는 중 오류가 발생했습니다. 나중에 다시 시도해 주세요." "댓글 추가" diff --git a/stream-chat-android-compose/src/main/res/values/strings.xml b/stream-chat-android-compose/src/main/res/values/strings.xml index f3838844e35..12957290e89 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -361,6 +361,8 @@ Poll created: %s Poll closed: %s Reorder poll option + Move up + Move down Remove poll option From 563ecb5f1db18d6e67639821ce3e68094be83a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 11:57:43 +0100 Subject: [PATCH 05/12] Simplify poll option move callbacks --- .../attachments/poll/PollOptionList.kt | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt index aff43918135..80467b91365 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt @@ -111,8 +111,8 @@ public fun PollOptionList( optionItemList = optionItemList.toMutableList().apply { removeAt(index) } onQuestionsChanged(optionItemList) }, - onMoveUp = if (index > 0) { { move(index, index - 1) } } else null, - onMoveDown = if (index < optionItemList.lastIndex) { { move(index, index + 1) } } else null, + onMoveUp = index.takeIf { it > 0 }?.let { i -> { move(i, i - 1) } }, + onMoveDown = index.takeIf { it < optionItemList.lastIndex }?.let { i -> { move(i, i + 1) } }, ) } } @@ -142,18 +142,8 @@ private fun ReorderableScope.PollOptionRow( val moveUpLabel = stringResource(R.string.stream_compose_poll_option_move_up) val moveDownLabel = stringResource(R.string.stream_compose_poll_option_move_down) val moveActions = listOfNotNull( - onMoveUp?.let { move -> - CustomAccessibilityAction(moveUpLabel) { - move() - true - } - }, - onMoveDown?.let { move -> - CustomAccessibilityAction(moveDownLabel) { - move() - true - } - }, + onMoveUp.toMoveAction(moveUpLabel), + onMoveDown.toMoveAction(moveDownLabel), ) Column( modifier = Modifier @@ -265,6 +255,14 @@ internal val PollInputShape = RoundedCornerShape(StreamTokens.radiusLg) private fun List.moveItem(fromIndex: Int, toIndex: Int): List = toMutableList().apply { add(toIndex, removeAt(fromIndex)) } +private fun (() -> Unit)?.toMoveAction(label: String): CustomAccessibilityAction? = + this?.let { invoke -> + CustomAccessibilityAction(label) { + invoke() + true + } + } + private fun List.updateOnTitleChange( context: Context, affectedIndex: Int, From b6261ccf818be452b7dfdc101baa8fc6248066cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 14:15:05 +0100 Subject: [PATCH 06/12] Pin poll switch row min height to interactive size --- .../compose/ui/messages/attachments/poll/PollSwitchList.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt index f45498278a9..48de206dc93 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt @@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -34,6 +35,7 @@ import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon +import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -171,6 +173,7 @@ private fun PollSwitchHeader( Row( modifier = Modifier .fillMaxWidth() + .defaultMinSize(minHeight = LocalMinimumInteractiveComponentSize.current) .toggleable( value = enabled, role = Role.Switch, @@ -220,6 +223,7 @@ private fun LimitVotesPerPerson( Row( modifier = Modifier .fillMaxWidth() + .defaultMinSize(minHeight = LocalMinimumInteractiveComponentSize.current) .toggleable( value = enabled, role = Role.Switch, From 54539b2a6c3692b3b9ac1f860d4f734e5d9b7af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 14:15:05 +0100 Subject: [PATCH 07/12] Include option name in reorder and remove a11y labels --- .../attachments/poll/PollOptionList.kt | 28 +++++++++++-------- .../src/main/res/values-es/strings.xml | 4 +-- .../src/main/res/values-fr/strings.xml | 4 +-- .../src/main/res/values-hi/strings.xml | 4 +-- .../src/main/res/values-in/strings.xml | 4 +-- .../src/main/res/values-it/strings.xml | 4 +-- .../src/main/res/values-ja/strings.xml | 4 +-- .../src/main/res/values-ko/strings.xml | 4 +-- .../src/main/res/values/strings.xml | 4 +-- 9 files changed, 33 insertions(+), 27 deletions(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt index 80467b91365..066d5300094 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt @@ -103,6 +103,7 @@ public fun PollOptionList( key(item.key) { PollOptionRow( item = item, + index = index, onTitleChange = { newTitle -> optionItemList = optionItemList.updateOnTitleChange(context, index, newTitle) onQuestionsChanged.invoke(optionItemList) @@ -111,8 +112,10 @@ public fun PollOptionList( optionItemList = optionItemList.toMutableList().apply { removeAt(index) } onQuestionsChanged(optionItemList) }, - onMoveUp = index.takeIf { it > 0 }?.let { i -> { move(i, i - 1) } }, - onMoveDown = index.takeIf { it < optionItemList.lastIndex }?.let { i -> { move(i, i + 1) } }, + moves = PollOptionMoves( + up = index.takeIf { it > 0 }?.let { i -> { move(i, i - 1) } }, + down = index.takeIf { it < optionItemList.lastIndex }?.let { i -> { move(i, i + 1) } }, + ), ) } } @@ -133,17 +136,16 @@ public fun PollOptionList( @Composable private fun ReorderableScope.PollOptionRow( item: PollOptionItem, + index: Int, onTitleChange: (String) -> Unit, onRemove: () -> Unit, - onMoveUp: (() -> Unit)?, - onMoveDown: (() -> Unit)?, + moves: PollOptionMoves, ) { val colors = ChatTheme.colors - val moveUpLabel = stringResource(R.string.stream_compose_poll_option_move_up) - val moveDownLabel = stringResource(R.string.stream_compose_poll_option_move_down) + val displayName = item.title.ifBlank { (index + 1).toString() } val moveActions = listOfNotNull( - onMoveUp.toMoveAction(moveUpLabel), - onMoveDown.toMoveAction(moveDownLabel), + moves.up.toMoveAction(stringResource(R.string.stream_compose_poll_option_move_up)), + moves.down.toMoveAction(stringResource(R.string.stream_compose_poll_option_move_down)), ) Column( modifier = Modifier @@ -163,9 +165,8 @@ private fun ReorderableScope.PollOptionRow( ) { Icon( painter = painterResource(id = R.drawable.stream_design_ic_reorder), - contentDescription = stringResource(R.string.stream_compose_poll_option_reorder), + contentDescription = stringResource(R.string.stream_compose_poll_option_reorder, displayName), tint = colors.inputTextIcon, - modifier = Modifier.size(20.dp), ) } @@ -179,7 +180,7 @@ private fun ReorderableScope.PollOptionRow( IconButton(onClick = onRemove) { Icon( painter = painterResource(R.drawable.stream_design_ic_minus_circle), - contentDescription = stringResource(R.string.stream_compose_poll_option_remove), + contentDescription = stringResource(R.string.stream_compose_poll_option_remove, displayName), tint = colors.inputTextIcon, modifier = Modifier.size(20.dp), ) @@ -263,6 +264,11 @@ private fun (() -> Unit)?.toMoveAction(label: String): CustomAccessibilityAction } } +private data class PollOptionMoves( + val up: (() -> Unit)?, + val down: (() -> Unit)?, +) + private fun List.updateOnTitleChange( context: Context, affectedIndex: Int, diff --git a/stream-chat-android-compose/src/main/res/values-es/strings.xml b/stream-chat-android-compose/src/main/res/values-es/strings.xml index dba3dcaabb0..71a0d1fe495 100644 --- a/stream-chat-android-compose/src/main/res/values-es/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-es/strings.xml @@ -181,10 +181,10 @@ "Elegir entre 2\u201310 opciones" "Aumentar votos por persona" "Votos por persona" - "Eliminar opción de la encuesta" + "Eliminar opción %s" "Mover abajo" "Mover arriba" - "Reordenar opción de la encuesta" + "Reordenar opción %s" "Se produjo un error al cargar los resultados de la opción de la encuesta. Inténtalo de nuevo más tarde." "Añadir un comentario" "Permitir que otros añadan comentarios" diff --git a/stream-chat-android-compose/src/main/res/values-fr/strings.xml b/stream-chat-android-compose/src/main/res/values-fr/strings.xml index c38981b9677..8ba0888d524 100644 --- a/stream-chat-android-compose/src/main/res/values-fr/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-fr/strings.xml @@ -181,10 +181,10 @@ "Choisir entre 2\u201310 options" "Augmenter les votes par personne" "Votes par personne" - "Supprimer l\'option du sondage" + "Supprimer l\'option %s" "Déplacer vers le bas" "Déplacer vers le haut" - "Réorganiser l\'option du sondage" + "Réorganiser l\'option %s" "Une erreur est survenue lors du chargement des résultats de l\'option du sondage. Veuillez réessayer plus tard." "Ajouter un commentaire" "Permettre aux autres d\'ajouter des commentaires" diff --git a/stream-chat-android-compose/src/main/res/values-hi/strings.xml b/stream-chat-android-compose/src/main/res/values-hi/strings.xml index f3bdbe8496e..f097a0f23bf 100644 --- a/stream-chat-android-compose/src/main/res/values-hi/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-hi/strings.xml @@ -239,10 +239,10 @@ "2\u201310 विकल्पों में से चुनें" "प्रति व्यक्ति वोट बढ़ाएँ" "प्रति व्यक्ति वोट" - "पोल विकल्प हटाएँ" + "विकल्प %s हटाएँ" "नीचे ले जाएँ" "ऊपर ले जाएँ" - "पोल विकल्प क्रम बदलें" + "विकल्प %s का क्रम बदलें" "टिप्पणी जोड़ें" "दूसरों को टिप्पणी जोड़ने दें" "गुमनाम पोल" diff --git a/stream-chat-android-compose/src/main/res/values-in/strings.xml b/stream-chat-android-compose/src/main/res/values-in/strings.xml index 93479cdbfcd..a04b54fcdc9 100644 --- a/stream-chat-android-compose/src/main/res/values-in/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-in/strings.xml @@ -181,10 +181,10 @@ "Pilih antara 2\u201310 opsi" "Tambah suara per orang" "Suara per orang" - "Hapus opsi polling" + "Hapus opsi %s" "Pindahkan ke bawah" "Pindahkan ke atas" - "Urutkan ulang opsi polling" + "Urutkan ulang opsi %s" "Terjadi kesalahan saat memuat hasil opsi polling. Silakan coba lagi nanti." "Tambahkan komentar" "Izinkan orang lain menambahkan komentar" diff --git a/stream-chat-android-compose/src/main/res/values-it/strings.xml b/stream-chat-android-compose/src/main/res/values-it/strings.xml index 0576f397fa4..f59937affc1 100644 --- a/stream-chat-android-compose/src/main/res/values-it/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-it/strings.xml @@ -239,10 +239,10 @@ "Scegli tra 2\u201310 opzioni" "Aumenta voti per persona" "Voti per persona" - "Rimuovi opzione sondaggio" + "Rimuovi opzione %s" "Sposta giù" "Sposta su" - "Riordina opzione sondaggio" + "Riordina opzione %s" "Aggiungi un commento" "Permetti ad altri di aggiungere commenti" "Sondaggio anonimo" diff --git a/stream-chat-android-compose/src/main/res/values-ja/strings.xml b/stream-chat-android-compose/src/main/res/values-ja/strings.xml index 9619e66506c..2c346fde6ae 100644 --- a/stream-chat-android-compose/src/main/res/values-ja/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-ja/strings.xml @@ -202,10 +202,10 @@ "2〜10の選択肢から選択" "1人あたりの投票数を増やす" "1人あたりの投票数" - "投票の選択肢を削除" + "選択肢%sを削除" "下に移動" "上に移動" - "投票の選択肢を並べ替え" + "選択肢%sを並べ替え" "投票の選択肢の結果の読み込み中にエラーが発生しました。後でもう一度お試しください。" "コメントを追加" "他のユーザーがコメントを追加できるようにする" diff --git a/stream-chat-android-compose/src/main/res/values-ko/strings.xml b/stream-chat-android-compose/src/main/res/values-ko/strings.xml index 6757007c6ce..7a377a5f0c4 100644 --- a/stream-chat-android-compose/src/main/res/values-ko/strings.xml +++ b/stream-chat-android-compose/src/main/res/values-ko/strings.xml @@ -202,10 +202,10 @@ "2\u201310개의 옵션 중 선택" "1인당 투표 수 늘리기" "1인당 투표 수" - "투표 옵션 삭제" + "옵션 %s 삭제" "아래로 이동" "위로 이동" - "투표 옵션 재정렬" + "옵션 %s 재정렬" "투표 옵션 결과를 불러오는 중 오류가 발생했습니다. 나중에 다시 시도해 주세요." "댓글 추가" "다른 사용자가 댓글을 추가할 수 있도록 허용" diff --git a/stream-chat-android-compose/src/main/res/values/strings.xml b/stream-chat-android-compose/src/main/res/values/strings.xml index 12957290e89..de2dc28e0db 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -360,10 +360,10 @@ Poll created: %s Poll closed: %s - Reorder poll option + Reorder option %s Move up Move down - Remove poll option + Remove option %s No pinned messages From f7b70d1b192d1232d78283cac4a6b8984666c247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Tue, 19 May 2026 16:05:40 +0100 Subject: [PATCH 08/12] Anchor poll drag handle a11y on its full Box bounds --- .../ui/messages/attachments/poll/PollOptionList.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt index 066d5300094..af94544276d 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionList.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.LiveRegionMode +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.liveRegion import androidx.compose.ui.semantics.semantics @@ -157,15 +158,19 @@ private fun ReorderableScope.PollOptionRow( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, ) { + val reorderLabel = stringResource(R.string.stream_compose_poll_option_reorder, displayName) Box( modifier = Modifier + .semantics(mergeDescendants = true) { + contentDescription = reorderLabel + customActions = moveActions + } .draggableHandle() - .minimumInteractiveComponentSize() - .semantics(mergeDescendants = true) { customActions = moveActions }, + .minimumInteractiveComponentSize(), ) { Icon( painter = painterResource(id = R.drawable.stream_design_ic_reorder), - contentDescription = stringResource(R.string.stream_compose_poll_option_reorder, displayName), + contentDescription = null, tint = colors.inputTextIcon, ) } From a79973c2c27ffa1dae11a8ffc2cacce47c5d1d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Wed, 20 May 2026 13:29:08 +0100 Subject: [PATCH 09/12] Let integrators supply the poll create click label --- .../api/stream-chat-android-compose.api | 6 +++--- .../messages/attachments/poll/CreatePollScreen.kt | 3 +++ .../attachments/poll/PollCreationHeader.kt | 15 ++++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/stream-chat-android-compose/api/stream-chat-android-compose.api b/stream-chat-android-compose/api/stream-chat-android-compose.api index c4d12fa5b1b..bd552751c19 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -1877,7 +1877,7 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/pol public static final field INSTANCE Lio/getstream/chat/android/compose/ui/messages/attachments/poll/ComposableSingletons$PollCreationHeaderKt; public fun ()V public final fun getLambda$1291237378$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$2011802524$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1718700457$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$226546083$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } @@ -1902,7 +1902,7 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/pol } public final class io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreenKt { - public static final fun CreatePollScreen (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V + public static final fun CreatePollScreen (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Landroidx/compose/runtime/Composer;II)V } public final class io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationDiscardDialogKt { @@ -1910,7 +1910,7 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/pol } public final class io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeaderKt { - public static final fun PollCreationHeader (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V + public static final fun PollCreationHeader (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;ZLkotlin/jvm/functions/Function0;Ljava/lang/String;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V } public final class io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionDuplicated : io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionError { diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt index ce9c2c26b7e..d020baa7b17 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt @@ -52,12 +52,14 @@ import io.getstream.chat.android.models.CreatePollParams * @param onBack Called when the user navigates back from the poll creation screen * (via back press or discard). Resets the ViewModel state. * @param onCreatePoll Called when the user submits a new poll configuration. + * @param onCreatePollLabel Semantic / accessibility label for the poll creation button that triggers [onCreatePoll]. */ @Suppress("LongMethod") @Composable public fun CreatePollScreen( onBack: () -> Unit, onCreatePoll: (CreatePollParams) -> Unit, + onCreatePollLabel: String? = null, ) { val viewModel: CreatePollViewModel = viewModel( factory = CreatePollViewModelFactory(ChatTheme.config.polls), @@ -88,6 +90,7 @@ public fun CreatePollScreen( PollCreationHeader( modifier = Modifier.fillMaxWidth(), enabledCreation = state.isCreationEnabled, + onPollCreateClickedLabel = onCreatePollLabel, onPollCreateClicked = { onCreatePoll( createPollParamsFrom( diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt index 5ed724f7625..c41339fb172 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt @@ -50,6 +50,7 @@ import io.getstream.chat.android.compose.ui.theme.ChatTheme * @param onBackPressed A lambda that will be executed if users click the back button on the default [leadingContent]. * @param enabledCreation Represents if user can click the creation button or not. * @param onPollCreateClicked A lambda that will be executed if users click the poll creation button. + * @param onPollCreateClickedLabel Semantic / accessibility label for [onPollCreateClicked]. * @param leadingContent Customizable composable function that represents the leading content of a poll creation item, usually * holding a back action button. * @param centerContent Customizable composable function that represents the center content of a poll creation item, usually @@ -63,6 +64,7 @@ public fun PollCreationHeader( onBackPressed: () -> Unit = {}, enabledCreation: Boolean, onPollCreateClicked: () -> Unit, + onPollCreateClickedLabel: String? = null, leadingContent: @Composable (RowScope.() -> Unit)? = null, centerContent: @Composable (RowScope.() -> Unit)? = null, trailingContent: @Composable (RowScope.() -> Unit)? = null, @@ -86,7 +88,8 @@ public fun PollCreationHeader( trailingContent?.invoke(this) ?: DefaultPollOptionsHeaderTrailingContent( enabled = enabledCreation, - onPollCreateClicked = onPollCreateClicked, + onPollCreateClick = onPollCreateClicked, + onPollCreateClickLabel = onPollCreateClickedLabel, ) } } @@ -118,14 +121,16 @@ internal fun DefaultPollOptionsHeaderCenterContent(modifier: Modifier, title: St } @Composable -internal fun DefaultPollOptionsHeaderTrailingContent( +private fun DefaultPollOptionsHeaderTrailingContent( enabled: Boolean, - onPollCreateClicked: () -> Unit, + onPollCreateClick: () -> Unit, + onPollCreateClickLabel: String? = null, ) { + val onClickLabel = onPollCreateClickLabel ?: stringResource(R.string.stream_compose_poll_create_action) StreamButton( - onClick = onPollCreateClicked, + onClick = onPollCreateClick, enabled = enabled, - onClickLabel = stringResource(R.string.stream_compose_poll_create_action), + onClickLabel = onClickLabel, style = StreamButtonStyleDefaults.primarySolid, ) { Icon( From 59456614c9ae467de496471435158564be4c9685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Thu, 21 May 2026 09:29:58 +0100 Subject: [PATCH 10/12] Disambiguate Create Poll button label from screen heading --- stream-chat-android-compose/api/stream-chat-android-compose.api | 1 - .../compose/ui/messages/attachments/poll/PollCreationHeader.kt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/stream-chat-android-compose/api/stream-chat-android-compose.api b/stream-chat-android-compose/api/stream-chat-android-compose.api index e2e4f55f918..ce574928f6f 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -1877,7 +1877,6 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/pol public static final field INSTANCE Lio/getstream/chat/android/compose/ui/messages/attachments/poll/ComposableSingletons$PollCreationHeaderKt; public fun ()V public final fun getLambda$1291237378$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1718700457$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$226546083$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt index c41339fb172..ca5c1aaa540 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollCreationHeader.kt @@ -135,7 +135,7 @@ private fun DefaultPollOptionsHeaderTrailingContent( ) { Icon( painter = painterResource(R.drawable.stream_design_ic_checkmark), - contentDescription = stringResource(R.string.stream_compose_poll_title), + contentDescription = onClickLabel, ) } } From 1901e5c5031227d1270e23903aeb837dc9d182a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Thu, 21 May 2026 09:30:02 +0100 Subject: [PATCH 11/12] Hide poll input placeholder text from accessibility --- .../chat/android/compose/ui/components/poll/PollOptionInput.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionInput.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionInput.kt index f67046f43bc..b574c0dcff8 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionInput.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionInput.kt @@ -39,6 +39,7 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.hideFromAccessibility import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextStyle @@ -127,6 +128,7 @@ public fun PollOptionInput( if (value.isBlank()) { Text( text = description, + modifier = Modifier.semantics { hideFromAccessibility() }, style = typography.bodyDefault, color = colors.inputTextPlaceholder, ) From 2cc5ae4b75cb18945c46aaa44c9b08ca4634b714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Mion?= Date: Thu, 21 May 2026 09:30:06 +0100 Subject: [PATCH 12/12] Hide redundant switch state on poll switch rows --- .../compose/ui/messages/attachments/poll/PollSwitchList.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt index 48de206dc93..a4de2809193 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt @@ -48,6 +48,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.hideFromAccessibility import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign @@ -201,6 +202,7 @@ private fun PollSwitchHeader( } StreamSwitch( + modifier = Modifier.semantics { hideFromAccessibility() }, checked = enabled, onCheckedChange = null, ) @@ -249,6 +251,7 @@ private fun LimitVotesPerPerson( } StreamSwitch( + modifier = Modifier.semantics { hideFromAccessibility() }, checked = enabled, onCheckedChange = null, )