diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatViewModel.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatViewModel.kt index a3da90f..6499560 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatViewModel.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatViewModel.kt @@ -300,8 +300,18 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { // ProtocolManager.setupPacketHandlers() не вызывается, поэтому сохраняем сами // Используем fromPublicKey как opponent для корректного dialogKey val senderKey = packet.fromPublicKey + + // 🔥 FIX: Если messageId пустой - генерируем новый UUID + val finalMessageId = if (packet.messageId.isNullOrEmpty()) { + UUID.randomUUID().toString().replace("-", "").take(32).also { + ProtocolManager.addLog("⚠️ Empty messageId from server, generated: ${it.take(8)}...") + } + } else { + packet.messageId + } + saveMessageToDatabase( - messageId = packet.messageId, + messageId = finalMessageId, text = decryptedText, encryptedContent = packet.content, encryptedKey = packet.chachaKey, @@ -441,8 +451,12 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { ProtocolManager.addLog("📋 Decrypted and loaded ${messages.size} messages from DB") // 🔥 СРАЗУ обновляем UI - пользователь видит сообщения мгновенно + // НО сохраняем оптимистичные сообщения (SENDING), которые ещё не в БД withContext(Dispatchers.Main.immediate) { - _messages.value = messages + val optimisticMessages = _messages.value.filter { msg -> + msg.status == MessageStatus.SENDING && messages.none { it.id == msg.id } + } + _messages.value = messages + optimisticMessages _isLoading.value = false } @@ -1080,13 +1094,22 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { try { val dialogKey = getDialogKey(account, opponent) + // 🔒 Проверяем messageId - если пустой, генерируем новый + val finalMessageId = if (messageId.isEmpty()) { + val generated = UUID.randomUUID().toString().replace("-", "").take(32) + ProtocolManager.addLog("⚠️ Empty messageId detected, generated new: $generated") + generated + } else { + messageId + } + // 🔒 Шифруем plainMessage с использованием приватного ключа val encryptedPlainMessage = CryptoManager.encryptWithPassword(text, privateKey) // Проверяем существует ли сообщение - val exists = messageDao.messageExists(account, messageId) + val exists = messageDao.messageExists(account, finalMessageId) ProtocolManager.addLog("💾 Saving message to DB:") - ProtocolManager.addLog(" messageId: $messageId") + ProtocolManager.addLog(" messageId: $finalMessageId") ProtocolManager.addLog(" exists in DB: $exists") ProtocolManager.addLog(" dialogKey: $dialogKey") ProtocolManager.addLog(" text: ${text.take(20)}...") @@ -1101,7 +1124,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { read = if (isFromMe) 1 else 0, fromMe = if (isFromMe) 1 else 0, delivered = delivered, - messageId = messageId, + messageId = finalMessageId, plainMessage = encryptedPlainMessage, // 🔒 Зашифрованный текст для хранения в БД attachments = attachmentsJson, replyToMessageId = null,