diff --git a/client-mobile/.gradle/8.5/executionHistory/executionHistory.bin b/client-mobile/.gradle/8.5/executionHistory/executionHistory.bin
index 16c344b..8099f3c 100644
Binary files a/client-mobile/.gradle/8.5/executionHistory/executionHistory.bin and b/client-mobile/.gradle/8.5/executionHistory/executionHistory.bin differ
diff --git a/client-mobile/.gradle/8.5/executionHistory/executionHistory.lock b/client-mobile/.gradle/8.5/executionHistory/executionHistory.lock
index 85cfe74..983dcba 100644
Binary files a/client-mobile/.gradle/8.5/executionHistory/executionHistory.lock and b/client-mobile/.gradle/8.5/executionHistory/executionHistory.lock differ
diff --git a/client-mobile/.gradle/8.5/fileHashes/fileHashes.bin b/client-mobile/.gradle/8.5/fileHashes/fileHashes.bin
index 973789f..7d9f990 100644
Binary files a/client-mobile/.gradle/8.5/fileHashes/fileHashes.bin and b/client-mobile/.gradle/8.5/fileHashes/fileHashes.bin differ
diff --git a/client-mobile/.gradle/8.5/fileHashes/fileHashes.lock b/client-mobile/.gradle/8.5/fileHashes/fileHashes.lock
index 09715ad..9f3cca0 100644
Binary files a/client-mobile/.gradle/8.5/fileHashes/fileHashes.lock and b/client-mobile/.gradle/8.5/fileHashes/fileHashes.lock differ
diff --git a/client-mobile/.gradle/8.5/fileHashes/resourceHashesCache.bin b/client-mobile/.gradle/8.5/fileHashes/resourceHashesCache.bin
index b1543db..338b816 100644
Binary files a/client-mobile/.gradle/8.5/fileHashes/resourceHashesCache.bin and b/client-mobile/.gradle/8.5/fileHashes/resourceHashesCache.bin differ
diff --git a/client-mobile/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/client-mobile/.gradle/buildOutputCleanup/buildOutputCleanup.lock
index 794f912..1262973 100644
Binary files a/client-mobile/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/client-mobile/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/client-mobile/.gradle/buildOutputCleanup/outputFiles.bin b/client-mobile/.gradle/buildOutputCleanup/outputFiles.bin
index c4c8f46..beb3dcf 100644
Binary files a/client-mobile/.gradle/buildOutputCleanup/outputFiles.bin and b/client-mobile/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/client-mobile/app/src/main/res/values-en/strings.xml b/client-mobile/app/src/main/res/values-en/strings.xml
index ef63089..8654653 100644
--- a/client-mobile/app/src/main/res/values-en/strings.xml
+++ b/client-mobile/app/src/main/res/values-en/strings.xml
@@ -53,4 +53,11 @@
Message...
Voice Message
Send
+ Photo
+ Video
+ Audio
+ File
+ GIF
+ Reply to
+ yourself
diff --git a/client-mobile/app/src/main/res/values/strings.xml b/client-mobile/app/src/main/res/values/strings.xml
index 3962884..b3a476a 100644
--- a/client-mobile/app/src/main/res/values/strings.xml
+++ b/client-mobile/app/src/main/res/values/strings.xml
@@ -75,4 +75,11 @@
Контакты
Профиль
Сохранение...
+ Фото
+ Видео
+ Аудио
+ Файл
+ GIF
+ Ответ
+ самому себе
diff --git a/client-mobile/chats/presentation/chat_detail/ChatDetailScreen.kt b/client-mobile/chats/presentation/chat_detail/ChatDetailScreen.kt
index 981950e..225aea0 100644
--- a/client-mobile/chats/presentation/chat_detail/ChatDetailScreen.kt
+++ b/client-mobile/chats/presentation/chat_detail/ChatDetailScreen.kt
@@ -640,20 +640,63 @@ fun ChatDetailScreen(
.weight(1f)
.padding(horizontal = 8.dp, vertical = 2.dp)
) {
+ val replyPrefix = stringResource(R.string.reply_prefix)
+ val replySelf = stringResource(R.string.reply_self)
+
Text(
- text = "Ответ " + (if (replyMsg.senderId == viewModel.getCurrentUserId()) "самом себе" else replyMsg.senderName),
+ text = replyPrefix + (if (replyMsg.senderId == viewModel.getCurrentUserId()) replySelf else replyMsg.senderName),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold
)
+
+ val photoText = stringResource(R.string.reply_photo)
+ val videoText = stringResource(R.string.reply_video)
+ val voiceText = stringResource(R.string.voice_message)
+ val audioText = stringResource(R.string.reply_audio)
+ val fileText = stringResource(R.string.reply_file)
+ val gifText = stringResource(R.string.reply_gif)
+ val mediaText = stringResource(R.string.media)
+
+ val replyText = remember(replyMsg) {
+ if (!replyMsg.content.isNullOrEmpty()) {
+ replyMsg.content
+ } else {
+ when (replyMsg.mediaType) {
+ chats.domain.model.MediaType.IMAGE -> photoText
+ chats.domain.model.MediaType.VIDEO -> videoText
+ chats.domain.model.MediaType.AUDIO -> if (replyMsg.media.any { it.type == "voice" }) voiceText else audioText
+ chats.domain.model.MediaType.FILE -> fileText
+ chats.domain.model.MediaType.GIF -> gifText
+ else -> mediaText
+ }
+ }
+ }
+
Text(
- text = replyMsg.content ?: if (replyMsg.media.isNotEmpty()) "Медиа" else "...",
+ text = replyText,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
+
+ if ((replyMsg.mediaType == chats.domain.model.MediaType.IMAGE ||
+ replyMsg.mediaType == chats.domain.model.MediaType.VIDEO ||
+ replyMsg.mediaType == chats.domain.model.MediaType.GIF) &&
+ replyMsg.media.isNotEmpty()) {
+ androidx.compose.foundation.Image(
+ painter = rememberAsyncImagePainter(replyMsg.media.first().url),
+ contentDescription = null,
+ modifier = Modifier
+ .padding(end = 4.dp)
+ .size(36.dp)
+ .clip(RoundedCornerShape(4.dp)),
+ contentScale = androidx.compose.ui.layout.ContentScale.Crop
+ )
+ }
+
IconButton(onClick = { viewModel.cancelReply() }) {
Icon(Icons.Default.Close, contentDescription = "Cancel", modifier = Modifier.size(20.dp), tint = Color.Gray)
}
diff --git a/client-mobile/chats/presentation/components/MessageBubble.kt b/client-mobile/chats/presentation/components/MessageBubble.kt
index 7b30a20..8baeea6 100644
--- a/client-mobile/chats/presentation/components/MessageBubble.kt
+++ b/client-mobile/chats/presentation/components/MessageBubble.kt
@@ -123,7 +123,22 @@ fun MessageBubble(
.width(2.dp)
.background(if (isCurrentUser) Color.White else Color(0xFF3096E5))
)
- Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) {
+ val context = androidx.compose.ui.platform.LocalContext.current
+ val isReplyImage = reply.mediaType == MediaType.IMAGE || reply.mediaType == MediaType.VIDEO || reply.mediaType == MediaType.GIF
+
+ if (isReplyImage && reply.media.isNotEmpty()) {
+ AsyncImage(
+ model = reply.media.first().url,
+ contentDescription = null,
+ modifier = Modifier
+ .fillMaxHeight()
+ .width(40.dp)
+ .clip(RoundedCornerShape(0.dp, 4.dp, 4.dp, 0.dp)),
+ contentScale = ContentScale.Crop
+ )
+ }
+
+ Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp).weight(1f)) {
val accentColor = if (isCurrentUser) Color.White else Color(0xFF3096E5)
Text(
text = reply.senderName,
@@ -132,8 +147,32 @@ fun MessageBubble(
maxLines = 1,
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
)
+
+ val photoText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.reply_photo)
+ val videoText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.reply_video)
+ val voiceText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.voice_message)
+ val audioText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.reply_audio)
+ val fileText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.reply_file)
+ val gifText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.reply_gif)
+ val mediaText = androidx.compose.ui.res.stringResource(ru.knot.messager.R.string.media)
+
+ val replyText = remember(reply) {
+ if (!reply.content.isNullOrEmpty()) {
+ reply.content
+ } else {
+ when (reply.mediaType) {
+ MediaType.IMAGE -> photoText
+ MediaType.VIDEO -> videoText
+ MediaType.AUDIO -> if (reply.media.any { it.type == "voice" }) voiceText else audioText
+ MediaType.FILE -> fileText
+ MediaType.GIF -> gifText
+ else -> mediaText
+ }
+ }
+ }
+
Text(
- text = reply.content ?: if (reply.media.isNotEmpty()) "\uD83D\uDCCE Media" else "",
+ text = replyText,
style = MaterialTheme.typography.bodySmall,
color = contentColor.copy(alpha = 0.8f),
maxLines = 1,