feat: Optimize emoji picker performance by eliminating chunk loading, reducing animations, and improving emoji caching

This commit is contained in:
k1ngsterr1
2026-01-15 01:24:33 +05:00
parent 05fc6f61b7
commit 65094125f6
5 changed files with 300 additions and 102 deletions

View File

@@ -262,13 +262,8 @@ fun ChatDetailScreen(
// 🔥 Флаг видимости панели эмодзи (тот же что в MessageInputBar) - единый источник правды
val isEmojiPanelVisible = showEmojiPicker && !isKeyboardVisible
// 🔥 Анимированный отступ для списка сообщений когда emoji picker открыт
// Используем isEmojiPanelVisible для синхронизации с анимацией панели
val emojiPanelPadding by animateDpAsState(
targetValue = if (isEmojiPanelVisible) emojiPanelHeight else 0.dp,
animationSpec = tween(100, easing = FastOutSlowInEasing), // 100ms как exit анимация панели
label = "emojiPanelPadding"
)
// <EFBFBD> Простой отступ без анимации - AnimatedVisibility сама анимирует
val emojiPanelPadding = if (isEmojiPanelVisible) emojiPanelHeight else 0.dp
// 🔥 Reply/Forward state
val replyMessages by viewModel.replyMessages.collectAsState()
@@ -2322,11 +2317,11 @@ private fun MessageInputBar(
visible = showPanel,
enter = slideInVertically(
initialOffsetY = { it }, // Снизу вверх
animationSpec = tween(100, easing = FastOutSlowInEasing)
animationSpec = tween(150, easing = FastOutSlowInEasing) // 🚀 Быстрее и плавнее
),
exit = slideOutVertically(
targetOffsetY = { it }, // Сверху вниз
animationSpec = tween(100, easing = FastOutSlowInEasing) // 🔥 Синхронизировано с padding анимацией
animationSpec = tween(150, easing = FastOutSlowInEasing)
)
) {
AppleEmojiPickerPanel(

View File

@@ -280,32 +280,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
_messages.value = _messages.value + message
}
// 🔥 Сохраняем в БД здесь (в ChatViewModel)
// ProtocolManager.setupPacketHandlers() не вызывается, поэтому сохраняем сами
// Используем fromPublicKey как opponent для корректного dialogKey
// НЕ сохраняем в БД здесь - это делает MessageRepository.handleIncomingMessage()!
// Убираем дублирование: одно сообщение не должно сохраняться дважды
// 🔥 Обновляем диалог - используем fromPublicKey
val senderKey = packet.fromPublicKey
// 🔥 FIX: Если messageId пустой - генерируем новый UUID
val finalMessageId = if (packet.messageId.isNullOrEmpty()) {
UUID.randomUUID().toString().replace("-", "").take(32).also {
}
} else {
packet.messageId
}
saveMessageToDatabase(
messageId = finalMessageId,
text = decryptedText,
encryptedContent = packet.content,
encryptedKey = packet.chachaKey,
timestamp = packet.timestamp,
isFromMe = false, // Это входящее сообщение
delivered = DeliveryStatus.DELIVERED.value,
attachmentsJson = attachmentsJson,
opponentPublicKey = senderKey
)
// 🔥 Обновляем диалог - используем senderKey
updateDialog(senderKey, decryptedText, packet.timestamp, incrementUnread = !isDialogActive)
// 👁️ НЕ отправляем read receipt автоматически!
@@ -1059,8 +1038,12 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// 🔒 Шифруем plainMessage с использованием приватного ключа
val encryptedPlainMessage = CryptoManager.encryptWithPassword(text, privateKey)
// Проверяем существует ли сообщение
// Проверяем существует ли сообщение - ИСПОЛЬЗУЕМ результат!
val exists = messageDao.messageExists(account, finalMessageId)
if (exists) {
// Сообщение уже есть в БД - не дублируем
return
}
val entity = MessageEntity(
account = account,