feat: Enhance logging in MessageRepository and ChatsListViewModel for better debugging and flow tracking

This commit is contained in:
k1ngsterr1
2026-01-13 23:28:48 +05:00
parent 14ef342e80
commit 2c173bda26
6 changed files with 232 additions and 94 deletions

View File

@@ -464,7 +464,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
launch(Dispatchers.IO) {
// Отмечаем как прочитанные в БД
messageDao.markDialogAsRead(account, dialogKey)
dialogDao.clearUnreadCount(account, opponent)
// 🔥 Пересчитываем счетчики из messages
dialogDao.updateDialogFromMessages(account, opponent)
// Отправляем read receipt собеседнику
if (messages.isNotEmpty()) {
@@ -519,7 +520,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
// Фоновые операции
messageDao.markDialogAsRead(account, dialogKey)
dialogDao.clearUnreadCount(account, opponent)
// 🔥 Пересчитываем счетчики из messages
dialogDao.updateDialogFromMessages(account, opponent)
} catch (e: Exception) {
}
@@ -1013,33 +1015,18 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
/**
* Сохранить диалог в базу данных
* 🔒 lastMessage шифруется для безопасного хранения
* <EFBFBD> Используем updateDialogFromMessages для пересчета счетчиков из messages
*/
private suspend fun saveDialog(lastMessage: String, timestamp: Long) {
val account = myPublicKey ?: return
val opponent = opponentKey ?: return
val privateKey = myPrivateKey ?: return
try {
// 🔒 Шифруем lastMessage перед сохранением
val encryptedLastMessage = CryptoManager.encryptWithPassword(lastMessage, privateKey)
// 🔥 КРИТИЧНО: Используем updateDialogFromMessages который пересчитывает счетчики
// напрямую из таблицы messages, как в Архиве!
dialogDao.updateDialogFromMessages(account, opponent)
val existingDialog = dialogDao.getDialog(account, opponent)
if (existingDialog != null) {
// Обновляем последнее сообщение
dialogDao.updateLastMessage(account, opponent, encryptedLastMessage, timestamp)
} else {
// Создаём новый диалог
dialogDao.insertDialog(DialogEntity(
account = account,
opponentKey = opponent,
opponentTitle = opponentTitle,
opponentUsername = opponentUsername,
lastMessage = encryptedLastMessage,
lastMessageTimestamp = timestamp
))
}
Log.d(TAG, "✅ Dialog saved/updated from messages table")
} catch (e: Exception) {
Log.e(TAG, "Dialog save error", e)
}
@@ -1050,34 +1037,14 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
*/
private suspend fun updateDialog(opponentKey: String, lastMessage: String, timestamp: Long, incrementUnread: Boolean) {
val account = myPublicKey ?: return
val privateKey = myPrivateKey ?: return
try {
// 🔒 Шифруем lastMessage для диалога
val encryptedLastMessage = CryptoManager.encryptWithPassword(lastMessage, privateKey)
// 🔥 КРИТИЧНО: Используем updateDialogFromMessages который пересчитывает счетчики
// напрямую из таблицы messages, как в Архиве!
// Это гарантирует что unread_count всегда соответствует реальному количеству непрочитанных
dialogDao.updateDialogFromMessages(account, opponentKey)
val existingDialog = dialogDao.getDialog(account, opponentKey)
if (existingDialog != null) {
// Обновляем последнее сообщение
dialogDao.updateLastMessage(account, opponentKey, encryptedLastMessage, timestamp)
// Инкрементируем непрочитанные если нужно
if (incrementUnread) {
dialogDao.incrementUnreadCount(account, opponentKey)
}
} else {
// Создаём новый диалог
dialogDao.insertDialog(DialogEntity(
account = account,
opponentKey = opponentKey,
opponentTitle = opponentTitle,
opponentUsername = opponentUsername,
lastMessage = encryptedLastMessage, // 🔒 Зашифрованный
lastMessageTimestamp = timestamp,
unreadCount = if (incrementUnread) 1 else 0
))
}
Log.d(TAG, "✅ Dialog updated from messages table for $opponentKey")
} catch (e: Exception) {
Log.e(TAG, "updateDialog error", e)
}
@@ -1252,12 +1219,13 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
if (lastIncoming.timestamp.time <= lastReadMessageTimestamp) return
// Отмечаем в БД и очищаем счетчик непрочитанных
// Отмечаем в БД и пересчитываем счетчики
viewModelScope.launch(Dispatchers.IO) {
try {
val dialogKey = getDialogKey(account, opponent)
messageDao.markDialogAsRead(account, dialogKey)
dialogDao.clearUnreadCount(account, opponent)
// 🔥 Пересчитываем счетчики из messages
dialogDao.updateDialogFromMessages(account, opponent)
} catch (e: Exception) {
Log.e(TAG, "Mark as read error", e)
}

View File

@@ -54,14 +54,20 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
* Установить текущий аккаунт и загрузить диалоги
*/
fun setAccount(publicKey: String, privateKey: String) {
if (currentAccount == publicKey) return
if (currentAccount == publicKey) {
android.util.Log.d("ChatsListViewModel", "⚠️ setAccount called again for same account, skipping")
return
}
currentAccount = publicKey
currentPrivateKey = privateKey
android.util.Log.d("ChatsListViewModel", "✅ Setting up dialogs Flow for account: ${publicKey.take(16)}...")
viewModelScope.launch {
dialogDao.getDialogsFlow(publicKey)
.flowOn(Dispatchers.IO) // 🚀 Flow работает на IO
.map { dialogsList ->
android.util.Log.d("ChatsListViewModel", "📋 Dialogs Flow emitted: ${dialogsList.size} dialogs")
// 🔓 Расшифровываем lastMessage на IO потоке (PBKDF2 - тяжелая операция!)
dialogsList.map { dialog ->
val decryptedLastMessage = try {
@@ -91,7 +97,9 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
}
}
.flowOn(Dispatchers.Default) // 🚀 map выполняется на Default (CPU)
.flowOn(Dispatchers.Main) // 🎯 КРИТИЧНО: Обновляем UI на главном потоке!
.collect { decryptedDialogs ->
android.util.Log.d("ChatsListViewModel", "✅ Updated UI with ${decryptedDialogs.size} decrypted dialogs")
_dialogs.value = decryptedDialogs
// 🟢 Подписываемся на онлайн-статусы всех собеседников
@@ -125,6 +133,7 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
/**
* Создать или обновить диалог после отправки/получения сообщения
* 🔥 Используем updateDialogFromMessages для пересчета счетчиков из messages
*/
suspend fun upsertDialog(
opponentKey: String,
@@ -136,31 +145,20 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio
isOnline: Int = 0
) {
if (currentAccount.isEmpty()) return
val privateKey = currentPrivateKey ?: return
// 🔒 Шифруем lastMessage перед сохранением
val encryptedLastMessage = CryptoManager.encryptWithPassword(lastMessage, privateKey)
val existingDialog = dialogDao.getDialog(currentAccount, opponentKey)
if (existingDialog != null) {
// Обновляем
dialogDao.updateLastMessage(currentAccount, opponentKey, encryptedLastMessage, timestamp)
try {
// 🔥 КРИТИЧНО: Используем updateDialogFromMessages который пересчитывает счетчики
// напрямую из таблицы messages, как в Архиве!
dialogDao.updateDialogFromMessages(currentAccount, opponentKey)
// Обновляем информацию о собеседнике если есть
if (opponentTitle.isNotEmpty()) {
dialogDao.updateOpponentInfo(currentAccount, opponentKey, opponentTitle, opponentUsername, verified)
}
} else {
// Создаём новый
dialogDao.insertDialog(DialogEntity(
account = currentAccount,
opponentKey = opponentKey,
opponentTitle = opponentTitle,
opponentUsername = opponentUsername,
lastMessage = encryptedLastMessage, // 🔒 Зашифрованный
lastMessageTimestamp = timestamp,
verified = verified,
isOnline = isOnline
))
android.util.Log.d("ChatsListViewModel", "✅ Dialog upserted from messages table")
} catch (e: Exception) {
android.util.Log.e("ChatsListViewModel", "Error upserting dialog", e)
}
}