feat: интегрировать TextSelectionHelper в ChatDetailScreen и MessageBubble
- TextSelectionHelper инстанс в ChatDetailScreen - TextSelectionOverlay поверх LazyColumn - Clear selection при scroll и при message selection mode - onTextLongPress + onViewCreated проброшены через MessageBubble к AppleEmojiText Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -394,6 +394,9 @@ fun ChatDetailScreen(
|
||||
var longPressSuppressedMessageId by remember { mutableStateOf<String?>(null) }
|
||||
var longPressSuppressUntilMs by remember { mutableLongStateOf(0L) }
|
||||
|
||||
// 🔤 TEXT SELECTION - Telegram-style character-level selection
|
||||
val textSelectionHelper = remember { com.rosetta.messenger.ui.chats.components.TextSelectionHelper() }
|
||||
|
||||
// 💬 MESSAGE CONTEXT MENU STATE
|
||||
var contextMenuMessage by remember { mutableStateOf<ChatMessage?>(null) }
|
||||
var showContextMenu by remember { mutableStateOf(false) }
|
||||
@@ -838,6 +841,7 @@ fun ChatDetailScreen(
|
||||
// иначе при двойном колбэке (text + bubble) сообщение мгновенно "откатывается".
|
||||
val selectMessageOnLongPress: (messageId: String, canSelect: Boolean) -> Unit =
|
||||
{ messageId, canSelect ->
|
||||
textSelectionHelper.clear()
|
||||
if (canSelect && !selectedMessages.contains(messageId)) {
|
||||
selectedMessages = selectedMessages + messageId
|
||||
}
|
||||
@@ -886,6 +890,13 @@ fun ChatDetailScreen(
|
||||
}
|
||||
}
|
||||
|
||||
// 🔤 Сброс текстового выделения при скролле
|
||||
LaunchedEffect(listState.isScrollInProgress) {
|
||||
if (listState.isScrollInProgress && textSelectionHelper.isActive) {
|
||||
textSelectionHelper.clear()
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 Display reply messages - получаем полную информацию о сообщениях для reply
|
||||
val displayReplyMessages =
|
||||
remember(replyMessages, messages) {
|
||||
@@ -3164,6 +3175,8 @@ fun ChatDetailScreen(
|
||||
MessageBubble(
|
||||
message =
|
||||
message,
|
||||
textSelectionHelper =
|
||||
textSelectionHelper,
|
||||
isDarkTheme =
|
||||
isDarkTheme,
|
||||
hasWallpaper =
|
||||
@@ -3644,6 +3657,11 @@ fun ChatDetailScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
// 🔤 Text selection overlay
|
||||
com.rosetta.messenger.ui.chats.components.TextSelectionOverlay(
|
||||
helper = textSelectionHelper,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +320,7 @@ fun TypingIndicator(
|
||||
@Composable
|
||||
fun MessageBubble(
|
||||
message: ChatMessage,
|
||||
textSelectionHelper: com.rosetta.messenger.ui.chats.components.TextSelectionHelper? = null,
|
||||
isDarkTheme: Boolean,
|
||||
hasWallpaper: Boolean = false,
|
||||
isSystemSafeChat: Boolean = false,
|
||||
@@ -400,6 +401,7 @@ fun MessageBubble(
|
||||
if (message.isOutgoing) Color(0xFFB3E5FC) // Светло-голубой на синем фоне
|
||||
else Color(0xFF2196F3) // Стандартный Material Blue для входящих
|
||||
}
|
||||
var textViewRef by remember { mutableStateOf<com.rosetta.messenger.ui.components.AppleEmojiTextView?>(null) }
|
||||
val linksEnabled = !isSelectionMode
|
||||
val textClickHandler: (() -> Unit)? = onClick
|
||||
val mentionClickHandler: ((String) -> Unit)? =
|
||||
@@ -1066,7 +1068,20 @@ fun MessageBubble(
|
||||
onClick =
|
||||
textClickHandler,
|
||||
onLongClick =
|
||||
onLongClick // 🔥 Long press для selection
|
||||
onLongClick, // 🔥 Long press для selection
|
||||
onViewCreated = { textViewRef = it },
|
||||
onTextLongPress = if (textSelectionHelper != null && !isSelectionMode) { touchX, touchY ->
|
||||
val info = textViewRef?.getLayoutInfo()
|
||||
if (info != null) {
|
||||
textSelectionHelper.startSelection(
|
||||
messageId = message.id,
|
||||
info = info,
|
||||
touchX = touchX,
|
||||
touchY = touchY,
|
||||
view = textViewRef
|
||||
)
|
||||
}
|
||||
} else null
|
||||
)
|
||||
},
|
||||
timeContent = {
|
||||
@@ -1157,12 +1172,21 @@ fun MessageBubble(
|
||||
suppressBubbleTapFromSpan,
|
||||
onClick = textClickHandler,
|
||||
onLongClick =
|
||||
onLongClick // 🔥
|
||||
// Long
|
||||
// press
|
||||
// для
|
||||
// selection
|
||||
)
|
||||
onLongClick, // 🔥 Long press для selection
|
||||
onViewCreated = { textViewRef = it },
|
||||
onTextLongPress = if (textSelectionHelper != null && !isSelectionMode) { touchX, touchY ->
|
||||
val info = textViewRef?.getLayoutInfo()
|
||||
if (info != null) {
|
||||
textSelectionHelper.startSelection(
|
||||
messageId = message.id,
|
||||
info = info,
|
||||
touchX = touchX,
|
||||
touchY = touchY,
|
||||
view = textViewRef
|
||||
)
|
||||
}
|
||||
} else null
|
||||
)
|
||||
},
|
||||
timeContent = {
|
||||
Row(
|
||||
@@ -1261,11 +1285,20 @@ fun MessageBubble(
|
||||
suppressBubbleTapFromSpan,
|
||||
onClick = textClickHandler,
|
||||
onLongClick =
|
||||
onLongClick // 🔥
|
||||
// Long
|
||||
// press
|
||||
// для
|
||||
// selection
|
||||
onLongClick, // 🔥 Long press для selection
|
||||
onViewCreated = { textViewRef = it },
|
||||
onTextLongPress = if (textSelectionHelper != null && !isSelectionMode) { touchX, touchY ->
|
||||
val info = textViewRef?.getLayoutInfo()
|
||||
if (info != null) {
|
||||
textSelectionHelper.startSelection(
|
||||
messageId = message.id,
|
||||
info = info,
|
||||
touchX = touchX,
|
||||
touchY = touchY,
|
||||
view = textViewRef
|
||||
)
|
||||
}
|
||||
} else null
|
||||
)
|
||||
},
|
||||
timeContent = {
|
||||
|
||||
Reference in New Issue
Block a user