@@ -126,15 +126,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Входящие сообщения
ProtocolManager . waitPacket ( 0x06 ) { packet ->
val msgPacket = packet as PacketMessage
ProtocolManager . addLog ( " 📨 ChatVM got packet 0x06: from= ${msgPacket.fromPublicKey.take(16)} , to= ${msgPacket.toPublicKey.take(16)} " )
ProtocolManager . addLog ( " 📨 opponentKey= ${opponentKey?.take(16) ?: "NULL"} " )
if ( msgPacket . fromPublicKey == opponentKey || msgPacket . toPublicKey == opponentKey ) {
ProtocolManager . addLog ( " 📨 ✅ Match! Processing message... " )
viewModelScope . launch {
viewModelScope . launch ( Dispatchers . IO ) {
handleIncomingMessage ( msgPacket )
}
} else {
ProtocolManager . addLog ( " 📨 ❌ No match, ignoring " )
}
}
@@ -148,7 +144,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
withContext ( Dispatchers . Main ) {
updateMessageStatus ( deliveryPacket . messageId , MessageStatus . DELIVERED )
}
ProtocolManager . addLog ( " ✓ Delivered: ${deliveryPacket.messageId.take(8)} ... " )
}
}
@@ -172,7 +167,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
} else msg
}
}
ProtocolManager . addLog ( " ✓✓ Read receipt from: ${readPacket.fromPublicKey.take(8)} ... " )
}
}
}
@@ -180,30 +174,20 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Typing
ProtocolManager . waitPacket ( 0x0B ) { packet ->
val typingPacket = packet as PacketTyping
ProtocolManager . addLog ( " ⌨️ TYPING received from: ${typingPacket.fromPublicKey.take(16)} ... " )
ProtocolManager . addLog ( " My opponent: ${opponentKey?.take(16)} ... " )
if ( typingPacket . fromPublicKey == opponentKey ) {
ProtocolManager . addLog ( " ✅ Match! Showing typing indicator " )
showTypingIndicator ( )
} else {
ProtocolManager . addLog ( " ❌ No match, ignoring " )
}
}
// 🟢 Онлайн статус (массив publicKey+state как в React Native)
ProtocolManager . waitPacket ( 0x05 ) { packet ->
val onlinePacket = packet as PacketOnlineState
ProtocolManager . addLog ( " 🟢 ONLINE STATUS received: ${onlinePacket.publicKeysState.size} entries " )
onlinePacket . publicKeysState . forEach { item ->
ProtocolManager . addLog ( " Key: ${item.publicKey.take(16)} ... State: ${item.state} " )
ProtocolManager . addLog ( " My opponent: ${opponentKey?.take(16)} ... " )
if ( item . publicKey == opponentKey ) {
ProtocolManager . addLog ( " ✅ Match! Updating UI - online: ${item.state == OnlineState. ONLINE} " )
viewModelScope . launch {
_opponentOnline . value = item . state == OnlineState . ONLINE
}
_opponentOnline . value = item . state == OnlineState. ONLINE
}
}
}
@@ -216,8 +200,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
val privateKey = myPrivateKey ?: return @launch
val account = myPublicKey ?: return @launch
ProtocolManager . addLog ( " 📩 Incoming message: ${packet.messageId.take(8)} ... " )
ProtocolManager . addLog ( " 📎 Attachments count: ${packet.attachments.size} " )
// Расшифровываем в фоне - получаем и текст и plainKeyAndNonce
val decryptResult = MessageCrypto . decryptIncomingFull (
@@ -231,14 +213,12 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Кэшируем расшифрованный текст
decryptionCache [ packet . messageId ] = decryptedText
ProtocolManager . addLog ( " ✅ Decrypted: ${decryptedText.take(20)} ... " )
// 🔥 Парсим reply из attachments (как в React Native)
var replyData : ReplyData ? = null
val attachmentsJson = if ( packet . attachments . isNotEmpty ( ) ) {
val jsonArray = JSONArray ( )
for ( att in packet . attachments ) {
ProtocolManager . addLog ( " 📎 Attachment type: ${att.type} , blob size: ${att.blob.length} " )
// Если это MESSAGES (reply) - парсим и расшифровываем данные
var blobToStore = att . blob // По умолчанию сохраняем оригинальный blob
@@ -246,7 +226,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
try {
// 🔥 Сначала расшифровываем blob (он зашифрован!)
val decryptedBlob = MessageCrypto . decryptReplyBlob ( att . blob , plainKeyAndNonce )
ProtocolManager . addLog ( " 📎 Decrypted reply blob: ${decryptedBlob.take(100)} " )
// 🔥 Сохраняем расшифрованный blob в БД
blobToStore = decryptedBlob
@@ -268,10 +247,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
text = replyText ,
isFromMe = isReplyFromMe
)
ProtocolManager . addLog ( " ✅ Parsed reply: from= ${replyData?.senderName} , text= ${replyText.take(30)} " )
}
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Failed to parse reply: ${e.message} " )
}
}
@@ -297,7 +274,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
)
// Просто добавляем как в архиве: setMessages((prev) => ([...prev, newMessage]))
_messages . value = _messages . value + message
ProtocolManager . addLog ( " ✅ Added to UI: ${packet.messageId.take(8)} ... text: ${decryptedText.take(20)} " )
}
// 🔥 Сохраняем в БД здесь (в ChatViewModel)
@@ -308,7 +284,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// 🔥 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
@@ -334,7 +309,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// (через markVisibleMessagesAsRead вызываемый из ChatDetailScreen)
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Error handling incoming message: ${e.message} " )
Log . e ( TAG , " Incoming message error " , e )
}
}
@@ -364,7 +338,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
fun setUserKeys ( publicKey : String , privateKey : String ) {
myPublicKey = publicKey
myPrivateKey = privateKey
ProtocolManager . addLog ( " 🔑 Keys set: ${publicKey.take(16)} ... " )
}
/**
@@ -373,7 +346,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
fun openDialog ( publicKey : String , title : String = " " , username : String = " " ) {
// 🔥 ВСЕГДА перезагружаем данные - не кешируем, т.к. диалог мог быть удалён
// if (opponentKey == publicKey) {
// ProtocolManager.addLog("💬 Dialog already open: ${publicKey.take(16)}...")
// return
// }
@@ -395,7 +367,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
readReceiptSentForCurrentDialog = false
isDialogActive = true // 🔥 Диалог активен!
ProtocolManager . addLog ( " 💬 Dialog opened: ${title.ifEmpty { publicKey.take(16) } }... " )
// Подписываемся на онлайн статус
subscribeToOnlineStatus ( )
@@ -411,7 +382,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
*/
fun closeDialog ( ) {
isDialogActive = false
ProtocolManager . addLog ( " 💬 Dialog closed (isDialogActive = false) " )
}
/**
@@ -431,7 +401,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// 🔥 МГНОВЕННАЯ загрузка из кэша если есть!
val cachedMessages = dialogMessagesCache [ dialogKey ]
if ( cachedMessages != null && cachedMessages . isNotEmpty ( ) ) {
ProtocolManager . addLog ( " ⚡ Loading ${cachedMessages.size} messages from CACHE (instant!) " )
withContext ( Dispatchers . Main . immediate ) {
_messages . value = cachedMessages
_isLoading . value = false
@@ -452,16 +421,13 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
delay ( delayMs )
}
ProtocolManager . addLog ( " 📂 Loading messages from DB for dialog: $dialogKey " )
// 🔍 Проверяем общее количество сообщений в диалоге
val totalCount = messageDao . getMessageCount ( account , dialogKey )
ProtocolManager . addLog ( " 📂 Total messages in DB: $totalCount " )
// 🔥 Получаем первую страницу - БЕЗ suspend задержки
val entities = messageDao . getMessages ( account , dialogKey , limit = PAGE _SIZE , offset = 0 )
ProtocolManager . addLog ( " 📂 Loaded ${entities.size} messages from DB (offset: 0, limit: $PAGE _SIZE) " )
hasMoreMessages = entities . size >= PAGE _SIZE
currentOffset = entities . size
@@ -480,11 +446,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
}
ProtocolManager . addLog ( " 📋 Decrypted and loaded ${messages.size} messages from DB " )
// 🔥 Сохраняем в кэш для мгновенной повторной загрузки!
dialogMessagesCache [ dialogKey ] = messages . toList ( )
ProtocolManager . addLog ( " 💾 Cached ${messages.size} messages for dialog $dialogKey " )
// 🔥 С Р А З У обновляем UI - пользователь видит сообщения мгновенно
// Н О сохраняем оптимистичные сообщения (SENDING), которые ещё не в БД
@@ -501,7 +465,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Отмечаем как прочитанные в БД
messageDao . markDialogAsRead ( account , dialogKey )
dialogDao . clearUnreadCount ( account , opponent )
ProtocolManager . addLog ( " 👁️ Marked all incoming messages as read in DB, cleared unread count " )
// Отправляем read receipt собеседнику
if ( messages . isNotEmpty ( ) ) {
@@ -515,7 +478,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
isLoadingMessages = false
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Error loading messages: ${e.message} " )
Log . e ( TAG , " Error loading messages " , e )
withContext ( Dispatchers . Main . immediate ) {
_isLoading . value = false
@@ -550,7 +512,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
withContext ( Dispatchers . Main . immediate ) {
_messages . value = messages
}
ProtocolManager . addLog ( " 🔄 Refreshed: found ${messages.size - cachedMessages.size} new messages " )
}
hasMoreMessages = entities . size >= PAGE _SIZE
@@ -561,7 +522,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
dialogDao . clearUnreadCount ( account , opponent )
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Error refreshing messages: ${e.message} " )
}
}
@@ -639,7 +599,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
encryptedKey = entity . chachaKey ,
myPrivateKey = privateKey
)
ProtocolManager . addLog ( " 🔓 Decrypted from DB: ${decrypted.take(20)} ... " )
decrypted
} else {
// Fallback на расшифровку plainMessage с приватным ключом
@@ -647,7 +606,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
try {
CryptoManager . decryptWithPassword ( entity . plainMessage , privateKey ) ?: entity . plainMessage
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ⚠️ plainMessage decrypt error: ${e.message} " )
entity . plainMessage
}
} else {
@@ -655,7 +613,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
}
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Decrypt error: ${e.message} , trying plainMessage " )
// Пробуем расшифровать plainMessage
val privateKey = myPrivateKey
if ( privateKey != null && entity . plainMessage . isNotEmpty ( ) ) {
@@ -806,7 +763,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
)
}
_isForwardMode . value = false
ProtocolManager . addLog ( " 📝 Reply set: ${messages.size} messages " )
}
/**
@@ -826,7 +782,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
)
}
_isForwardMode . value = true
ProtocolManager . addLog ( " ➡️ Forward set: ${messages.size} messages " )
}
/**
@@ -841,16 +796,13 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
* 🔥 Удалить сообщение (для ошибки отправки)
*/
fun deleteMessage ( messageId : String ) {
viewModelScope . launch {
// Удаляем из UI
_messages . value = _messages . value . filter { it . id != messageId }
// Удаляем из БД
// Удаляем из UI сразу на main
_messages . value = _messages . value . filter { it . id != messageId }
// Удаляем из БД в IO
viewModelScope . launch ( Dispatchers . IO ) {
val account = myPublicKey ?: return @launch
withContext ( Dispatchers . IO ) {
messageDao . deleteMessage ( account , messageId )
}
ProtocolManager . addLog ( " 🗑️ Message deleted: ${messageId.take(8)} ... " )
messageDao . deleteMessage ( account , messageId )
}
}
@@ -858,17 +810,16 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
* 🔥 Повторить отправку сообщения (для ошибки)
*/
fun retryMessage ( message : ChatMessage ) {
// Удаляем старое сообщение
deleteMessage ( message . id )
// Устанавливаем текст в инпут и отправляем
_inputText . value = message . text
// Отправляем с небольшой задержкой
viewModelScope . launch {
// Удаляем старое сообщение
deleteMessage ( message . id )
// Устанавливаем текст в инпут и отправляем
_inputText . value = message . text
// Небольшая задержка чтобы UI обновился
delay ( 100 )
sendMessage ( )
ProtocolManager . addLog ( " 🔄 Retrying message: ${message.text.take(20)} ... " )
}
}
@@ -881,7 +832,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
*/
fun sendMessage ( ) {
Log . d ( TAG , " 🚀🚀🚀 sendMessage() CALLED 🚀🚀🚀 " )
ProtocolManager . addLog ( " 🚀🚀🚀 sendMessage() CALLED " )
val text = _inputText . value . trim ( )
val recipient = opponentKey
@@ -896,35 +846,26 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
Log . d ( TAG , " 🔑 PrivateKey exists: ${privateKey != null} " )
Log . d ( TAG , " 💬 ReplyMsgs: ${replyMsgs.size} " )
ProtocolManager . addLog ( " 📝 Text: ' $text ' " )
ProtocolManager . addLog ( " 📧 Recipient: ${recipient?.take(16)} " )
ProtocolManager . addLog ( " 👤 Sender: ${sender?.take(16)} " )
ProtocolManager . addLog ( " 🔑 PrivateKey exists: ${privateKey != null} " )
// Разрешаем отправку пустого текста если есть reply/forward
if ( text . isEmpty ( ) && replyMsgs . isEmpty ( ) ) {
Log . e ( TAG , " ❌ Empty text and no reply " )
ProtocolManager . addLog ( " ❌ Empty text and no reply " )
return
}
if ( recipient == null ) {
Log . e ( TAG , " ❌ No recipient " )
ProtocolManager . addLog ( " ❌ No recipient " )
return
}
if ( sender == null || privateKey == null ) {
Log . e ( TAG , " ❌ No keys - sender: $sender , privateKey: $privateKey " )
ProtocolManager . addLog ( " ❌ No keys - set via setUserKeys() " )
return
}
if ( isSending ) {
Log . w ( TAG , " ⏳ Already sending... " )
ProtocolManager . addLog ( " ⏳ Already sending... " )
return
}
Log . d ( TAG , " ✅ All checks passed, starting send... " )
ProtocolManager . addLog ( " ✅ All checks passed, starting send... " )
isSending = true
@@ -964,7 +905,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Кэшируем текст
decryptionCache [ messageId ] = text
ProtocolManager . addLog ( " 📤 Sending: \" ${text.take(20)} ... \" with ${replyMsgsToSend.size} reply attachments " )
// 2. 🔥 Шифрование и отправка в IO потоке
viewModelScope . launch ( Dispatchers . IO ) {
@@ -1007,8 +947,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
preview = " "
) )
ProtocolManager . addLog ( " 📎 Reply attachment created: ${replyBlobPlaintext.take(50)} ... " )
ProtocolManager . addLog ( " 📎 Encrypted reply blob: ${encryptedReplyBlob.take(50)} ... " )
}
val packet = PacketMessage ( ) . apply {
@@ -1023,10 +961,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
// 🔥 Log packet details before sending
ProtocolManager . addLog ( " 📤📤📤 SENDING PACKET 📤📤📤 " )
ProtocolManager . addLog ( " - Attachments count: ${packet.attachments.size} " )
packet . attachments . forEach { att ->
ProtocolManager . addLog ( " - Attachment: type= ${att.type} , id= ${att.id} , blob= ${att.blob.take(50)} ... " )
}
// Отправляем пакет
@@ -1089,13 +1024,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// 🔒 Шифруем lastMessage перед сохранением
val encryptedLastMessage = CryptoManager . encryptWithPassword ( lastMessage , privateKey )
ProtocolManager . addLog ( " 💾 Saving dialog: ${lastMessage.take(20)} ... (encrypted) " )
val existingDialog = dialogDao . getDialog ( account , opponent )
if ( existingDialog != null ) {
// Обновляем последнее сообщение
dialogDao . updateLastMessage ( account , opponent , encryptedLastMessage , timestamp )
ProtocolManager . addLog ( " ✅ Dialog updated (existing) " )
} else {
// Создаём новый диалог
dialogDao . insertDialog ( DialogEntity (
@@ -1106,10 +1039,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
lastMessage = encryptedLastMessage ,
lastMessageTimestamp = timestamp
) )
ProtocolManager . addLog ( " ✅ Dialog created (new) " )
}
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Dialog save error: ${e.message} " )
Log . e ( TAG , " Dialog save error " , e )
}
}
@@ -1134,9 +1065,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Инкрементируем непрочитанные если нужно
if ( incrementUnread ) {
dialogDao . incrementUnreadCount ( account , opponentKey )
ProtocolManager . addLog ( " 📬 Unread incremented for: ${opponentKey.take(16)} ... " )
}
ProtocolManager . addLog ( " ✅ Dialog updated: ${lastMessage.take(20)} ... " )
} else {
// Создаём новый диалог
dialogDao . insertDialog ( DialogEntity (
@@ -1148,10 +1077,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
lastMessageTimestamp = timestamp ,
unreadCount = if ( incrementUnread ) 1 else 0
) )
ProtocolManager . addLog ( " ✅ Dialog created (new) " )
}
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ updateDialog error: ${e.message} " )
Log . e ( TAG , " updateDialog error " , e )
}
}
@@ -1183,7 +1110,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// 🔒 Проверяем 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
@@ -1194,11 +1120,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Проверяем существует ли сообщение
val exists = messageDao . messageExists ( account , finalMessageId )
ProtocolManager . addLog ( " 💾 Saving message to DB: " )
ProtocolManager . addLog ( " messageId: $finalMessageId " )
ProtocolManager . addLog ( " exists in DB: $exists " )
ProtocolManager . addLog ( " dialogKey: $dialogKey " )
ProtocolManager . addLog ( " text: ${text.take(20)} ... " )
val entity = MessageEntity (
account = account ,
@@ -1218,17 +1139,15 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
)
val insertedId = messageDao . insertMessage ( entity )
ProtocolManager . addLog ( " ✅ Message saved with DB id: $insertedId " )
} catch ( e : Exception ) {
ProtocolManager . addLog ( " ❌ Message save error: ${e.message} " )
Log . e ( TAG , " Message save error " , e )
}
}
private fun showTypingIndicator ( ) {
_opponentTyping . value = true
viewModelScope . launch {
viewModelScope . launch ( Dispatchers . Default ) {
kotlinx . coroutines . delay ( 3000 )
_opponentTyping . value = false
}
@@ -1243,15 +1162,12 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
if ( now - lastTypingSentTime < TYPING _THROTTLE _MS ) return
val opponent = opponentKey ?: run {
ProtocolManager . addLog ( " ❌ Typing: No opponent key " )
return
}
val sender = myPublicKey ?: run {
ProtocolManager . addLog ( " ❌ Typing: No sender key " )
return
}
val privateKey = myPrivateKey ?: run {
ProtocolManager . addLog ( " ❌ Typing: No private key " )
return
}
@@ -1261,10 +1177,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
try {
val privateKeyHash = CryptoManager . generatePrivateKeyHash ( privateKey )
ProtocolManager . addLog ( " ⌨️ Sending typing... " )
ProtocolManager . addLog ( " From: ${sender.take(16)} ... " )
ProtocolManager . addLog ( " To: ${opponent.take(16)} ... " )
ProtocolManager . addLog ( " PrivateHash: ${privateKeyHash.take(16)} ... " )
val packet = PacketTyping ( ) . apply {
this . privateKey = privateKeyHash
@@ -1273,10 +1185,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
ProtocolManager . send ( packet )
ProtocolManager . addLog ( " ⌨️ Typing indicator sent ✅ " )
} catch ( e : Exception ) {
Log . e ( TAG , " Typing send error " , e )
ProtocolManager . addLog ( " ❌ Typing send error: ${e.message} " )
}
}
}
@@ -1289,7 +1199,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
private fun sendReadReceiptToOpponent ( ) {
// 🔥 Н е отправляем read receipt если диалог не активен (как в архиве)
if ( !is DialogActive ) {
ProtocolManager . addLog ( " 👁️ Read receipt skipped - dialog not active " )
return
}
@@ -1315,7 +1224,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
ProtocolManager . send ( packet )
ProtocolManager . addLog ( " 👁️ Read receipt sent to: ${opponent.take(8)} ... " )
readReceiptSentForCurrentDialog = true
} catch ( e : Exception ) {
Log . e ( TAG , " Read receipt send error " , e )
@@ -1330,7 +1238,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
fun markVisibleMessagesAsRead ( ) {
// 🔥 Н е читаем если диалог не активен
if ( !is DialogActive ) {
ProtocolManager . addLog ( " 👁️ markVisibleMessagesAsRead skipped - dialog not active " )
return
}
@@ -1344,7 +1251,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Если timestamp не изменился - не отправляем повторно
if ( lastIncoming . timestamp . time <= lastReadMessageTimestamp ) return
ProtocolManager . addLog ( " 👁️ markVisibleMessagesAsRead: new message detected " )
// Отмечаем в БД и очищаем счетчик непрочитанных
viewModelScope . launch ( Dispatchers . IO ) {
@@ -1352,7 +1258,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
val dialogKey = getDialogKey ( account , opponent )
messageDao . markDialogAsRead ( account , dialogKey )
dialogDao . clearUnreadCount ( account , opponent )
ProtocolManager . addLog ( " 👁️ Marked dialog as read in DB, cleared unread count " )
} catch ( e : Exception ) {
Log . e ( TAG , " Mark as read error " , e )
}
@@ -1379,10 +1284,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
ProtocolManager . send ( packet )
ProtocolManager . addLog ( " 🟢 Subscribed to online status: ${opponent.take(16)} ... " )
} catch ( e : Exception ) {
Log . e ( TAG , " Online subscribe error " , e )
ProtocolManager . addLog ( " ❌ Online subscribe error: ${e.message} " )
}
}
}