feat: Enhance search functionality and user experience
- Added local account metadata handling in SearchScreen for improved "Saved Messages" search fallback. - Updated search logic to include username and account name checks when searching for the user. - Introduced search logging in SearchUsersViewModel for better debugging and tracking of search queries. - Refactored image download process in AttachmentComponents to include detailed logging for debugging. - Created AttachmentDownloadDebugLogger to manage and display download logs. - Improved DeviceVerificationBanner UI for better user engagement during device verification. - Adjusted OtherProfileScreen layout to enhance information visibility and user interaction. - Updated network security configuration to include new Let's Encrypt certificate for CDN.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package com.rosetta.messenger.data
|
||||
|
||||
private const val PLACEHOLDER_ACCOUNT_NAME = "Account"
|
||||
|
||||
fun resolveAccountDisplayName(publicKey: String, name: String?, username: String?): String {
|
||||
val normalizedName = name?.trim().orEmpty()
|
||||
if (normalizedName.isNotEmpty() && !normalizedName.equals(PLACEHOLDER_ACCOUNT_NAME, ignoreCase = true)) {
|
||||
return normalizedName
|
||||
}
|
||||
|
||||
val normalizedUsername = username?.trim().orEmpty()
|
||||
if (normalizedUsername.isNotEmpty()) {
|
||||
return normalizedUsername
|
||||
}
|
||||
|
||||
if (publicKey.isBlank()) {
|
||||
return PLACEHOLDER_ACCOUNT_NAME
|
||||
}
|
||||
|
||||
return if (publicKey.length > 12) {
|
||||
"${publicKey.take(6)}...${publicKey.takeLast(4)}"
|
||||
} else {
|
||||
publicKey
|
||||
}
|
||||
}
|
||||
|
||||
fun isPlaceholderAccountName(name: String?): Boolean =
|
||||
name?.trim().orEmpty().equals(PLACEHOLDER_ACCOUNT_NAME, ignoreCase = true)
|
||||
@@ -612,6 +612,13 @@ class MessageRepository private constructor(private val context: Context) {
|
||||
// 🔒 Шифруем plainMessage с использованием приватного ключа
|
||||
val encryptedPlainMessage = CryptoManager.encryptWithPassword(plainText, privateKey)
|
||||
|
||||
val storedChachaKey =
|
||||
if (isOwnMessage && packet.aesChachaKey.isNotBlank()) {
|
||||
"sync:${packet.aesChachaKey}"
|
||||
} else {
|
||||
packet.chachaKey
|
||||
}
|
||||
|
||||
// Создаем entity для кэша и возможной вставки
|
||||
val entity =
|
||||
MessageEntity(
|
||||
@@ -620,7 +627,7 @@ class MessageRepository private constructor(private val context: Context) {
|
||||
toPublicKey = packet.toPublicKey,
|
||||
content = packet.content,
|
||||
timestamp = packet.timestamp,
|
||||
chachaKey = packet.chachaKey,
|
||||
chachaKey = storedChachaKey,
|
||||
read = 0,
|
||||
fromMe = if (isOwnMessage) 1 else 0,
|
||||
delivered = DeliveryStatus.DELIVERED.value,
|
||||
@@ -711,27 +718,37 @@ class MessageRepository private constructor(private val context: Context) {
|
||||
*/
|
||||
suspend fun handleRead(packet: PacketRead) {
|
||||
val account = currentAccount ?: return
|
||||
val fromPublicKey = packet.fromPublicKey.trim()
|
||||
val toPublicKey = packet.toPublicKey.trim()
|
||||
if (fromPublicKey.isBlank() || toPublicKey.isBlank()) return
|
||||
|
||||
MessageLogger.debug("👁 READ PACKET from: ${packet.fromPublicKey.take(16)}...")
|
||||
MessageLogger.debug("👁 READ PACKET from=${fromPublicKey.take(16)}..., to=${toPublicKey.take(16)}...")
|
||||
|
||||
// Синхронизация read может прийти как:
|
||||
// 1) from=opponent, to=account (обычный read от собеседника)
|
||||
// 2) from=account, to=opponent (read c другого устройства этого же аккаунта)
|
||||
val opponentKey =
|
||||
if (packet.fromPublicKey == account) packet.toPublicKey else packet.fromPublicKey
|
||||
// Desktop parity:
|
||||
// 1) from=opponent, to=account -> собеседник прочитал НАШИ сообщения (double check)
|
||||
// 2) from=account, to=opponent -> sync с другого нашего устройства (мы прочитали входящие)
|
||||
val isOwnReadSync = fromPublicKey == account
|
||||
val opponentKey = if (isOwnReadSync) toPublicKey else fromPublicKey
|
||||
if (opponentKey.isBlank()) return
|
||||
|
||||
// Проверяем последнее сообщение ДО обновления
|
||||
val lastMsgBefore = messageDao.getLastMessageDebug(account, opponentKey)
|
||||
val dialogKey = getDialogKey(opponentKey)
|
||||
|
||||
// Отмечаем все наши исходящие сообщения к этому собеседнику как прочитанные
|
||||
if (isOwnReadSync) {
|
||||
// Sync read from another own device: mark incoming messages as read.
|
||||
messageDao.markDialogAsRead(account, dialogKey)
|
||||
messageCache[dialogKey]?.let { flow ->
|
||||
flow.value =
|
||||
flow.value.map { msg ->
|
||||
if (!msg.isFromMe && !msg.isRead) msg.copy(isRead = true) else msg
|
||||
}
|
||||
}
|
||||
dialogDao.updateDialogFromMessages(account, opponentKey)
|
||||
return
|
||||
}
|
||||
|
||||
// Opponent read our outgoing messages.
|
||||
messageDao.markAllAsRead(account, opponentKey)
|
||||
|
||||
// 🔥 DEBUG: Проверяем последнее сообщение ПОСЛЕ обновления
|
||||
val lastMsgAfter = messageDao.getLastMessageDebug(account, opponentKey)
|
||||
|
||||
// Обновляем кэш - все исходящие сообщения помечаем как прочитанные
|
||||
val dialogKey = getDialogKey(opponentKey)
|
||||
val readCount = messageCache[dialogKey]?.value?.count { it.isFromMe && !it.isRead } ?: 0
|
||||
messageCache[dialogKey]?.let { flow ->
|
||||
flow.value =
|
||||
@@ -740,17 +757,11 @@ class MessageRepository private constructor(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// 🔔 Уведомляем UI о прочтении (пустой messageId = все исходящие сообщения)
|
||||
// Notify current dialog UI: all outgoing messages are now read.
|
||||
_deliveryStatusEvents.tryEmit(DeliveryStatusUpdate(dialogKey, "", DeliveryStatus.READ))
|
||||
|
||||
// 📝 LOG: Статус прочтения
|
||||
MessageLogger.logReadStatus(fromPublicKey = opponentKey, messagesCount = readCount)
|
||||
|
||||
// 🔥 КРИТИЧНО: Обновляем диалог чтобы lastMessageRead обновился
|
||||
dialogDao.updateDialogFromMessages(account, opponentKey)
|
||||
|
||||
// Логируем что записалось в диалог
|
||||
val dialog = dialogDao.getDialog(account, opponentKey)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user