diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/list/ChannelItem.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/list/ChannelItem.kt index d1d38cd12ac..e5d760b3203 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/list/ChannelItem.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/list/ChannelItem.kt @@ -47,8 +47,6 @@ import androidx.compose.ui.platform.LocalResources import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -142,7 +140,8 @@ public fun ChannelItem( }, ) { val channel = channelItem.channel - val description = stringResource(id = R.string.stream_compose_cd_channel_item) + val openLabel = stringResource(R.string.stream_compose_channel_item_open) + val optionsLabel = stringResource(R.string.stream_compose_channel_item_options) val interactionSource = remember { MutableInteractionSource() } val isFocused by interactionSource.collectIsFocusedAsState() @@ -154,13 +153,14 @@ public fun ChannelItem( .testTag("Stream_ChannelItem") .fillMaxWidth() .wrapContentHeight() - .semantics { contentDescription = description } .applyIf(isFocused) { border(2.dp, ChatTheme.colors.borderUtilityFocused, shape) } .clip(shape) .applyIf(channelItem.isSelected) { background(ChatTheme.colors.backgroundUtilitySelected, shape) } .combinedClickable( onClick = { onChannelClick(channel) }, + onClickLabel = openLabel, onLongClick = { onChannelLongClick(channel) }, + onLongClickLabel = optionsLabel, indication = ripple(), interactionSource = interactionSource, ), @@ -283,7 +283,7 @@ private fun TitleRow( .testTag("Stream_ChannelMutedIcon") .size(16.dp), painter = painterResource(id = R.drawable.stream_design_ic_mute), - contentDescription = null, + contentDescription = stringResource(R.string.stream_compose_channel_item_muted), tint = ChatTheme.colors.textTertiary, ) } @@ -350,7 +350,7 @@ private fun MessageRow( .testTag("Stream_ChannelMutedIcon") .size(16.dp), painter = painterResource(id = R.drawable.stream_design_ic_mute), - contentDescription = null, + contentDescription = stringResource(R.string.stream_compose_channel_item_muted), tint = ChatTheme.colors.textTertiary, ) } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/HeaderScaffold.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/HeaderScaffold.kt index 11701e5eccc..84c464b2db0 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/HeaderScaffold.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/HeaderScaffold.kt @@ -36,6 +36,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.heading +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize @@ -140,7 +142,8 @@ internal fun RowScope.DefaultListHeaderCenterContent( modifier = Modifier .weight(1f) .wrapContentWidth() - .padding(horizontal = StreamTokens.spacingMd), + .padding(horizontal = StreamTokens.spacingMd) + .semantics { heading() }, text = title, style = ChatTheme.typography.headingSmall, maxLines = 1, @@ -154,7 +157,8 @@ internal fun RowScope.DefaultListHeaderCenterContent( modifier = Modifier .weight(1f) .wrapContentWidth() - .padding(horizontal = StreamTokens.spacingMd), + .padding(horizontal = StreamTokens.spacingMd) + .semantics { heading() }, text = stringResource(R.string.stream_compose_disconnected), style = ChatTheme.typography.headingSmall, maxLines = 1, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/MessagePreviewContent.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/MessagePreviewContent.kt index ded6fda1744..ca0b3cdfb73 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/MessagePreviewContent.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/MessagePreviewContent.kt @@ -25,7 +25,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.text import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle @@ -64,7 +64,7 @@ internal fun MessagePreviewContent( Row( modifier = modifier .testTag("Stream_MessagePreview") - .semantics { text = AnnotatedString(fullPreview) }, + .clearAndSetSemantics { text = AnnotatedString(fullPreview) }, horizontalArrangement = Arrangement.spacedBy(StreamTokens.spacing3xs), ) { if (senderName != null) { @@ -101,7 +101,7 @@ internal fun DraftPreviewContent( Row( modifier = modifier .testTag("Stream_MessagePreview") - .semantics { text = AnnotatedString(fullPreview) }, + .clearAndSetSemantics { text = AnnotatedString(fullPreview) }, horizontalArrangement = Arrangement.spacedBy(StreamTokens.spacing3xs), ) { Text( diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/UnreadCountIndicator.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/UnreadCountIndicator.kt index f74faba21fd..724148cb68e 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/UnreadCountIndicator.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/channels/UnreadCountIndicator.kt @@ -27,9 +27,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.pluralStringResource +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview 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.StreamTokens @@ -47,12 +51,18 @@ public fun UnreadCountIndicator( color: Color = ChatTheme.colors.accentPrimary, ) { val displayText = if (unreadCount > LimitTooManyUnreadCount) UnreadCountMany else unreadCount.toString() + val description = pluralStringResource( + R.plurals.stream_compose_channel_item_unread, + unreadCount, + unreadCount, + ) Box( modifier = modifier .defaultMinSize(minWidth = 20.dp, minHeight = 20.dp) .background(shape = CircleShape, color = color) - .padding(horizontal = StreamTokens.spacing2xs), // 4dp horizontal content padding + .padding(horizontal = StreamTokens.spacing2xs) + .clearAndSetSemantics { contentDescription = description }, contentAlignment = Alignment.Center, ) { Text( diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/TextUtils.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/TextUtils.kt index 0631f35d053..7bf1f90bd21 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/TextUtils.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/TextUtils.kt @@ -226,16 +226,21 @@ private fun AnnotatedString.Builder.tagUser( if (start < 0) return@forEach + // Backtrack one position to include the leading `@`. Clamp to 0 when the mention is at the + // start of the text and no `@` precedes it — otherwise the resulting -1 span start crashes + // TalkBack's spannable conversion with `setSpan (-1 ...) starts before 0`. + val styledStart = (start - 1).coerceAtLeast(0) + addStyle( style = SpanStyle(color = mentionsColor), - start = start - 1, // -1 to include the @ symbol + start = styledStart, end = end, ) addStringAnnotation( tag = AnnotationTagMention, annotation = userName, - start = start - 1, // -1 to include the @ symbol + start = styledStart, end = end, ) } 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 202dcf8b5e5..7481f63b568 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 @@ -56,7 +56,9 @@ "+%1$d" "Bloquear usuario" "Cancelar" - "Elemento de canal" + "silenciado" + "Abrir conversación" + "Abrir opciones de conversación" "Elemento de mensaje" "Botón de reproducción" "Borrador: " @@ -259,6 +261,10 @@ "Conectado" "Vídeo" "Esperando conexión de red" + + "%d mensaje sin leer" + "%d mensajes sin leer" + "%d persona está escribiendo" "%d personas están escribiendo" 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 76a4240e600..5ce3ccca9b5 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 @@ -56,7 +56,9 @@ "+%1$d" "Bloquer l\'utilisateur" "Annuler" - "Élément de canal" + "en sourdine" + "Ouvrir la conversation" + "Ouvrir les options de conversation" "Élément de message" "Bouton de lecture" "Brouillon : " @@ -259,6 +261,10 @@ "En ligne" "Vidéo" "En attente de réseau" + + "%d message non lu" + "%d messages non lus" + "%d personne écrit" "%d personnes écrivent" 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 2c511cd628b..eae677cfdcb 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 @@ -15,6 +15,10 @@ limitations under the License. --> + + "%d अपठित संदेश" + "%d अपठित संदेश" + "%d व्यक्ति टाइप कर रहा है" "%d लोग टाइप कर रहे हैं" @@ -112,7 +116,9 @@ "+%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 d465a0a68d6..9d7a7034dc7 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 @@ -56,7 +56,9 @@ "+%1$d" "Blokir pengguna" "Batal" - "Item saluran" + "dibisukan" + "Buka percakapan" + "Buka opsi percakapan" "Item pesan" "Tombol putar" "Draf: " @@ -259,6 +261,10 @@ "Online" "Video" "Menunggu jaringan" + + "%d pesan belum dibaca" + "%d pesan belum dibaca" + "%d orang sedang mengetik" 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 f69c0f98282..4fb11462293 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 @@ -15,6 +15,10 @@ limitations under the License. --> + + "%d messaggio non letto" + "%d messaggi non letti" + "%d persona sta scrivendo" "%d persone stanno scrivendo" @@ -112,7 +116,9 @@ "+%1$d" "Blocca utente" "Annulla" - "Elemento canale" + "silenziato" + "Apri conversazione" + "Apri opzioni conversazione" "Elemento messaggio" "Pulsante riproduci" "Bozza: " 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 d478f091e40..5e6ffcc84a5 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 @@ -56,7 +56,9 @@ "+%1$d" "ユーザーをブロック" "キャンセル" - "チャンネル項目" + "ミュート中" + "会話を開く" + "会話のオプションを開く" "メッセージ項目" "再生ボタン" "下書き: " @@ -64,6 +66,10 @@ "\"%1$s\"の検索結果はありません" "新しいチャット" "チャットを始める" + + "%d件の未読メッセージ" + "%d件の未読メッセージ" + "%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 b5b4caa2a14..fb28eb654c1 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 @@ -56,7 +56,9 @@ "+%1$d" "사용자 차단" "취소" - "채널 항목" + "음소거됨" + "대화 열기" + "대화 옵션 열기" "메시지 항목" "재생 버튼" "임시 저장: " @@ -64,6 +66,10 @@ "\"%1$s\"에 대한 검색결과가 없습니다" "새 채팅" "채팅 시작하기" + + "%d개의 안 읽은 메시지" + "%d개의 안 읽은 메시지" + "%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 4faa3c59bf2..23bbe66965a 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -288,7 +288,13 @@ %.2f MB needs to be downloaded before sharing. - Channel item + Open conversation + Open conversation options + muted + + %d unread message + %d unread messages + Message item Play button