feat: Implement read receipt handling and mark all outgoing messages as read

This commit is contained in:
k1ngsterr1
2026-01-13 04:10:07 +05:00
parent cdb3d7ab9e
commit e44bed4fa8
5 changed files with 59 additions and 27 deletions

View File

@@ -134,17 +134,28 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
}
}
// Прочитано
// Прочитано - пакет сообщает что собеседник прочитал наши сообщения
// В Desktop нет messageId - просто отмечаем все исходящие сообщения как прочитанные
ProtocolManager.waitPacket(0x07) { packet ->
val readPacket = packet as PacketRead
viewModelScope.launch(Dispatchers.IO) {
// Обновляем в БД
updateMessageStatusInDb(readPacket.messageId, 3) // READ
// Обновляем UI
withContext(Dispatchers.Main) {
updateMessageStatus(readPacket.messageId, MessageStatus.READ)
// Если fromPublicKey == наш собеседник, значит он прочитал наши сообщения
if (readPacket.fromPublicKey == opponentKey) {
// Обновляем все непрочитанные исходящие сообщения в БД
val account = myPublicKey ?: return@launch
val opponent = opponentKey ?: return@launch
messageDao.markAllAsRead(account, opponent)
// Обновляем UI - все исходящие сообщения помечаем как прочитанные
withContext(Dispatchers.Main) {
_messages.value = _messages.value.map { msg ->
if (msg.isOutgoing && msg.status != MessageStatus.READ) {
msg.copy(status = MessageStatus.READ)
} else msg
}
}
ProtocolManager.addLog("✓✓ Read receipt from: ${readPacket.fromPublicKey.take(8)}...")
}
ProtocolManager.addLog("✓✓ Read: ${readPacket.messageId.take(8)}...")
}
}
@@ -762,29 +773,31 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
/**
* 👁️ Отправить подтверждение о прочтении сообщения
* В Desktop PacketRead не содержит messageId - он просто сообщает что мы прочитали сообщения
*/
fun sendReadReceipt(messageId: String, senderPublicKey: String) {
// Не отправляем повторно
if (sentReadReceipts.contains(messageId)) return
// Не отправляем повторно для этого собеседника
val receiptKey = senderPublicKey
if (sentReadReceipts.contains(receiptKey)) return
val sender = myPublicKey ?: return
val privateKey = myPrivateKey ?: return
sentReadReceipts.add(messageId)
sentReadReceipts.add(receiptKey)
viewModelScope.launch(Dispatchers.IO) {
try {
val privateKeyHash = CryptoManager.generatePrivateKeyHash(privateKey)
// Desktop формат: privateKey, fromPublicKey, toPublicKey
val packet = PacketRead().apply {
this.messageId = messageId
fromPublicKey = sender
toPublicKey = senderPublicKey
this.privateKey = privateKeyHash
fromPublicKey = sender // Мы (кто прочитал)
toPublicKey = senderPublicKey // Кому отправляем уведомление
}
ProtocolManager.send(packet)
ProtocolManager.addLog("👁️ Read receipt sent for: ${messageId.take(8)}...")
ProtocolManager.addLog("👁️ Read receipt sent to: ${senderPublicKey.take(8)}...")
// Обновляем в БД что сообщение прочитано
updateMessageReadInDb(messageId)