From 12e09cb0ed4694003da7af1bc26d59f3c571afad Mon Sep 17 00:00:00 2001 From: evgeny Date: Sun, 4 Oct 2026 18:07:46 +0200 Subject: [PATCH] Render one-line Android invitations and retain full links for copy --- .../utun/chat/ui/components/MessageBubble.kt | 17 +++++++++++++++++ tools/chatgui/src/messagedelegate.h | 1 + 2 files changed, 18 insertions(+) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt index 02075213..16fa0feb 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/components/MessageBubble.kt @@ -15,6 +15,8 @@ import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -41,11 +43,13 @@ import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -95,6 +99,7 @@ private fun detectEmojiOnly(text: String): Int { private fun deliveryLabel(message: Message): String = if (message.deliveryStatusRes == 0) "" else stringResource(message.deliveryStatusRes) +@OptIn(ExperimentalFoundationApi::class) @Composable fun MessageBubble(message: Message, playbackState: ChatViewModel.PlaybackState = ChatViewModel.PlaybackState(), onPlayVoice: (String, Int) -> Unit = { _, _ -> }, @@ -154,6 +159,18 @@ fun MessageBubble(message: Message, playbackState: ChatViewModel.PlaybackState = Spacer(Modifier.height(2.dp)) when { + message.inviteGroupName != null -> { + val clipboard = LocalClipboardManager.current + Text(stringResource(R.string.group_invitation, message.inviteGroupName), fontSize = 17.sp, color = textColor) + Text(message.text, fontSize = 17.sp, color = Color(0xFF3390EC), maxLines = 1, overflow = TextOverflow.Ellipsis, + modifier = Modifier.fillMaxWidth().combinedClickable( + onClick = { onInviteLink(message.text) }, + onLongClickLabel = stringResource(R.string.copy_link), + onLongClick = { + clipboard.setText(AnnotatedString(message.text)) + LogManager.addLog("DEBUG", "PM", "invitation link copied: seq=${message.id} bytes=${message.text.length}") + })) + } isVoice -> VoiceBubble(message, textColor, isActive, playbackState, onPlayVoice, onSeekVoice, onDownloadFile) isVideo -> VideoBubble(message, textColor, onDownloadFile, onPlayVideo) isImage -> ImageBubble(message, textColor, onDownloadFile, onOpenImage) diff --git a/tools/chatgui/src/messagedelegate.h b/tools/chatgui/src/messagedelegate.h index 3d9fbd77..94ab1bc6 100644 --- a/tools/chatgui/src/messagedelegate.h +++ b/tools/chatgui/src/messagedelegate.h @@ -43,6 +43,7 @@ enum MessageDataRole { MsgVideoHeightRole = Qt::UserRole + 34, MsgVideoDurationMsRole = Qt::UserRole + 35, MsgDeliveryStateRole = Qt::UserRole + 36, + MsgInviteLinkRole = Qt::UserRole + 37, /* полная ссылка; MsgTextRole содержит локализованный заголовок и ссылку */ }; class MessageDelegate : public QStyledItemDelegate {