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 a09d5c3e41f..f849ce0de22 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -1084,6 +1084,12 @@ public final class io/getstream/chat/android/compose/ui/components/ComposableSin public final fun getLambda$2132906032$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; } +public final class io/getstream/chat/android/compose/ui/components/ComposableSingletons$StreamModalBottomSheetKt { + public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/ComposableSingletons$StreamModalBottomSheetKt; + public fun ()V + public final fun getLambda$932570128$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; +} + public final class io/getstream/chat/android/compose/ui/components/ComposerCancelIconKt { public static final fun ComposerCancelIcon (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;II)V } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt index f63e8e1c3db..6ee8e68e330 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt @@ -19,6 +19,7 @@ package io.getstream.chat.android.compose.ui.components import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetState @@ -30,6 +31,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.semantics.hideFromAccessibility +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.Dp import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.StreamTokens @@ -38,7 +41,8 @@ import io.getstream.chat.android.compose.ui.theme.StreamTokens * Card-style Stream modal bottom sheet. * * Bakes the design-system tokens for a card sitting above the app: - * 32dp top corners, elevated surface color, heavier scrim, and the M3 default drag handle. + * 32dp top corners, elevated surface color, heavier scrim, and the M3 default drag handle + * (hidden from the accessibility tree). * Use for menus and option pickers that appear on top of the underlying screen * (e.g. reactions, channel info member modal, attachment command picker). * @@ -70,6 +74,11 @@ internal fun StreamCardBottomSheet( shape = StreamCardSheetShape, containerColor = ChatTheme.colors.backgroundCoreElevation1, scrimColor = ChatTheme.colors.backgroundCoreScrim, + dragHandle = { + BottomSheetDefaults.DragHandle( + modifier = Modifier.semantics { hideFromAccessibility() }, + ) + }, content = content, ) } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/MessageActions.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/MessageActions.kt index 408d8424568..aa47da67cb2 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/MessageActions.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/MessageActions.kt @@ -49,6 +49,8 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.paneTitle import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.tooling.preview.Preview @@ -59,6 +61,7 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogWindowProvider import androidx.compose.ui.zIndex +import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.state.messageoptions.MessageOptionItemState import io.getstream.chat.android.compose.state.messages.MessageAlignment import io.getstream.chat.android.compose.ui.components.messageoptions.defaultMessageOptionsState @@ -175,9 +178,13 @@ public fun MessageActions( if (isInspection) animation.snapIn() else animation.animateIn() } + val menuPaneTitle = stringResource(R.string.stream_compose_message_actions_menu_title) Column( modifier = modifier - .semantics { testTagsAsResourceId = true } + .semantics { + testTagsAsResourceId = true + paneTitle = menuPaneTitle + } .fillMaxSize() .clickable(onClick = animatedDismiss, indication = null, interactionSource = null) .systemBarsPadding() diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt index e8c842e19e8..bca38531533 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt @@ -19,7 +19,11 @@ package io.getstream.chat.android.compose.ui.components.reactionpicker import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.stringResource +import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.reactionoptions.ExtendedReactionsOptions import io.getstream.chat.android.compose.ui.theme.ChatTheme @@ -45,6 +49,12 @@ public fun ReactionsPicker( modifier: Modifier = Modifier, onDismiss: () -> Unit = {}, ) { + val view = LocalView.current + val emojiPickerTitle = stringResource(R.string.stream_compose_emoji_picker_title) + // ModalBottomSheet swallows the standard `paneTitle` window-state-changed event, so + // announce the title programmatically. See PollDialogHeader for the same workaround. + LaunchedEffect(emojiPickerTitle) { view.announceForAccessibility(emojiPickerTitle) } + StreamCardBottomSheet( onDismissRequest = onDismiss, modifier = modifier, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactions/ReactionToggle.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactions/ReactionToggle.kt index 2541009b7a6..d3cbb9ba4ce 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactions/ReactionToggle.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactions/ReactionToggle.kt @@ -29,10 +29,16 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.onClick +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.ReactionIconParams import io.getstream.chat.android.compose.ui.util.ReactionResolver @@ -60,6 +66,13 @@ internal fun ReactionToggle( ) { emoji?.let { val containerSize = size.toContainerSize() + val selectedStateDescription = stringResource(R.string.stream_compose_reactions_state_selected) + val notSelectedStateDescription = stringResource(R.string.stream_compose_reactions_state_not_selected) + val selectActionLabel = stringResource(R.string.stream_compose_reactions_action_select) + val unselectActionLabel = stringResource(R.string.stream_compose_reactions_action_unselect) + val selectedAnnouncement = stringResource(R.string.stream_compose_reactions_selected, emoji) + val unselectedAnnouncement = stringResource(R.string.stream_compose_reactions_unselected, emoji) + val view = LocalView.current ChatTheme.componentFactory.ReactionIcon( params = ReactionIconParams( type = type, @@ -70,11 +83,31 @@ internal fun ReactionToggle( background(ChatTheme.colors.backgroundUtilitySelected, CircleShape) } .ifNotNull(onCheckedChange) { onChange -> - clip(CircleShape).toggleable( - value = checked, - role = Role.Checkbox, - onValueChange = onChange, - ) + val toggleAndAnnounce: (Boolean) -> Unit = { newChecked -> + view.announceForAccessibility( + if (newChecked) selectedAnnouncement else unselectedAnnouncement, + ) + onChange(newChecked) + } + clip(CircleShape) + .toggleable( + value = checked, + role = Role.Button, + onValueChange = toggleAndAnnounce, + ) + .semantics { + stateDescription = if (checked) { + selectedStateDescription + } else { + notSelectedStateDescription + } + onClick( + label = if (checked) unselectActionLabel else selectActionLabel, + ) { + toggleAndAnnounce(!checked) + true + } + } } .defaultMinSize(minWidth = containerSize, minHeight = containerSize) .wrapContentSize(), 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 0e328588b14..0966f3a4956 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 @@ -85,6 +85,7 @@ "Descartar" "Actualizar tu comentario" "Editar mensaje" + "Selector de emojis" "Archivo" "Marcar mensaje" "¿Quieres enviar una copia de este mensaje a un moderador para una investigación más detallada?" @@ -135,6 +136,7 @@ "Abrir archivos adjuntos" "Mensaje eliminado" "Mensaje eliminado" + "Acciones del mensaje" "Abrir hilo" "Mostrar opciones del mensaje" "Abrir archivo adjunto" @@ -225,8 +227,14 @@ "Responder a %s" "Responder a ti" "Tú" + "Seleccionar" + "Deseleccionar" "Añadir reacción" "Toca para eliminar" + "Reacción %1$s seleccionada" + "Reacción %1$s deseleccionada" + "No seleccionado" + "Seleccionado" "Tú" "Archivos recientes" "+%1$d" 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 7f2816a1484..aab62aed9cc 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 @@ -85,6 +85,7 @@ "Ignorer" "Mettre à jour votre commentaire" "Modifier le message" + "Sélecteur d’emojis" "Fichier" "Signaler le message" "Voulez-vous envoyer une copie de ce message à un modérateur pour une enquête plus approfondie ?" @@ -135,6 +136,7 @@ "Ouvrir les pièces jointes" "Message supprimé" "Message supprimé" + "Actions du message" "Ouvrir le fil" "Afficher les options du message" "Ouvrir la pièce jointe" @@ -225,8 +227,14 @@ "Répondre à %s" "Répondre à vous-même" "Vous" + "Sélectionner" + "Désélectionner" "Ajouter une réaction" "Appuyez pour supprimer" + "Réaction %1$s sélectionnée" + "Réaction %1$s désélectionnée" + "Non sélectionné" + "Sélectionné" "Vous" "Fichiers récents" "+%1$d" 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 7895f79f6ba..152f472badf 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 @@ -145,6 +145,7 @@ "खारिज करें" "अपनी टिप्पणी अपडेट करें" "मैसेज एडिट करें" + "इमोजी चयनकर्ता" "फ़ाइल" "मैसेज चिह्नित करें" "क्या आप आगे की जांच के लिए इस संदेश की एक कॉपी मॉडरेटर को भेजना चाहते हैं?" @@ -195,6 +196,7 @@ "अटैचमेंट खोलें" "मैसेज मिटाया गया" "मैसेज हटा दिया गया" + "संदेश की क्रियाएँ" "थ्रेड खोलें" "संदेश के विकल्प दिखाएँ" "अटैचमेंट खोलें" @@ -285,8 +287,14 @@ "%s को जवाब" "स्वयं को जवाब" "आप" + "चुनें" + "अचयन करें" "प्रतिक्रिया जोड़ें" "हटाने के लिए टैप करें" + "%1$s प्रतिक्रिया चुनी गई" + "%1$s प्रतिक्रिया का चयन हटाया गया" + "चयनित नहीं" + "चयनित" "आप" "हाल ही की फाइलें" "+%1$d" 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 4a95f6f35a5..b8641a0dd00 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 @@ -85,6 +85,7 @@ "Tutup" "Perbarui Komentar Anda" "Edit Pesan" + "Pemilih emoji" "File" "Tandai Pesan" "Apakah Anda ingin mengirim salinan pesan ini ke moderator untuk investigasi lebih lanjut?" @@ -135,6 +136,7 @@ "Buka lampiran" "Pesan dihapus" "Pesan dihapus" + "Tindakan pesan" "Buka utas" "Tampilkan opsi pesan" "Buka lampiran" @@ -225,8 +227,14 @@ "Balas ke %s" "Balas ke diri sendiri" "Anda" + "Pilih" + "Batalkan pilihan" "Tambahkan reaksi" "Ketuk untuk menghapus" + "Reaksi %1$s dipilih" + "Reaksi %1$s tidak dipilih" + "Tidak dipilih" + "Dipilih" "Anda" "File Terbaru" "+%1$d" 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 f1c60dd3d8d..aa4c860bc22 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 @@ -145,6 +145,7 @@ "Chiudi" "Aggiorna il tuo commento" "Modifica messaggio" + "Selettore emoji" "File" "Segnala messaggio" "Vuoi mandare una copia di questo messaggio ad un moderatore?" @@ -195,6 +196,7 @@ "Apri allegati" "Messaggio cancellato" "Messaggio cancellato" + "Azioni del messaggio" "Apri thread" "Mostra opzioni messaggio" "Apri allegato" @@ -285,8 +287,14 @@ "Rispondi a %s" "Rispondi a te stesso" "Tu" + "Seleziona" + "Deseleziona" "Aggiungi reazione" "Tocca per rimuovere" + "Reazione %1$s selezionata" + "Reazione %1$s deselezionata" + "Non selezionato" + "Selezionato" "Tu" "File recenti" "+%1$d" 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 553a50bcb49..f37bcd36aef 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 @@ -92,6 +92,7 @@ "閉じる" "コメントを更新" "メッセージを編集" + "絵文字ピッカー" "ファイル" "%dファイル" @@ -147,6 +148,7 @@ "添付ファイルを開く" "メッセージは削除されました" "メッセージは削除されました" + "メッセージのアクション" "スレッドを開く" "メッセージのオプションを表示" "添付ファイルを開く" @@ -261,8 +263,14 @@ "%d本の動画" "あなた" + "選択" + "選択解除" "リアクションを追加" "タップして削除" + "%1$s リアクションを選択しました" + "%1$s リアクションの選択を解除しました" + "選択されていません" + "選択されています" "あなた" "最近のファイル" "+%1$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 8506f63ca69..b8fede41890 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 @@ -92,6 +92,7 @@ "닫기" "댓글 수정" "메시지 수정" + "이모지 선택기" "파일" "%d개의 파일" @@ -147,6 +148,7 @@ "첨부파일 열기" "메시지가 삭제되었습니다" "메시지가 삭제되었습니다" + "메시지 작업" "스레드 열기" "메시지 옵션 표시" "첨부파일 열기" @@ -261,8 +263,14 @@ "%d개의 동영상" "나" + "선택" + "선택 해제" "리액션 추가" "탭하여 삭제" + "%1$s 리액션 선택됨" + "%1$s 리액션 선택 해제됨" + "선택되지 않음" + "선택됨" "나" "최근 파일" "+%1$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 20d4ebaacf8..18d06556836 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -111,6 +111,7 @@ Show message options Show reactions Open attachment + Message actions Voice message (%s) @@ -155,9 +156,16 @@ Add reaction You Tap to remove + Selected + Not selected + Select + Unselect + %1$s reaction selected + %1$s reaction unselected Show more reactions + Emoji picker Delete message