Forward: фикс размера пузыря и отправки. Дубли дат убраны.

- Forward пузырь подстраивается под размер контента (как Telegram)
- Длинные имена обрезаются "Forwarded from Alex M..." вместо растяжения
- Исправлена отправка forward — consumeForwardMessagesForChat при открытии чата
- Floating date header показывается только при активном скролле (убраны дубли дат)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-08 00:50:25 +05:00
parent 9fafa52483
commit 14d7fc6eb1
2 changed files with 33 additions and 27 deletions

View File

@@ -1388,6 +1388,14 @@ fun ChatDetailScreen(
com.rosetta.messenger.ui.components.EmojiCache.preload(context) com.rosetta.messenger.ui.components.EmojiCache.preload(context)
} }
// Consume pending forward messages for this chat
LaunchedEffect(user.publicKey, forwardTrigger) {
val pendingForwards = ForwardManager.consumeForwardMessagesForChat(user.publicKey)
if (pendingForwards.isNotEmpty()) {
viewModel.sendForwardDirectly(user.publicKey, pendingForwards)
}
}
// Отмечаем сообщения как прочитанные только когда экран активен (RESUMED) // Отмечаем сообщения как прочитанные только когда экран активен (RESUMED)
LaunchedEffect(messages, isScreenActive) { LaunchedEffect(messages, isScreenActive) {
if (messages.isNotEmpty() && isScreenActive) { if (messages.isNotEmpty() && isScreenActive) {
@@ -1440,8 +1448,7 @@ fun ChatDetailScreen(
messagesWithDates.isNotEmpty() && messagesWithDates.isNotEmpty() &&
floatingDateText != null && floatingDateText != null &&
!isAtBottom && !isAtBottom &&
(listState.isScrollInProgress || listState.isScrollInProgress
listState.firstVisibleItemIndex > 0)
} }
} }

View File

@@ -2383,6 +2383,7 @@ fun ForwardedMessagesBubble(
onMentionClick: (username: String) -> Unit = {}, onMentionClick: (username: String) -> Unit = {},
onTextSpanPressStart: (() -> Unit)? = null onTextSpanPressStart: (() -> Unit)? = null
) { ) {
val configuration = androidx.compose.ui.platform.LocalConfiguration.current
val backgroundColor = val backgroundColor =
if (isOutgoing) Color.Black.copy(alpha = 0.1f) if (isOutgoing) Color.Black.copy(alpha = 0.1f)
else Color.Black.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.05f)
@@ -2406,9 +2407,11 @@ fun ForwardedMessagesBubble(
}.toMap() }.toMap()
} }
val maxBubbleWidth = (configuration.screenWidthDp * 0.65f).dp
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .widthIn(max = maxBubbleWidth)
.clip(RoundedCornerShape(4.dp)) .clip(RoundedCornerShape(4.dp))
.background(backgroundColor) .background(backgroundColor)
) { ) {
@@ -2439,29 +2442,24 @@ fun ForwardedMessagesBubble(
} }
// "Forwarded from [Name]" — clickable to open profile // "Forwarded from [Name]" — clickable to open profile
Row( Text(
verticalAlignment = Alignment.CenterVertically, text = buildAnnotatedString {
withStyle(SpanStyle(
color = nameColor.copy(alpha = 0.7f),
fontWeight = FontWeight.Normal
)) { append("Forwarded from ") }
withStyle(SpanStyle(
color = nameColor,
fontWeight = FontWeight.Bold
)) { append(fwd.forwardedFromName.ifEmpty { "User" }) }
},
fontSize = 13.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.clickable(enabled = fwd.senderPublicKey.isNotEmpty()) { modifier = Modifier.clickable(enabled = fwd.senderPublicKey.isNotEmpty()) {
onForwardedSenderClick(fwd.senderPublicKey) onForwardedSenderClick(fwd.senderPublicKey)
} }
) { )
Text(
text = "Forwarded from ",
color = nameColor.copy(alpha = 0.7f),
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
maxLines = 1
)
Text(
text = fwd.forwardedFromName.ifEmpty { "User" },
color = nameColor,
fontSize = 13.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f, fill = false)
)
}
// Attachments (images) — before text (text acts as caption) // Attachments (images) — before text (text acts as caption)
val imageAttachments = fwd.attachments.filter { it.type == AttachmentType.IMAGE } val imageAttachments = fwd.attachments.filter { it.type == AttachmentType.IMAGE }
@@ -2611,10 +2609,11 @@ private fun ForwardedImagePreview(
} }
} }
val maxPhotoWidthDp = TelegramBubbleSpec.maxPhotoWidth(configuration.screenWidthDp).dp // Forwarded images use smaller max size to fit inside the forward bubble
val minPhotoWidthDp = TelegramBubbleSpec.minPhotoWidth.dp val maxPhotoWidthDp = (configuration.screenWidthDp * 0.55f).toInt().dp
val minPhotoHeightDp = TelegramBubbleSpec.minPhotoHeight.dp val minPhotoWidthDp = 100.dp
val maxPhotoHeightDp = TelegramBubbleSpec.maxPhotoHeight.dp val minPhotoHeightDp = 80.dp
val maxPhotoHeightDp = 280.dp
val (previewWidth, previewHeight) = val (previewWidth, previewHeight) =
remember( remember(
attachment.width, attachment.width,