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 f849ce0de22..9735a9e8963 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -1557,10 +1557,12 @@ public final class io/getstream/chat/android/compose/ui/components/messages/Comp public final class io/getstream/chat/android/compose/ui/components/messages/ComposableSingletons$QuotedMessageKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/messages/ComposableSingletons$QuotedMessageKt; public fun ()V + public final fun getLambda$-1414494261$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-242957275$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-615170823$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1327756724$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1642749758$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1769024465$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1784593268$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$976393970$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/messages/QuotedMessage.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/QuotedMessage.kt index 16abcda92cf..07e48059a97 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/QuotedMessage.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messages/QuotedMessage.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:Suppress("TooManyFunctions") + package io.getstream.chat.android.compose.ui.components.messages import androidx.annotation.DrawableRes @@ -154,10 +156,26 @@ private fun QuotedMessageUserName( isComposerBanner -> stringResource(R.string.stream_compose_quoted_message_reply_to, message.user.name) else -> message.user.name } - val accessibilityName = if (isMine && isComposerBanner) { - stringResource(R.string.stream_compose_quoted_message_reply_to_you) - } else { - null + val accessibilityName = when { + replyMessage == null && isMine -> + stringResource(R.string.stream_compose_quoted_message_reply_to_you) + replyMessage != null -> { + val replierName = if (replyMessage.isMine(currentUser)) { + stringResource(R.string.stream_compose_quoted_message_you) + } else { + replyMessage.user.name + } + if (isMine) { + stringResource(R.string.stream_compose_quoted_message_replied_to_your_message, replierName) + } else { + stringResource( + R.string.stream_compose_quoted_message_replied_to_their_message, + replierName, + message.user.name, + ) + } + } + else -> null } Text( @@ -287,6 +305,18 @@ private fun QuotedMessageInComposerPreview() { ChatTheme { QuotedMessageInComposer() } } +@Preview +@Composable +private fun QuotedMessageReplyByMeToOtherPreview() { + ChatTheme { QuotedMessageReplyByMeToOther() } +} + +@Preview +@Composable +private fun QuotedMessageReplyByOtherToMePreview() { + ChatTheme { QuotedMessageReplyByOtherToMe() } +} + @Composable internal fun QuotedMessageFromOtherUser() { QuotedMessage( @@ -374,3 +404,37 @@ internal fun QuotedMessageInComposer() { onCancelClick = {}, ) } + +@Composable +internal fun QuotedMessageReplyByMeToOther() { + QuotedMessage( + message = Message( + id = "msg-7", + text = "Original message from the other user", + user = PreviewUserData.user2, + ), + currentUser = PreviewUserData.user1, + replyMessage = Message( + id = "reply-7", + text = "On it.", + user = PreviewUserData.user1, + ), + ) +} + +@Composable +internal fun QuotedMessageReplyByOtherToMe() { + QuotedMessage( + message = Message( + id = "msg-8", + text = "Original message from me", + user = PreviewUserData.user1, + ), + currentUser = PreviewUserData.user1, + replyMessage = Message( + id = "reply-8", + text = "Got it, thanks!", + user = PreviewUserData.user2, + ), + ) +} diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageContainer.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageContainer.kt index 26828e6f9ea..53a90e813e1 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageContainer.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageContainer.kt @@ -23,6 +23,7 @@ import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.detectHorizontalDragGestures +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -62,6 +63,8 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.onLongClick +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.LayoutDirection @@ -177,15 +180,36 @@ public fun MessageContainer( val openThreadLabel = stringResource(R.string.stream_compose_message_item_open_thread) val messageOptionsLabel = stringResource(R.string.stream_compose_message_item_options) - val clickModifier = Modifier.combinedClickable( - interactionSource = remember(::MutableInteractionSource), - indication = null, - enabled = canOpenThread || canOpenActions, - onClick = { if (canOpenThread) onThreadClick(message) }, - onLongClick = { if (canOpenActions) onLongItemClick(message) }, - onClickLabel = openThreadLabel.takeIf { canOpenThread }, - onLongClickLabel = messageOptionsLabel.takeIf { canOpenActions }, - ) + // The pointerInput lambda below is keyed on Unit, so it is launched once and survives + // recomposition. Read the latest message + handler through rememberUpdatedState so the + // long-press fires with the current state (e.g. after a reaction is added) instead of a + // stale capture from first composition. + val currentMessage by rememberUpdatedState(message) + val currentOnLongItemClick by rememberUpdatedState(onLongItemClick) + val clickModifier = when { + canOpenThread -> Modifier.combinedClickable( + interactionSource = remember(::MutableInteractionSource), + indication = null, + onClick = { onThreadClick(message) }, + onLongClick = { if (canOpenActions) onLongItemClick(message) }, + onClickLabel = openThreadLabel, + onLongClickLabel = messageOptionsLabel.takeIf { canOpenActions }, + ) + canOpenActions -> + Modifier + .pointerInput(Unit) { + detectTapGestures( + onLongPress = { currentOnLongItemClick(currentMessage) }, + ) + } + .semantics(mergeDescendants = true) { + onLongClick(label = messageOptionsLabel) { + currentOnLongItemClick(currentMessage) + true + } + } + else -> Modifier.semantics(mergeDescendants = true) {} + } val highlightColor = ChatTheme.colors.backgroundCoreHighlight val backgroundColor = when { 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 0966f3a4956..d7e4530a4f6 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 @@ -224,6 +224,8 @@ "Mensaje de voz (%s)" "Giphy" "%d multimedia" + "%1$s respondió al mensaje de %2$s" + "%1$s respondió a tu mensaje" "Responder a %s" "Responder a ti" "Tú" 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 aab62aed9cc..9a10ebe8c97 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 @@ -224,6 +224,8 @@ "Message vocal (%s)" "Giphy" "%d média" + "%1$s a répondu au message de %2$s" + "%1$s a répondu à votre message" "Répondre à %s" "Répondre à vous-même" "Vous" 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 152f472badf..94f1dbbdf26 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 @@ -284,6 +284,8 @@ "वॉइस मैसेज (%s)" "Giphy" "%d मीडिया" + "%1$s ने %2$s के संदेश का जवाब दिया" + "%1$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 b8641a0dd00..be571420618 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 @@ -224,6 +224,8 @@ "Pesan suara (%s)" "Giphy" "%d media" + "%1$s membalas pesan %2$s" + "%1$s membalas pesan Anda" "Balas ke %s" "Balas ke diri sendiri" "Anda" 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 aa4c860bc22..c6f90f00a10 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 @@ -284,6 +284,8 @@ "Messaggio vocale (%s)" "Giphy" "%d media" + "%1$s ha risposto al messaggio di %2$s" + "%1$s ha risposto al tuo messaggio" "Rispondi a %s" "Rispondi a te stesso" "Tu" 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 f37bcd36aef..c7628d76f80 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 @@ -257,6 +257,8 @@ "%d枚の写真" "%dメディア" + "%1$sが%2$sのメッセージに返信しました" + "%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 b8fede41890..ca3b52ca9d9 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 @@ -257,6 +257,8 @@ "%d장의 사진" "%d 미디어" + "%1$s님이 %2$s님의 메시지에 답장했습니다" + "%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 18d06556836..25422da5cc2 100644 --- a/stream-chat-android-compose/src/main/res/values/strings.xml +++ b/stream-chat-android-compose/src/main/res/values/strings.xml @@ -119,6 +119,8 @@ %d media Reply to %s Reply to you + %1$s replied to your message + %1$s replied to %2$s\'s message You diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messages/QuotedMessageTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messages/QuotedMessageTest.kt index 65d7ea00b31..b3f4442c05c 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messages/QuotedMessageTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messages/QuotedMessageTest.kt @@ -60,4 +60,14 @@ internal class QuotedMessageTest : PaparazziComposeTest { fun `in composer`() { snapshotWithDarkModeRow { QuotedMessageInComposer() } } + + @Test + fun `reply by me to other`() { + snapshotWithDarkModeRow { QuotedMessageReplyByMeToOther() } + } + + @Test + fun `reply by other to me`() { + snapshotWithDarkModeRow { QuotedMessageReplyByOtherToMe() } + } } diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messages_QuotedMessageTest_reply_by_me_to_other.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messages_QuotedMessageTest_reply_by_me_to_other.png new file mode 100644 index 00000000000..3c4e1f180c9 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messages_QuotedMessageTest_reply_by_me_to_other.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messages_QuotedMessageTest_reply_by_other_to_me.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messages_QuotedMessageTest_reply_by_other_to_me.png new file mode 100644 index 00000000000..dbc5baddea3 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messages_QuotedMessageTest_reply_by_other_to_me.png differ