diff --git a/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt b/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt index 74e33bc..eaa0b2e 100644 --- a/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt +++ b/app/src/main/java/app/rosette/android/ui/keyboard/AnimatedKeyboardTransition.kt @@ -15,7 +15,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.unit.dp -import android.util.Log import kotlinx.coroutines.delay /** @@ -94,7 +93,6 @@ fun AnimatedKeyboardTransition( if (shouldLog && lastLoggedAlpha.value != animatedAlpha) { lastLoggedAlpha.value = animatedAlpha - Log.d(tag, "🎬 Alpha: ${alphaPercent}%, show=$showEmojiPicker, shouldShow=$shouldShowBox, transitioning=$isTransitioningToKeyboard, kb=${coordinator.keyboardHeight.value.toInt()}dp") } if (shouldShowBox) { diff --git a/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt b/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt index ffa12af..12f9ef8 100644 --- a/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt +++ b/app/src/main/java/app/rosette/android/ui/keyboard/KeyboardTransitionCoordinator.kt @@ -2,7 +2,6 @@ package app.rosette.android.ui.keyboard import android.os.Handler import android.os.Looper -import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf @@ -95,10 +94,8 @@ class KeyboardTransitionCoordinator { isEmojiVisible = true // 🔥 ВАЖНО: Устанавливаем флаг видимости emoji! // Теперь скрываем клавиатуру (она будет закрываться синхронно с появлением emoji) - Log.d(TAG, " ⌨️ Hiding keyboard...") try { hideKeyboard() - Log.d(TAG, " ✅ hideKeyboard() completed") } catch (e: Exception) {} isKeyboardVisible = false diff --git a/app/src/main/java/com/rosetta/messenger/MainActivity.kt b/app/src/main/java/com/rosetta/messenger/MainActivity.kt index 2e2cbcd..98fa160 100644 --- a/app/src/main/java/com/rosetta/messenger/MainActivity.kt +++ b/app/src/main/java/com/rosetta/messenger/MainActivity.kt @@ -4,7 +4,6 @@ import android.Manifest import android.content.pm.PackageManager import android.os.Build import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent @@ -77,7 +76,6 @@ class MainActivity : FragmentActivity() { if (_fcmLogs.size > 20) { _fcmLogs.removeAt(_fcmLogs.size - 1) } - Log.d(TAG, "FCM: $message") } fun clearFcmLogs() { @@ -491,7 +489,6 @@ fun MainScreen( val encryptedAccount = accountManager.getAccount(accountPublicKey) accountUsername = encryptedAccount?.username ?: "" accountName = encryptedAccount?.name ?: accountName - Log.d("MainActivity", "Loaded from DB: name=$accountName, username=$accountUsername") } } @@ -630,7 +627,6 @@ fun MainScreen( null } } catch (e: Exception) { - Log.e("MainActivity", "Error verifying password", e) null } } @@ -658,7 +654,6 @@ fun MainScreen( }, onDeleteAccount = { // TODO: Implement account deletion - Log.d("MainActivity", "Delete account requested") } ) } @@ -769,7 +764,6 @@ fun MainScreen( mainScreenScope.launch { onAccountInfoUpdated() } - Log.d("MainActivity", "Profile saved: name=$name, username=$username, UI updated") }, onLogout = onLogout, onNavigateToTheme = { diff --git a/app/src/main/java/com/rosetta/messenger/RosettaApplication.kt b/app/src/main/java/com/rosetta/messenger/RosettaApplication.kt index 0842f78..4e857fc 100644 --- a/app/src/main/java/com/rosetta/messenger/RosettaApplication.kt +++ b/app/src/main/java/com/rosetta/messenger/RosettaApplication.kt @@ -1,7 +1,6 @@ package com.rosetta.messenger import android.app.Application -import android.util.Log import com.rosetta.messenger.utils.CrashReportManager /** @@ -16,12 +15,10 @@ class RosettaApplication : Application() { override fun onCreate() { super.onCreate() - Log.d(TAG, "Application starting...") // Инициализируем crash reporter initCrashReporting() - Log.d(TAG, "Application initialized successfully") } /** @@ -30,9 +27,7 @@ class RosettaApplication : Application() { private fun initCrashReporting() { try { CrashReportManager.init(this) - Log.d(TAG, "Crash reporting initialized") } catch (e: Exception) { - Log.e(TAG, "Failed to initialize crash reporting", e) } } } diff --git a/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt b/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt index c77779d..5f3afc4 100644 --- a/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt +++ b/app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt @@ -437,16 +437,13 @@ object MessageCrypto { cipher.init(Cipher.DECRYPT_MODE, aesKey, IvParameterSpec(iv)) val decryptedUtf8Bytes = cipher.doFinal(encryptedKey) - android.util.Log.d("MessageCrypto", "🔓 AES decrypted raw bytes: ${decryptedUtf8Bytes.size}, hex=${decryptedUtf8Bytes.toHex()}") // ⚠️ КРИТИЧНО: Обратная конвертация UTF-8 → Latin1! // Desktop: decrypted.toString(crypto.enc.Utf8) → Buffer.from(str, 'binary') // Это декодирует UTF-8 в строку, потом берёт charCode каждого символа val utf8String = String(decryptedUtf8Bytes, Charsets.UTF_8) - android.util.Log.d("MessageCrypto", "🔓 UTF-8 string length: ${utf8String.length}, chars: ${utf8String.take(20).map { it.code }}") val originalBytes = utf8String.toByteArray(Charsets.ISO_8859_1) - android.util.Log.d("MessageCrypto", "🔓 Latin1 bytes: ${originalBytes.size}, hex=${originalBytes.toHex().take(80)}...") return originalBytes } @@ -527,8 +524,6 @@ object MessageCrypto { chachaKeyPlain: ByteArray ): String? { return try { - android.util.Log.d("MessageCrypto", "🔐 decryptAttachmentBlobWithPlainKey(bytes): data length=${encryptedData.length}, key=${chachaKeyPlain.size} bytes") - android.util.Log.d("MessageCrypto", "🔑 Raw key bytes hex: ${chachaKeyPlain.toHex()}") // Desktop использует key.toString('binary') → encrypt → decrypt → toString('utf-8') → PBKDF2 // Это эквивалентно: raw bytes → Latin1 string → UTF-8 encode → шифрование → @@ -545,91 +540,60 @@ object MessageCrypto { // Вариант 1: UTF-8 decode (как Node.js Buffer.toString('utf-8')) val password1 = bytesToJsUtf8String(chachaKeyPlain) val passwordBytes1 = password1.toByteArray(Charsets.UTF_8) - android.util.Log.d("MessageCrypto", "🔑 V1 (UTF-8 decode → string → UTF-8 encode): ${passwordBytes1.size} bytes") - android.util.Log.d("MessageCrypto", "🔑 V1 hex: ${passwordBytes1.toHex().take(60)}...") // Вариант 2: Latin1 decode (каждый byte = char 0-255) val password2 = String(chachaKeyPlain, Charsets.ISO_8859_1) val passwordBytes2 = password2.toByteArray(Charsets.UTF_8) - android.util.Log.d("MessageCrypto", "🔑 V2 (Latin1 → string → UTF-8 encode): ${passwordBytes2.size} bytes") - android.util.Log.d("MessageCrypto", "🔑 V2 hex: ${passwordBytes2.toHex().take(60)}...") // Вариант 3: Raw bytes напрямую (без string conversion) - android.util.Log.d("MessageCrypto", "🔑 V3 (raw bytes): ${chachaKeyPlain.size} bytes") - android.util.Log.d("MessageCrypto", "🔑 V3 hex: ${chachaKeyPlain.toHex().take(60)}...") // Пробуем расшифровать с КАЖДЫМ вариантом - android.util.Log.d("MessageCrypto", "🔓 Trying V1 (UTF-8 roundtrip)...") val pbkdf2Key1 = generatePBKDF2Key(password1) - android.util.Log.d("MessageCrypto", "🔑 V1 PBKDF2 key: ${pbkdf2Key1.toHex()}") val result1 = decryptWithPBKDF2Key(encryptedData, pbkdf2Key1) if (result1 != null) { - android.util.Log.d("MessageCrypto", "✅ V1 SUCCESS!") return result1 } - android.util.Log.d("MessageCrypto", "❌ V1 failed") - android.util.Log.d("MessageCrypto", "🔓 Trying V2 (Latin1 → UTF-8)...") val pbkdf2Key2 = generatePBKDF2Key(password2) - android.util.Log.d("MessageCrypto", "🔑 V2 PBKDF2 key: ${pbkdf2Key2.toHex()}") val result2 = decryptWithPBKDF2Key(encryptedData, pbkdf2Key2) if (result2 != null) { - android.util.Log.d("MessageCrypto", "✅ V2 SUCCESS!") return result2 } - android.util.Log.d("MessageCrypto", "❌ V2 failed") - android.util.Log.d("MessageCrypto", "🔓 Trying V3 (raw bytes for PBKDF2)...") val pbkdf2Key3 = generatePBKDF2KeyFromBytes(chachaKeyPlain) - android.util.Log.d("MessageCrypto", "🔑 V3 PBKDF2 key: ${pbkdf2Key3.toHex()}") val result3 = decryptWithPBKDF2Key(encryptedData, pbkdf2Key3) if (result3 != null) { - android.util.Log.d("MessageCrypto", "✅ V3 SUCCESS!") return result3 } - android.util.Log.d("MessageCrypto", "❌ V3 failed") // V4: Стандартный Java PBKDF2 (PBEKeySpec с char[]) - для совместимости с Android encryptReplyBlob - android.util.Log.d("MessageCrypto", "🔓 Trying V4 (Java SecretKeyFactory with Latin1 password)...") val pbkdf2Key4 = generatePBKDF2KeyJava(password2) val result4 = decryptWithPBKDF2Key(encryptedData, pbkdf2Key4) if (result4 != null) { - android.util.Log.d("MessageCrypto", "✅ V4 SUCCESS!") return result4 } - android.util.Log.d("MessageCrypto", "❌ V4 failed") // V5: Стандартный Java PBKDF2 с UTF-8 password - android.util.Log.d("MessageCrypto", "🔓 Trying V5 (Java SecretKeyFactory with UTF-8 password)...") val pbkdf2Key5 = generatePBKDF2KeyJava(password1) val result5 = decryptWithPBKDF2Key(encryptedData, pbkdf2Key5) if (result5 != null) { - android.util.Log.d("MessageCrypto", "✅ V5 SUCCESS!") return result5 } - android.util.Log.d("MessageCrypto", "❌ V5 failed") // V6: Java CharsetDecoder with REPLACE для UTF-8 (может отличаться от bytesToJsUtf8String) - android.util.Log.d("MessageCrypto", "🔓 Trying V6 (Java CharsetDecoder REPLACE)...") val decoder = java.nio.charset.StandardCharsets.UTF_8.newDecoder() decoder.onMalformedInput(java.nio.charset.CodingErrorAction.REPLACE) decoder.onUnmappableCharacter(java.nio.charset.CodingErrorAction.REPLACE) val password6 = decoder.decode(java.nio.ByteBuffer.wrap(chachaKeyPlain)).toString() val passwordBytes6 = password6.toByteArray(Charsets.UTF_8) - android.util.Log.d("MessageCrypto", "🔑 V6 password bytes: ${passwordBytes6.size}, hex: ${passwordBytes6.toHex().take(60)}...") val pbkdf2Key6 = generatePBKDF2Key(password6) - android.util.Log.d("MessageCrypto", "🔑 V6 PBKDF2 key: ${pbkdf2Key6.toHex()}") val result6 = decryptWithPBKDF2Key(encryptedData, pbkdf2Key6) if (result6 != null) { - android.util.Log.d("MessageCrypto", "✅ V6 SUCCESS!") return result6 } - android.util.Log.d("MessageCrypto", "❌ V6 failed") - android.util.Log.d("MessageCrypto", "❌ All variants failed!") null } catch (e: Exception) { - android.util.Log.e("MessageCrypto", "❌ decryptAttachmentBlobWithPlainKey failed: ${e.message}", e) null } } @@ -650,25 +614,20 @@ object MessageCrypto { passwordLatin1: String ): String? { return try { - android.util.Log.d("MessageCrypto", "🔐 decryptAttachmentBlobWithPassword: data length=${encryptedData.length}, password=${passwordLatin1.length} chars") // Конвертируем Latin1 string → bytes → UTF-8 string (эмулируем Desktop) // Desktop: Buffer.from(str, 'binary').toString('utf-8') val passwordBytes = passwordLatin1.toByteArray(Charsets.ISO_8859_1) val passwordUtf8 = bytesToJsUtf8String(passwordBytes) - android.util.Log.d("MessageCrypto", "🔑 Password UTF-8: ${passwordUtf8.length} chars") // Генерируем PBKDF2 ключ (salt='rosetta', 1000 iterations, sha1) // Crypto-js конвертирует passwordUtf8 string в UTF-8 bytes для PBKDF2 val pbkdf2Key = generatePBKDF2Key(passwordUtf8) - android.util.Log.d("MessageCrypto", "🔑 PBKDF2 key: ${pbkdf2Key.toHex()}") // Расшифровываем AES-256-CBC + zlib decompress val result = decryptWithPBKDF2Key(encryptedData, pbkdf2Key) - android.util.Log.d("MessageCrypto", "✅ Decryption: ${if (result != null) "success (${result.length} chars)" else "FAILED"}") result } catch (e: Exception) { - android.util.Log.e("MessageCrypto", "❌ decryptAttachmentBlobWithPassword failed: ${e.message}", e) null } } @@ -684,16 +643,13 @@ object MessageCrypto { myPrivateKey: String ): String? { return try { - android.util.Log.d("MessageCrypto", "🔐 decryptAttachmentBlob: data length=${encryptedData.length}, key length=${encryptedKey.length}") // 1. Расшифровываем ChaCha ключ+nonce (56 bytes) через ECDH val keyAndNonce = decryptKeyFromSender(encryptedKey, myPrivateKey) - android.util.Log.d("MessageCrypto", "🔑 Decrypted keyAndNonce: ${keyAndNonce.size} bytes, hex=${keyAndNonce.toHex().take(40)}...") // 2. Используем ВСЕ 56 байт как password для PBKDF2 decryptAttachmentBlobWithPlainKey(encryptedData, keyAndNonce) } catch (e: Exception) { - android.util.Log.e("MessageCrypto", "❌ decryptAttachmentBlob failed: ${e.message}", e) null } } @@ -791,20 +747,14 @@ object MessageCrypto { */ private fun decryptWithPBKDF2Key(encryptedData: String, pbkdf2Key: ByteArray): String? { return try { - android.util.Log.d("MessageCrypto", "🔓 decryptWithPBKDF2Key: data length=${encryptedData.length}") - android.util.Log.d("MessageCrypto", "🔓 First 100 chars: ${encryptedData.take(100)}") - android.util.Log.d("MessageCrypto", "🔓 Contains colon: ${encryptedData.contains(":")}") val parts = encryptedData.split(":") - android.util.Log.d("MessageCrypto", "🔓 Split parts: ${parts.size}") if (parts.size != 2) { - android.util.Log.e("MessageCrypto", "❌ Invalid format: expected 2 parts, got ${parts.size}") return null } val iv = android.util.Base64.decode(parts[0], android.util.Base64.DEFAULT) val ciphertext = android.util.Base64.decode(parts[1], android.util.Base64.DEFAULT) - android.util.Log.d("MessageCrypto", "🔓 IV: ${iv.size} bytes, Ciphertext: ${ciphertext.size} bytes") // AES-256-CBC расшифровка val cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding") @@ -812,7 +762,6 @@ object MessageCrypto { val ivSpec = javax.crypto.spec.IvParameterSpec(iv) cipher.init(javax.crypto.Cipher.DECRYPT_MODE, secretKey, ivSpec) val decrypted = cipher.doFinal(ciphertext) - android.util.Log.d("MessageCrypto", "🔓 AES decrypted: ${decrypted.size} bytes") // Zlib декомпрессия val inflater = java.util.zip.Inflater() @@ -826,10 +775,8 @@ object MessageCrypto { inflater.end() val result = String(outputStream.toByteArray(), Charsets.UTF_8) - android.util.Log.d("MessageCrypto", "🔓 Decompressed: ${result.length} chars") result } catch (e: Exception) { - android.util.Log.e("MessageCrypto", "❌ decryptWithPBKDF2Key failed: ${e.message}", e) null } } diff --git a/app/src/main/java/com/rosetta/messenger/data/MessageRepository.kt b/app/src/main/java/com/rosetta/messenger/data/MessageRepository.kt index 4925429..8ef36e8 100644 --- a/app/src/main/java/com/rosetta/messenger/data/MessageRepository.kt +++ b/app/src/main/java/com/rosetta/messenger/data/MessageRepository.kt @@ -1,7 +1,6 @@ package com.rosetta.messenger.data import android.content.Context -import android.util.Log import com.rosetta.messenger.crypto.CryptoManager import com.rosetta.messenger.crypto.MessageCrypto import com.rosetta.messenger.database.* @@ -204,7 +203,6 @@ class MessageRepository private constructor(private val context: Context) { // 🔑 КРИТИЧНО: Сохраняем ЗАШИФРОВАННЫЙ chacha_key (как в Desktop!) // Desktop хранит зашифрованный ключ, расшифровывает только при использовании - android.util.Log.d("MessageRepository", "🔑 Outgoing chacha_key (encrypted): ${encryptedKey.length} chars") // Сериализуем attachments в JSON val attachmentsJson = serializeAttachments(attachments) @@ -235,16 +233,13 @@ class MessageRepository private constructor(private val context: Context) { ) messageDao.insertMessage(entity) - Log.d("MessageRepository", "� Inserted OUTGOING message: fromMe=1, delivered=${entity.delivered}, read=0") } // 🔥 КРИТИЧНО: Обновляем диалог через updateDialogFromMessages - Log.d("MessageRepository", "🔄 Calling updateDialogFromMessages after sending...") dialogDao.updateDialogFromMessages(account, toPublicKey) // 🔥 Логируем что записалось в диалог val dialog = dialogDao.getDialog(account, toPublicKey) - Log.d("MessageRepository", "🎯 DIALOG AFTER SEND: lastMsgFromMe=${dialog?.lastMessageFromMe}, delivered=${dialog?.lastMessageDelivered}, read=${dialog?.lastMessageRead}") // 🔥 Отмечаем что я отправлял сообщения в этот диалог (перемещает из requests в chats) val updatedRows = dialogDao.markIHaveSent(account, toPublicKey) @@ -316,7 +311,6 @@ class MessageRepository private constructor(private val context: Context) { // 🔑 КРИТИЧНО: Сохраняем ЗАШИФРОВАННЫЙ chacha_key (как в Desktop!) // Desktop: хранит зашифрованный ключ, расшифровывает только при использовании // Buffer.from(await decrypt(message.chacha_key, privatePlain), "binary").toString('utf-8') - android.util.Log.d("MessageRepository", "🔑 Incoming chacha_key (encrypted): ${packet.chachaKey.length} chars") // Расшифровываем val plainText = MessageCrypto.decryptIncoming( @@ -365,16 +359,13 @@ class MessageRepository private constructor(private val context: Context) { // Сохраняем в БД только если сообщения нет messageDao.insertMessage(entity) - Log.d("MessageRepository", "� Inserted INCOMING message: fromMe=0, delivered=${entity.delivered}, read=0") } // 🔥 КРИТИЧНО: Обновляем диалог через updateDialogFromMessages - Log.d("MessageRepository", "🔄 Calling updateDialogFromMessages after incoming message...") dialogDao.updateDialogFromMessages(account, packet.fromPublicKey) // 🔥 Логируем что записалось в диалог val dialog = dialogDao.getDialog(account, packet.fromPublicKey) - Log.d("MessageRepository", "🎯 DIALOG AFTER INCOMING: lastMsgFromMe=${dialog?.lastMessageFromMe}, delivered=${dialog?.lastMessageDelivered}, read=${dialog?.lastMessageRead}") // 🔥 Запрашиваем информацию о пользователе для отображения имени вместо ключа requestUserInfo(packet.fromPublicKey) @@ -416,19 +407,15 @@ class MessageRepository private constructor(private val context: Context) { suspend fun handleRead(packet: PacketRead) { val account = currentAccount ?: return - Log.d("MessageRepository", "🔥🔥🔥 handleRead START: fromPublicKey=${packet.fromPublicKey.take(16)}...") // Проверяем последнее сообщение ДО обновления val lastMsgBefore = messageDao.getLastMessageDebug(account, packet.fromPublicKey) - Log.d("MessageRepository", "📊 BEFORE markAllAsRead: fromMe=${lastMsgBefore?.fromMe}, delivered=${lastMsgBefore?.delivered}, read=${lastMsgBefore?.read}, timestamp=${lastMsgBefore?.timestamp}") // Отмечаем все наши исходящие сообщения к этому собеседнику как прочитанные messageDao.markAllAsRead(account, packet.fromPublicKey) - Log.d("MessageRepository", "✅ markAllAsRead completed") // 🔥 DEBUG: Проверяем последнее сообщение ПОСЛЕ обновления val lastMsgAfter = messageDao.getLastMessageDebug(account, packet.fromPublicKey) - Log.d("MessageRepository", "📊 AFTER markAllAsRead: fromMe=${lastMsgAfter?.fromMe}, delivered=${lastMsgAfter?.delivered}, read=${lastMsgAfter?.read}, timestamp=${lastMsgAfter?.timestamp}") // Обновляем кэш - все исходящие сообщения помечаем как прочитанные val dialogKey = getDialogKey(packet.fromPublicKey) @@ -440,13 +427,10 @@ class MessageRepository private constructor(private val context: Context) { } // 🔥 КРИТИЧНО: Обновляем диалог чтобы lastMessageRead обновился - Log.d("MessageRepository", "🔄 Calling updateDialogFromMessages...") dialogDao.updateDialogFromMessages(account, packet.fromPublicKey) // Логируем что записалось в диалог val dialog = dialogDao.getDialog(account, packet.fromPublicKey) - Log.d("MessageRepository", "🎯 DIALOG AFTER UPDATE: lastMsgFromMe=${dialog?.lastMessageFromMe}, delivered=${dialog?.lastMessageDelivered}, read=${dialog?.lastMessageRead}") - Log.d("MessageRepository", "🔥🔥🔥 handleRead END") } /** @@ -640,19 +624,15 @@ class MessageRepository private constructor(private val context: Context) { suspend fun updateDialogUserInfo(publicKey: String, title: String, username: String, verified: Int) { val account = currentAccount ?: return - android.util.Log.d("MessageRepo", "🔄 updateDialogUserInfo: ${publicKey.take(16)}... title='$title' username='$username'") // Проверяем существует ли диалог с этим пользователем val existing = dialogDao.getDialog(account, publicKey) if (existing != null) { - android.util.Log.d("MessageRepo", "✅ Updating dialog opponent info in DB for ${publicKey.take(16)}...") dialogDao.updateOpponentInfo(account, publicKey, title, username, verified) // 🔥 Проверим что данные сохранились val updated = dialogDao.getDialog(account, publicKey) - android.util.Log.d("MessageRepo", "📝 After update: title='${updated?.opponentTitle}' username='${updated?.opponentUsername}'") } else { - android.util.Log.w("MessageRepo", "⚠️ Dialog not found for ${publicKey.take(16)}...") } } @@ -769,14 +749,11 @@ class MessageRepository private constructor(private val context: Context) { encryptedKey: String, privateKey: String ) { - Log.d("MessageRepository", "📸 processAvatarAttachments: ${attachments.size} attachments from ${fromPublicKey.take(16)}") for (attachment in attachments) { - Log.d("MessageRepository", "📸 Attachment type=${attachment.type} (AVATAR=${AttachmentType.AVATAR}), blob size=${attachment.blob.length}") if (attachment.type == AttachmentType.AVATAR && attachment.blob.isNotEmpty()) { try { - Log.d("MessageRepository", "📸 Found AVATAR attachment! Decrypting...") // 1. Расшифровываем blob с ChaCha ключом сообщения val decryptedBlob = MessageCrypto.decryptAttachmentBlob( @@ -785,12 +762,10 @@ class MessageRepository private constructor(private val context: Context) { privateKey ) - Log.d("MessageRepository", "📸 Decrypted blob: ${decryptedBlob?.take(50) ?: "NULL"}") if (decryptedBlob != null) { // 2. Сохраняем аватар в кэш val filePath = AvatarFileManager.saveAvatar(context, decryptedBlob, fromPublicKey) - Log.d("MessageRepository", "📸 Avatar saved to: $filePath") val entity = AvatarCacheEntity( publicKey = fromPublicKey, @@ -798,17 +773,13 @@ class MessageRepository private constructor(private val context: Context) { timestamp = System.currentTimeMillis() ) avatarDao.insertAvatar(entity) - Log.d("MessageRepository", "📸 Avatar inserted to DB for ${fromPublicKey.take(16)}") // 3. Очищаем старые аватары (оставляем последние 5) avatarDao.deleteOldAvatars(fromPublicKey, 5) - Log.d("MessageRepository", "📸 ✅ Successfully saved avatar for $fromPublicKey") } else { - Log.w("MessageRepository", "📸 ⚠️ Decryption returned null!") } } catch (e: Exception) { - Log.e("MessageRepository", "📸 ❌ Failed to process avatar attachment", e) } } } @@ -830,7 +801,6 @@ class MessageRepository private constructor(private val context: Context) { // Сохраняем только IMAGE, не FILE (файлы загружаются с CDN при необходимости) if (attachment.type == AttachmentType.IMAGE && attachment.blob.isNotEmpty()) { try { - Log.d("MessageRepository", "🖼️ Processing IMAGE attachment: ${attachment.id}") // 1. Расшифровываем blob с ChaCha ключом сообщения val decryptedBlob = MessageCrypto.decryptAttachmentBlob( @@ -850,15 +820,11 @@ class MessageRepository private constructor(private val context: Context) { ) if (saved) { - Log.d("MessageRepository", "🖼️ ✅ Image saved to file: ${attachment.id}") } else { - Log.w("MessageRepository", "🖼️ ⚠️ Failed to save image to file") } } else { - Log.w("MessageRepository", "🖼️ ⚠️ Decryption returned null for image") } } catch (e: Exception) { - Log.e("MessageRepository", "🖼️ ❌ Failed to process image attachment", e) } } } diff --git a/app/src/main/java/com/rosetta/messenger/network/Protocol.kt b/app/src/main/java/com/rosetta/messenger/network/Protocol.kt index f86f0a1..a90e3fd 100644 --- a/app/src/main/java/com/rosetta/messenger/network/Protocol.kt +++ b/app/src/main/java/com/rosetta/messenger/network/Protocol.kt @@ -35,7 +35,6 @@ class Protocol( private fun log(message: String) { // TEMPORARY: Enable logging for debugging PacketUserInfo - android.util.Log.d(TAG, message) logger(message) } diff --git a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt index 4ecec84..dc4a49e 100644 --- a/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt +++ b/app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt @@ -157,13 +157,11 @@ object ProtocolManager { // Обновляет информацию о пользователе в диалогах когда приходит ответ от сервера waitPacket(0x03) { packet -> val searchPacket = packet as PacketSearch - android.util.Log.d("Protocol", "🔍 Search/UserInfo response: ${searchPacket.users.size} users") // Обновляем информацию о пользователях в диалогах if (searchPacket.users.isNotEmpty()) { scope.launch(Dispatchers.IO) { // 🔥 Запускаем на IO потоке для работы с БД searchPacket.users.forEach { user -> - android.util.Log.d("Protocol", "📝 Updating user info: ${user.publicKey.take(16)}... title='${user.title}' username='${user.username}'") messageRepository?.updateDialogUserInfo( user.publicKey, user.title, @@ -178,7 +176,6 @@ object ProtocolManager { // 🚀 Обработчик транспортного сервера (0x0F) waitPacket(0x0F) { packet -> val transportPacket = packet as PacketRequestTransport - android.util.Log.d("Protocol", "🚀 Transport server: ${transportPacket.transportServer}") TransportManager.setTransportServer(transportPacket.transportServer) } } diff --git a/app/src/main/java/com/rosetta/messenger/network/TransportManager.kt b/app/src/main/java/com/rosetta/messenger/network/TransportManager.kt index 529a0b1..69880dc 100644 --- a/app/src/main/java/com/rosetta/messenger/network/TransportManager.kt +++ b/app/src/main/java/com/rosetta/messenger/network/TransportManager.kt @@ -1,6 +1,5 @@ package com.rosetta.messenger.network -import android.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -53,7 +52,6 @@ object TransportManager { */ fun setTransportServer(server: String) { transportServer = server - Log.d(TAG, "🚀 Transport server set: $server") } /** @@ -66,7 +64,6 @@ object TransportManager { */ private fun getActiveServer(): String { val server = transportServer ?: FALLBACK_TRANSPORT_SERVER - Log.d(TAG, "📡 Using transport server: $server (configured: ${transportServer != null})") return server } @@ -87,8 +84,6 @@ object TransportManager { suspend fun uploadFile(id: String, content: String): String = withContext(Dispatchers.IO) { val server = getActiveServer() - Log.d(TAG, "📤 Uploading file: $id to $server") - Log.d(TAG, "📤 Content length: ${content.length}, first 50 chars: ${content.take(50)}") // Добавляем в список загрузок _uploading.value = _uploading.value + TransportState(id, 0) @@ -96,7 +91,6 @@ object TransportManager { try { // 🔥 КРИТИЧНО: Преобразуем строку в байты (как desktop делает new Blob([content])) val contentBytes = content.toByteArray(Charsets.UTF_8) - Log.d(TAG, "📤 Content bytes length: ${contentBytes.size}") val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) @@ -115,8 +109,6 @@ object TransportManager { val response = suspendCoroutine { cont -> client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { - Log.e(TAG, "❌ Upload failed for $id: ${e.message}") - Log.e(TAG, "❌ Stack trace: ${e.stackTraceToString()}") cont.resumeWithException(e) } @@ -128,19 +120,16 @@ object TransportManager { if (!response.isSuccessful) { val errorBody = response.body?.string() ?: "No error body" - Log.e(TAG, "❌ Upload failed: ${response.code}, body: $errorBody") throw IOException("Upload failed: ${response.code}") } val responseBody = response.body?.string() ?: throw IOException("Empty response") - Log.d(TAG, "📤 Response body: $responseBody") // Parse JSON response to get tag val tag = org.json.JSONObject(responseBody).getString("t") - Log.d(TAG, "✅ Upload complete: $id -> $tag") // Обновляем прогресс до 100% _uploading.value = _uploading.value.map { @@ -163,7 +152,6 @@ object TransportManager { suspend fun downloadFile(id: String, tag: String): String = withContext(Dispatchers.IO) { val server = getActiveServer() - Log.d(TAG, "📥 Downloading file: $id (tag: $tag) from $server") // Добавляем в список скачиваний _downloading.value = _downloading.value + TransportState(id, 0) @@ -193,7 +181,6 @@ object TransportManager { val content = response.body?.string() ?: throw IOException("Empty response") - Log.d(TAG, "✅ Download complete: $id (${content.length} bytes)") // Обновляем прогресс до 100% _downloading.value = _downloading.value.map { diff --git a/app/src/main/java/com/rosetta/messenger/repository/AvatarRepository.kt b/app/src/main/java/com/rosetta/messenger/repository/AvatarRepository.kt index d73dbfa..5efe026 100644 --- a/app/src/main/java/com/rosetta/messenger/repository/AvatarRepository.kt +++ b/app/src/main/java/com/rosetta/messenger/repository/AvatarRepository.kt @@ -1,7 +1,6 @@ package com.rosetta.messenger.repository import android.content.Context -import android.util.Log import com.rosetta.messenger.database.AvatarCacheEntity import com.rosetta.messenger.database.AvatarDao import com.rosetta.messenger.utils.AvatarFileManager @@ -57,7 +56,6 @@ class AvatarRepository( // Подписываемся на изменения в БД с использованием repository scope avatarDao.getAvatars(publicKey) .onEach { entities -> - Log.d(TAG, "📥 DB update for $publicKey: ${entities.size} entities") val avatars = if (allDecode) { // Загружаем всю историю entities.mapNotNull { entity -> @@ -70,7 +68,6 @@ class AvatarRepository( }?.let { listOf(it) } ?: emptyList() } flow.value = avatars - Log.d(TAG, "✅ Flow updated for $publicKey: ${avatars.size} avatars") } .launchIn(repositoryScope) @@ -97,7 +94,6 @@ class AvatarRepository( try { // Сохраняем файл val filePath = AvatarFileManager.saveAvatar(context, base64Image, fromPublicKey) - Log.d(TAG, "💾 Avatar file saved for $fromPublicKey: $filePath") // Сохраняем в БД val entity = AvatarCacheEntity( @@ -106,7 +102,6 @@ class AvatarRepository( timestamp = System.currentTimeMillis() ) avatarDao.insertAvatar(entity) - Log.d(TAG, "💾 Avatar entity inserted to DB for $fromPublicKey") // Очищаем старые аватары (оставляем только последние N) avatarDao.deleteOldAvatars(fromPublicKey, MAX_AVATAR_HISTORY) @@ -117,15 +112,11 @@ class AvatarRepository( val avatarInfo = loadAndDecryptAvatar(entity) if (avatarInfo != null) { cachedFlow.value = listOf(avatarInfo) - Log.d(TAG, "✅ Memory cache updated for $fromPublicKey") } } else { - Log.d(TAG, "ℹ️ No memory cache for $fromPublicKey, will be loaded on next getAvatars()") } - Log.d(TAG, "✅ Saved avatar for $fromPublicKey") } catch (e: Exception) { - Log.e(TAG, "❌ Failed to save avatar for $fromPublicKey", e) } } } @@ -139,13 +130,9 @@ class AvatarRepository( suspend fun changeMyAvatar(base64Image: String) { withContext(Dispatchers.IO) { try { - Log.d(TAG, "🔄 changeMyAvatar called") - Log.d(TAG, "👤 Current public key: ${currentPublicKey.take(16)}...") - Log.d(TAG, "📊 Base64 image length: ${base64Image.length} chars") // Сохраняем файл val filePath = AvatarFileManager.saveAvatar(context, base64Image, currentPublicKey) - Log.d(TAG, "✅ Avatar file saved: $filePath") // Сохраняем в БД val entity = AvatarCacheEntity( @@ -154,14 +141,11 @@ class AvatarRepository( timestamp = System.currentTimeMillis() ) avatarDao.insertAvatar(entity) - Log.d(TAG, "✅ Avatar inserted to DB") // Очищаем старые аватары avatarDao.deleteOldAvatars(currentPublicKey, MAX_AVATAR_HISTORY) - Log.d(TAG, "🎉 Avatar changed successfully!") } catch (e: Exception) { - Log.e(TAG, "❌ Failed to change avatar: ${e.message}", e) throw e } } @@ -173,8 +157,6 @@ class AvatarRepository( suspend fun deleteMyAvatar() { withContext(Dispatchers.IO) { try { - Log.d(TAG, "🗑️ deleteMyAvatar called") - Log.d(TAG, "👤 Current public key: ${currentPublicKey.take(16)}...") // Получаем все аватары пользователя val avatars = avatarDao.getAvatarsByPublicKey(currentPublicKey) @@ -183,22 +165,17 @@ class AvatarRepository( for (avatar in avatars) { try { AvatarFileManager.deleteAvatar(context, avatar.avatar) - Log.d(TAG, "✅ Deleted avatar file: ${avatar.avatar}") } catch (e: Exception) { - Log.w(TAG, "⚠️ Failed to delete avatar file: ${avatar.avatar}", e) } } // Удаляем из БД avatarDao.deleteAllAvatars(currentPublicKey) - Log.d(TAG, "✅ Avatars deleted from DB") // Очищаем memory cache memoryCache.remove(currentPublicKey) - Log.d(TAG, "🎉 Avatar deleted successfully!") } catch (e: Exception) { - Log.e(TAG, "❌ Failed to delete avatar: ${e.message}", e) throw e } } @@ -217,11 +194,9 @@ class AvatarRepository( timestamp = entity.timestamp ) } else { - Log.w(TAG, "Failed to read avatar file: ${entity.avatar}") null } } catch (e: Exception) { - Log.e(TAG, "Failed to load avatar", e) null } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt index d3c1cac..32714dd 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/auth/UnlockScreen.kt @@ -110,7 +110,6 @@ private suspend fun performUnlock( name = account.name ) - android.util.Log.d("UnlockScreen", "🔐 Starting connection and authentication...") // Connect to server and authenticate ProtocolManager.connect() @@ -130,12 +129,10 @@ private suspend fun performUnlock( kotlinx.coroutines.delay(300) - android.util.Log.d("UnlockScreen", "🔐 Starting authentication...") ProtocolManager.authenticate(account.publicKey, privateKeyHash) accountManager.setCurrentAccount(account.publicKey) - android.util.Log.d("UnlockScreen", "✅ Unlock complete") onSuccess(decryptedAccount) } catch (e: Exception) { onError("Failed to unlock: ${e.message}") @@ -181,7 +178,6 @@ fun UnlockScreen( val biometricPrefs = remember { BiometricPreferences(context) } val scope = rememberCoroutineScope() - android.util.Log.d("UnlockScreen", "🎬 SCREEN INITIALIZED - Activity: $activity") var password by remember { mutableStateOf("") } var passwordVisible by remember { mutableStateOf(false) } @@ -203,7 +199,6 @@ fun UnlockScreen( // Load accounts and pre-select last used account LaunchedEffect(Unit) { - android.util.Log.d("UnlockScreen", "📦 LOADING DATA...") // ⚡ СИНХРОННОЕ чтение последнего аккаунта ДО загрузки списка val lastLoggedKey = accountManager.getLastLoggedPublicKey() @@ -243,38 +238,27 @@ fun UnlockScreen( } savedPasswordsMap = passwords - android.util.Log.d("UnlockScreen", "🔐 Biometric available: $biometricAvailable") - android.util.Log.d("UnlockScreen", "🔐 Biometric enabled: $isBiometricEnabled") - android.util.Log.d("UnlockScreen", "🔐 Activity: $activity") - android.util.Log.d("UnlockScreen", "🔐 Selected account: ${selectedAccount?.publicKey}") - android.util.Log.d("UnlockScreen", "🔐 Saved passwords count: ${passwords.size}") - android.util.Log.d("UnlockScreen", "🔐 Has password for selected: ${selectedAccount?.let { passwords.containsKey(it.publicKey) }}") dataLoaded = true - android.util.Log.d("UnlockScreen", "✅ DATA LOADED") } // Функция для запуска биометрической разблокировки fun tryBiometricUnlock() { if (selectedAccount == null || activity == null) { - android.util.Log.d("UnlockScreen", "❌ Cannot start biometric: no account or activity") return } val encryptedPassword = savedPasswordsMap[selectedAccount!!.publicKey] if (encryptedPassword == null) { - android.util.Log.d("UnlockScreen", "❌ No saved password for account") return } - android.util.Log.d("UnlockScreen", "🔐 Starting biometric unlock...") biometricManager.decryptPassword( activity = activity, encryptedData = encryptedPassword, onSuccess = { decryptedPassword -> - android.util.Log.d("UnlockScreen", "✅ Biometric success, unlocking...") scope.launch { performUnlock( selectedAccount = selectedAccount, @@ -289,11 +273,9 @@ fun UnlockScreen( } }, onError = { errorMessage -> - android.util.Log.e("UnlockScreen", "❌ Biometric error: $errorMessage") error = errorMessage }, onCancel = { - android.util.Log.d("UnlockScreen", "🚫 Biometric cancelled") } ) } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt index 2fe7fa1..cca22d1 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt @@ -198,7 +198,6 @@ fun ChatDetailScreen( contract = ActivityResultContracts.TakePicture() ) { success -> if (success && cameraImageUri != null) { - android.util.Log.d("ChatDetailScreen", "📷 Photo captured: $cameraImageUri") // Открываем редактор вместо прямой отправки pendingCameraPhotoUri = cameraImageUri } @@ -210,13 +209,11 @@ fun ChatDetailScreen( ) { uri -> if (uri != null) { scope.launch { - android.util.Log.d("ChatDetailScreen", "📄 File selected: $uri") val fileName = MediaUtils.getFileName(context, uri) val fileSize = MediaUtils.getFileSize(context, uri) // Проверяем размер файла if (fileSize > MediaUtils.MAX_FILE_SIZE_MB * 1024 * 1024) { - android.util.Log.w("ChatDetailScreen", "📄 File too large: ${fileSize / 1024 / 1024}MB") // TODO: Показать ошибку return@launch } @@ -1994,7 +1991,6 @@ fun ChatDetailScreen( currentUserPublicKey = currentUserPublicKey, onMediaSelected = { selectedMedia -> // 📸 Открываем edit screen для выбранных изображений - android.util.Log.d("ChatDetailScreen", "📸 Opening editor for ${selectedMedia.size} media items") // Собираем URI изображений (пока без видео) val imageUris = selectedMedia @@ -2020,7 +2016,6 @@ fun ChatDetailScreen( ) cameraLauncher.launch(cameraImageUri!!) } catch (e: Exception) { - android.util.Log.e("ChatDetailScreen", "📷 Failed to create camera file", e) } }, onOpenFilePicker = { @@ -2029,7 +2024,6 @@ fun ChatDetailScreen( }, onAvatarClick = { // 👤 Отправляем свой аватар (как в desktop) - android.util.Log.d("ChatDetailScreen", "👤 Sending avatar...") viewModel.sendAvatarMessage() } ) 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 7d3c9d4..6495928 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 @@ -4,7 +4,6 @@ import android.app.Application import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Base64 -import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.rosetta.messenger.crypto.CryptoManager @@ -334,8 +333,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { * Открыть диалог */ fun openDialog(publicKey: String, title: String = "", username: String = "") { - Log.d(TAG, "🚪 openDialog START: publicKey=$publicKey, title=$title") - Log.d(TAG, "🔍 Current state: opponentKey=$opponentKey, myPublicKey=$myPublicKey") // 🔥 ВСЕГДА перезагружаем данные - не кешируем, т.к. диалог мог быть удалён // if (opponentKey == publicKey) { @@ -354,11 +351,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val forwardMessages = ForwardManager.getForwardMessagesForChat(publicKey) val hasForward = forwardMessages.isNotEmpty() if (hasForward) { - Log.d(TAG, "📨 Has forward messages: ${forwardMessages.size}") } // Сбрасываем состояние - Log.d(TAG, "🔄 Resetting state, setting messages to empty") _messages.value = emptyList() _opponentOnline.value = false _opponentTyping.value = false @@ -370,7 +365,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { subscribedToOnlineStatus = false // 🔥 Сбрасываем флаг подписки при смене диалога isDialogActive = true // 🔥 Диалог активен! - Log.d(TAG, "📊 State after reset: messagesCount=${_messages.value.size}, isDialogActive=$isDialogActive") // 📨 Применяем Forward сообщения СРАЗУ после сброса if (hasForward) { @@ -427,13 +421,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val opponent = opponentKey ?: return val dialogKey = getDialogKey(account, opponent) - Log.d(TAG, "📥 loadMessagesFromDatabase START: account=$account, opponent=$opponent, dialogKey=$dialogKey") // 📁 Проверяем является ли это Saved Messages val isSavedMessages = (opponent == account) if (isLoadingMessages) { - Log.d(TAG, "⚠️ loadMessagesFromDatabase SKIP - already loading") return } isLoadingMessages = true @@ -442,10 +434,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { try { // 🔥 МГНОВЕННАЯ загрузка из кэша если есть! val cachedMessages = dialogMessagesCache[dialogKey] - Log.d(TAG, "📦 Cache check: dialogKey=$dialogKey, cachedCount=${cachedMessages?.size ?: 0}") if (cachedMessages != null && cachedMessages.isNotEmpty()) { - Log.d(TAG, "✅ Using cached messages: ${cachedMessages.size}") withContext(Dispatchers.Main.immediate) { _messages.value = cachedMessages _isLoading.value = false @@ -466,11 +456,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { messageDao.getMessageCount(account, dialogKey) } - Log.d(TAG, "📊 DB message count: totalCount=$totalCount, isSavedMessages=$isSavedMessages") if (totalCount == 0) { // Пустой диалог - сразу показываем пустое состояние без скелетона - Log.d(TAG, "📭 Empty dialog - showing empty state") withContext(Dispatchers.Main.immediate) { _messages.value = emptyList() _isLoading.value = false @@ -481,24 +469,20 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { // 🔥 Есть сообщения - показываем скелетон и загружаем с задержкой для анимации if (delayMs > 0) { - Log.d(TAG, "⏳ Delaying load for ${delayMs}ms") withContext(Dispatchers.Main.immediate) { _isLoading.value = true // Показываем скелетон } delay(delayMs) - Log.d(TAG, "✅ Delay finished, starting DB load") } // 🔥 Получаем первую страницу - используем специальный метод для saved messages - Log.d(TAG, "🔍 Querying DB for messages...") val entities = if (isSavedMessages) { messageDao.getMessagesForSavedDialog(account, limit = PAGE_SIZE, offset = 0) } else { messageDao.getMessages(account, dialogKey, limit = PAGE_SIZE, offset = 0) } - Log.d(TAG, "📋 Loaded entities from DB: count=${entities.size}") hasMoreMessages = entities.size >= PAGE_SIZE currentOffset = entities.size @@ -517,11 +501,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { } } - Log.d(TAG, "✅ Decrypted messages: count=${messages.size}") // 🔥 Сохраняем в кэш для мгновенной повторной загрузки! dialogMessagesCache[dialogKey] = messages.toList() - Log.d(TAG, "💾 Saved to cache: dialogKey=$dialogKey, count=${messages.size}") // 🔥 СРАЗУ обновляем UI - пользователь видит сообщения мгновенно // НО сохраняем оптимистичные сообщения (SENDING), которые ещё не в БД @@ -558,9 +540,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { isLoadingMessages = false } catch (e: Exception) { - Log.e(TAG, "❌ Error loading messages from DB", e) - Log.e(TAG, "❌ Exception details: ${e.message}") - Log.e(TAG, "❌ Stack trace: ${e.stackTraceToString()}") withContext(Dispatchers.Main.immediate) { _isLoading.value = false } @@ -828,7 +807,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { result } catch (e: Exception) { - android.util.Log.e("ChatViewModel", "Failed to parse attachments", e) emptyList() } } @@ -985,7 +963,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { } } } catch (e: Exception) { - Log.e(TAG, "📸 Failed to parse reply attachments from JSON: ${e.message}") } @@ -1256,13 +1233,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val isFirstMessage = messageDao.getMessageCount(sender, sender, recipient) == 0 if (isFirstMessage) { try { - Log.d(TAG, "📸 First message to user - checking for avatar...") // Получаем свой аватар из AvatarRepository val avatarDao = database.avatarDao() val myAvatar = avatarDao.getLatestAvatar(sender) if (myAvatar != null) { - Log.d(TAG, "📸 Found my avatar, path: ${myAvatar.avatar}") // Читаем и расшифровываем аватар val avatarBlob = com.rosetta.messenger.utils.AvatarFileManager.readAvatar( getApplication(), @@ -1270,10 +1245,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { ) if (avatarBlob != null && avatarBlob.isNotEmpty()) { - Log.d(TAG, "📸 Avatar blob read successfully, length: ${avatarBlob.length}") // Шифруем аватар с ChaCha ключом для отправки val encryptedAvatarBlob = MessageCrypto.encryptReplyBlob(avatarBlob, plainKeyAndNonce) - Log.d(TAG, "📸 Avatar encrypted, length: ${encryptedAvatarBlob.length}") val avatarAttachmentId = "avatar_${timestamp}" messageAttachments.add(MessageAttachment( @@ -1282,15 +1255,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { type = AttachmentType.AVATAR, preview = "" )) - Log.d(TAG, "📸 ✅ Avatar attached to first message!") } else { - Log.w(TAG, "📸 Avatar blob is null or empty!") } } else { - Log.d(TAG, "📸 No avatar found for current user") } } catch (e: Exception) { - Log.e(TAG, "📸 Failed to attach avatar to first message", e) } } @@ -1427,11 +1396,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val privateKey = myPrivateKey if (recipient == null || sender == null || privateKey == null) { - Log.e(TAG, "📸 Cannot send image: missing keys") return } if (isSending) { - Log.w(TAG, "📸 Already sending message") return } @@ -1462,7 +1429,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { _messages.value = _messages.value + optimisticMessage _inputText.value = "" - Log.d(TAG, "📸 Sending image message: id=$messageId") viewModelScope.launch(Dispatchers.IO) { try { @@ -1485,9 +1451,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { var uploadTag = "" if (!isSavedMessages) { - Log.d(TAG, "📤 Uploading image to Transport Server...") uploadTag = TransportManager.uploadFile(attachmentId, encryptedImageBlob) - Log.d(TAG, "📤 Upload complete, tag: $uploadTag") } // Preview содержит tag::blurhash (как в desktop) @@ -1556,10 +1520,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { ) saveDialog(if (text.isNotEmpty()) text else "photo", timestamp) - Log.d(TAG, "📸 ✅ Image message sent successfully") } catch (e: Exception) { - Log.e(TAG, "📸 ❌ Failed to send image message", e) withContext(Dispatchers.Main) { updateMessageStatus(messageId, MessageStatus.SENT) } @@ -1590,11 +1552,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val privateKey = myPrivateKey if (recipient == null || sender == null || privateKey == null) { - Log.e(TAG, "🖼️ Cannot send image group: missing keys") return } if (isSending) { - Log.w(TAG, "🖼️ Already sending message") return } @@ -1628,7 +1588,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { _messages.value = _messages.value + optimisticMessage _inputText.value = "" - Log.d(TAG, "🖼️ Sending image group: ${images.size} images, id=$messageId") viewModelScope.launch(Dispatchers.IO) { try { @@ -1687,7 +1646,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { put("height", imageData.height) }) - Log.d(TAG, "🖼️ Image $index uploaded: tag=${uploadTag?.take(20) ?: "null"}") } // Создаём пакет @@ -1725,10 +1683,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { ) saveDialog(if (text.isNotEmpty()) text else "📷 ${images.size} photos", timestamp) - Log.d(TAG, "🖼️ ✅ Image group sent successfully") } catch (e: Exception) { - Log.e(TAG, "🖼️ ❌ Failed to send image group", e) withContext(Dispatchers.Main) { updateMessageStatus(messageId, MessageStatus.SENT) } @@ -1751,11 +1707,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val privateKey = myPrivateKey if (recipient == null || sender == null || privateKey == null) { - Log.e(TAG, "📄 Cannot send file: missing keys") return } if (isSending) { - Log.w(TAG, "📄 Already sending message") return } @@ -1785,7 +1739,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { _messages.value = _messages.value + optimisticMessage _inputText.value = "" - Log.d(TAG, "📄 Sending file message: $fileName ($fileSize bytes)") viewModelScope.launch(Dispatchers.IO) { try { @@ -1807,9 +1760,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { var uploadTag = "" if (!isSavedMessages) { - Log.d(TAG, "📤 Uploading file to Transport Server...") uploadTag = TransportManager.uploadFile(attachmentId, encryptedFileBlob) - Log.d(TAG, "📤 Upload complete, tag: $uploadTag") } // Preview содержит tag::size::name (как в desktop) @@ -1865,10 +1816,8 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { ) saveDialog(if (text.isNotEmpty()) text else "file", timestamp) - Log.d(TAG, "📄 ✅ File message sent successfully") } catch (e: Exception) { - Log.e(TAG, "📄 ❌ Failed to send file message", e) withContext(Dispatchers.Main) { updateMessageStatus(messageId, MessageStatus.SENT) } @@ -1888,11 +1837,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val userPrivateKey = myPrivateKey if (recipient == null || sender == null || userPrivateKey == null) { - Log.e(TAG, "👤 Cannot send avatar: missing keys") return } if (isSending) { - Log.w(TAG, "👤 Already sending message") return } @@ -1903,13 +1850,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { viewModelScope.launch(Dispatchers.IO) { try { - Log.d(TAG, "👤 Fetching current user avatar...") // Получаем свой аватар из AvatarRepository val avatarDao = database.avatarDao() val myAvatar = avatarDao.getLatestAvatar(sender) if (myAvatar == null) { - Log.w(TAG, "👤 No avatar found for current user") withContext(Dispatchers.Main) { android.widget.Toast.makeText( getApplication(), @@ -1921,7 +1866,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { return@launch } - Log.d(TAG, "👤 Found avatar, path: ${myAvatar.avatar}") // Читаем и расшифровываем аватар val avatarBlob = com.rosetta.messenger.utils.AvatarFileManager.readAvatar( getApplication(), @@ -1929,7 +1873,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { ) if (avatarBlob == null || avatarBlob.isEmpty()) { - Log.w(TAG, "👤 Avatar blob is null or empty!") withContext(Dispatchers.Main) { android.widget.Toast.makeText( getApplication(), @@ -1941,8 +1884,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { return@launch } - Log.d(TAG, "👤 Avatar blob read successfully, length: ${avatarBlob.length}") - Log.d(TAG, "👤 Avatar blob first 100 chars: ${avatarBlob.take(100)}") // 🔥 КРИТИЧНО: Desktop ожидает полный data URL, а не просто Base64! // Добавляем префикс если его нет @@ -1951,7 +1892,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { } else { "data:image/png;base64,$avatarBlob" } - Log.d(TAG, "👤 Avatar data URL length: ${avatarDataUrl.length}") // Генерируем blurhash для preview (как на desktop) val avatarBlurhash = withContext(Dispatchers.IO) { @@ -1963,11 +1903,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { "" } } catch (e: Exception) { - Log.e(TAG, "Failed to generate blurhash for avatar: ${e.message}") "" } } - Log.d(TAG, "👤 Avatar blurhash generated: ${avatarBlurhash.take(20)}...") // 1. 🚀 Optimistic UI val optimisticMessage = ChatMessage( @@ -2001,7 +1939,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { // НЕ с AVATAR_PASSWORD! AVATAR_PASSWORD используется только для локального хранения // Используем avatarDataUrl (с префиксом data:image/...) а не avatarBlob! val encryptedAvatarBlob = MessageCrypto.encryptReplyBlob(avatarDataUrl, plainKeyAndNonce) - Log.d(TAG, "👤 Avatar encrypted with ChaCha key, length: ${encryptedAvatarBlob.length}") val avatarAttachmentId = "avatar_$timestamp" @@ -2011,18 +1948,14 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { if (!isSavedMessages) { try { - Log.d(TAG, "👤 📤 Uploading avatar to Transport Server...") uploadTag = TransportManager.uploadFile(avatarAttachmentId, encryptedAvatarBlob) - Log.d(TAG, "👤 📤 Upload complete, tag: $uploadTag") } catch (e: Exception) { - Log.e(TAG, "👤 ❌ Failed to upload avatar to Transport Server", e) throw e } } // Preview содержит tag::blurhash (как в desktop) val previewWithTag = if (uploadTag.isNotEmpty()) "$uploadTag::$avatarBlurhash" else avatarBlurhash - Log.d(TAG, "👤 Preview with tag: ${previewWithTag.take(50)}...") val avatarAttachment = MessageAttachment( id = avatarAttachmentId, @@ -2083,12 +2016,9 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { saveDialog("\$a=Avatar", timestamp) - Log.d(TAG, "👤 💾 Avatar message saved to database: messageId=$messageId") - Log.d(TAG, "👤 ✅ Avatar message sent successfully!") } catch (e: Exception) { - Log.e(TAG, "👤 ❌ Failed to send avatar message", e) withContext(Dispatchers.Main) { updateMessageStatus(messageId, MessageStatus.SENT) android.widget.Toast.makeText( @@ -2419,7 +2349,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { } } catch (e: Exception) { - android.util.Log.e(TAG, "Failed to clear chat history", e) } } } @@ -2437,7 +2366,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) { val bytes = Base64.decode(cleanBase64, Base64.DEFAULT) BitmapFactory.decodeByteArray(bytes, 0, bytes.size) } catch (e: Exception) { - Log.e(TAG, "Failed to decode base64 to bitmap: ${e.message}") null } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListViewModel.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListViewModel.kt index 73e9bc1..b1bd07b 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListViewModel.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatsListViewModel.kt @@ -127,7 +127,6 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio // 📁 НЕ загружаем для Saved Messages val isSavedMessages = (dialog.account == dialog.opponentKey) if (!isSavedMessages && (dialog.opponentTitle.isEmpty() || dialog.opponentTitle == dialog.opponentKey || dialog.opponentTitle == dialog.opponentKey.take(7))) { - android.util.Log.d("ChatsListVM", "🔍 Dialog needs user info: ${dialog.opponentKey.take(16)}... title='${dialog.opponentTitle}'") loadUserInfoForDialog(dialog.opponentKey) } @@ -166,12 +165,10 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio } else null } else null } catch (e: Exception) { - android.util.Log.e("ChatsListVM", "Failed to parse attachments", e) null } // 🔥 Лог для отладки - показываем и старые и новые значения - android.util.Log.d("ChatsListVM", "📊 Dialog ${dialog.opponentKey.take(16)}... | OLD: fromMe=${dialog.lastMessageFromMe}, del=${dialog.lastMessageDelivered}, read=${dialog.lastMessageRead} | NEW: fromMe=$actualFromMe, del=$actualDelivered, read=$actualRead | attachment=$attachmentType") DialogUiModel( id = dialog.id, @@ -212,13 +209,11 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio dialogDao.getRequestsFlow(publicKey) .flowOn(Dispatchers.IO) .map { requestsList -> - android.util.Log.d("ChatsListVM", "📬 getRequestsFlow emitted: ${requestsList.size} requests") requestsList.map { dialog -> // 🔥 Загружаем информацию о пользователе если её нет // 📁 НЕ загружаем для Saved Messages val isSavedMessages = (dialog.account == dialog.opponentKey) if (!isSavedMessages && (dialog.opponentTitle.isEmpty() || dialog.opponentTitle == dialog.opponentKey)) { - android.util.Log.d("ChatsListVM", "📬 Request needs user info: ${dialog.opponentKey.take(16)}... title='${dialog.opponentTitle}'") loadUserInfoForRequest(dialog.opponentKey) } @@ -250,7 +245,6 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio } else null } else null } catch (e: Exception) { - android.util.Log.e("ChatsListVM", "Failed to parse attachments in request", e) null } @@ -476,18 +470,15 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio private fun loadUserInfoForDialog(publicKey: String) { // 📁 Не запрашиваем информацию о самом себе (Saved Messages) if (publicKey == currentAccount) { - android.util.Log.d("ChatsListVM", "📁 Skipping loadUserInfoForDialog for Saved Messages") return } // 🔥 Не запрашиваем если уже запрашивали if (requestedUserInfoKeys.contains(publicKey)) { - android.util.Log.d("ChatsListVM", "⏭️ Skipping loadUserInfoForDialog - already requested for ${publicKey.take(16)}...") return } requestedUserInfoKeys.add(publicKey) - android.util.Log.d("ChatsListVM", "🔍 loadUserInfoForDialog: ${publicKey.take(16)}...") viewModelScope.launch(Dispatchers.IO) { try { @@ -499,7 +490,6 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio // 🔥 ВАЖНО: Используем хеш ключа, как в MessageRepository.requestUserInfo val privateKeyHash = CryptoManager.generatePrivateKeyHash(currentUserPrivateKey) - android.util.Log.d("ChatsListVM", "📤 Sending PacketSearch for user info: ${publicKey.take(16)}...") // Запрашиваем информацию о пользователе с сервера val packet = PacketSearch().apply { @@ -508,7 +498,6 @@ class ChatsListViewModel(application: Application) : AndroidViewModel(applicatio } ProtocolManager.send(packet) } catch (e: Exception) { - android.util.Log.e("ChatsListVM", "❌ loadUserInfoForRequest error: ${e.message}") } } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt index 98a7ed3..fbb2a62 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/SearchUsersViewModel.kt @@ -1,6 +1,5 @@ package com.rosetta.messenger.ui.chats -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.rosetta.messenger.network.PacketSearch @@ -48,43 +47,35 @@ class SearchUsersViewModel : ViewModel() { val currentQuery = lastSearchedText val responseSearch = packet.search - Log.d(TAG, "📥 PacketSearch received: ${packet.users.size} users, search='$responseSearch', ourQuery='$currentQuery'") // Принимаем ответ только если: // 1. search в ответе совпадает с нашим запросом, ИЛИ // 2. search пустой но мы ждём ответ (lastSearchedText не пустой) // НО: если search пустой и мы НЕ ждём ответ - игнорируем if (responseSearch.isEmpty() && currentQuery.isEmpty()) { - Log.d(TAG, "📥 Ignoring empty search response - no active search") return@handler } // Если search не пустой и не совпадает с нашим запросом - игнорируем if (responseSearch.isNotEmpty() && responseSearch != currentQuery) { - Log.d(TAG, "📥 Ignoring search response - search mismatch: '$responseSearch' != '$currentQuery'") return@handler } - Log.d(TAG, "📥 ACCEPTED PacketSearch response: ${packet.users.size} users") packet.users.forEachIndexed { index, user -> - Log.d(TAG, " [$index] publicKey=${user.publicKey.take(16)}... title=${user.title} username=${user.username}") } _searchResults.value = packet.users _isSearching.value = false - Log.d(TAG, "📥 Updated searchResults, isSearching=false") } } init { // Регистрируем обработчик пакетов поиска - Log.d(TAG, "🟢 INIT: Registering searchPacketHandler for 0x03") ProtocolManager.waitPacket(0x03, searchPacketHandler) } override fun onCleared() { super.onCleared() // Отписываемся от пакетов при уничтожении ViewModel - Log.d(TAG, "🔴 onCleared: Unregistering searchPacketHandler") ProtocolManager.unwaitPacket(0x03, searchPacketHandler) searchJob?.cancel() } @@ -101,7 +92,6 @@ class SearchUsersViewModel : ViewModel() { * Аналогично handleSearch в React Native */ fun onSearchQueryChange(query: String) { - Log.d(TAG, "🔍 onSearchQueryChange: query='$query' lastSearchedText='$lastSearchedText'") _searchQuery.value = query // Отменяем предыдущий поиск @@ -109,7 +99,6 @@ class SearchUsersViewModel : ViewModel() { // Если пустой запрос - очищаем результаты if (query.trim().isEmpty()) { - Log.d(TAG, "🔍 Empty query, clearing results") _searchResults.value = emptyList() _isSearching.value = false lastSearchedText = "" @@ -118,36 +107,30 @@ class SearchUsersViewModel : ViewModel() { // Если текст уже был найден - не повторяем поиск if (query == lastSearchedText) { - Log.d(TAG, "🔍 Query same as lastSearchedText, skipping") return } // Показываем индикатор загрузки _isSearching.value = true - Log.d(TAG, "🔍 Starting search job with 1s debounce") // Запускаем поиск с задержкой 1 секунда (как в React Native) searchJob = viewModelScope.launch { delay(1000) // debounce - Log.d(TAG, "🔍 After debounce: protocolState=${ProtocolManager.state.value}") // Проверяем состояние протокола if (ProtocolManager.state.value != ProtocolState.AUTHENTICATED) { - Log.d(TAG, "🔍 Protocol not authenticated, aborting") _isSearching.value = false return@launch } // Проверяем, не изменился ли запрос if (query != _searchQuery.value) { - Log.d(TAG, "🔍 Query changed during debounce, aborting") return@launch } lastSearchedText = query - Log.d(TAG, "📤 SENDING PacketSearch: query='$query' privateKeyHash=${privateKeyHash.take(16)}...") // Создаем и отправляем пакет поиска val packetSearch = PacketSearch().apply { @@ -156,7 +139,6 @@ class SearchUsersViewModel : ViewModel() { } ProtocolManager.sendPacket(packetSearch) - Log.d(TAG, "📤 PacketSearch sent!") } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/AttachmentComponents.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/AttachmentComponents.kt index bfc73c7..df74f6b 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/AttachmentComponents.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/AttachmentComponents.kt @@ -3,7 +3,6 @@ package com.rosetta.messenger.ui.chats.components import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Base64 -import android.util.Log import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.Image @@ -461,10 +460,6 @@ fun ImageAttachment( fillMaxSize: Boolean = false, onImageClick: (attachmentId: String) -> Unit = {} ) { - Log.d( - TAG, - "🖼️ ImageAttachment: id=${attachment.id}, isOutgoing=$isOutgoing, messageStatus=$messageStatus, showTimeOverlay=$showTimeOverlay" - ) val context = LocalContext.current val scope = rememberCoroutineScope() @@ -492,12 +487,10 @@ fun ImageAttachment( when { // 1. Если blob уже есть в памяти → DOWNLOADED attachment.blob.isNotEmpty() -> { - Log.d(TAG, "📦 Blob already in memory for ${attachment.id}") DownloadStatus.DOWNLOADED } // 2. Если preview НЕ содержит UUID → это наш локальный файл → DOWNLOADED !isDownloadTag(attachment.preview) -> { - Log.d(TAG, "📦 No download tag, local file for ${attachment.id}") DownloadStatus.DOWNLOADED } // 3. Есть UUID (download tag) → проверяем файловую систему @@ -511,10 +504,8 @@ fun ImageAttachment( senderPublicKey ) if (hasLocal) { - Log.d(TAG, "📦 Found local file for ${attachment.id}") DownloadStatus.DOWNLOADED } else { - Log.d(TAG, "📥 Need to download ${attachment.id}") DownloadStatus.NOT_DOWNLOADED } } @@ -525,25 +516,14 @@ fun ImageAttachment( if (preview.isNotEmpty() && !isDownloadTag(preview)) { withContext(Dispatchers.IO) { try { - Log.d( - TAG, - "🎨 Decoding blurhash: ${preview.take(30)}... (length: ${preview.length})" - ) blurhashBitmap = BlurHash.decode(preview, 200, 200) if (blurhashBitmap != null) { - Log.d(TAG, "✅ Blurhash decoded successfully") } else { - Log.w(TAG, "⚠️ Blurhash decode returned null") } } catch (e: Exception) { - Log.e(TAG, "❌ Failed to decode blurhash: ${e.message}", e) } } } else { - Log.d( - TAG, - "⚠️ No valid blurhash preview (preview='${preview.take(20)}...', isDownloadTag=${isDownloadTag(preview)})" - ) } // Загружаем изображение если статус DOWNLOADED @@ -551,11 +531,9 @@ fun ImageAttachment( withContext(Dispatchers.IO) { // 1. Сначала пробуем blob из памяти if (attachment.blob.isNotEmpty()) { - Log.d(TAG, "🖼️ Loading image from blob") imageBitmap = base64ToBitmap(attachment.blob) } else { // 2. Читаем из файловой системы (как в Desktop getBlob) - Log.d(TAG, "🖼️ Loading image from local file") val localBlob = AttachmentFileManager.readAttachment( context, @@ -565,9 +543,7 @@ fun ImageAttachment( ) if (localBlob != null) { imageBitmap = base64ToBitmap(localBlob) - Log.d(TAG, "✅ Image loaded from local file") } else { - Log.w(TAG, "⚠️ Failed to read local file, need to download") downloadStatus = DownloadStatus.NOT_DOWNLOADED } } @@ -580,34 +556,22 @@ fun ImageAttachment( scope.launch { try { downloadStatus = DownloadStatus.DOWNLOADING - Log.d(TAG, "=====================================") - Log.d(TAG, "📥 Starting IMAGE download") - Log.d(TAG, "📝 Attachment ID: ${attachment.id}") - Log.d(TAG, "🏷️ Download tag: $downloadTag") - Log.d(TAG, "👤 Sender public key: ${senderPublicKey.take(16)}...") - Log.d(TAG, "=====================================") // Скачиваем зашифрованный контент - Log.d(TAG, "⬇️ Downloading encrypted content from CDN...") val startTime = System.currentTimeMillis() val encryptedContent = TransportManager.downloadFile(attachment.id, downloadTag) val downloadTime = System.currentTimeMillis() - startTime - Log.d(TAG, "✅ Downloaded ${encryptedContent.length} chars in ${downloadTime}ms") downloadProgress = 0.5f downloadStatus = DownloadStatus.DECRYPTING - Log.d(TAG, "🔓 Starting decryption...") // КРИТИЧНО: chachaKey ЗАШИФРОВАН в БД (как в Desktop) // Сначала расшифровываем его, получаем raw bytes - Log.d(TAG, "🔑 Decrypting ChaCha key from sender...") val decryptedKeyAndNonce = MessageCrypto.decryptKeyFromSender(chachaKey, privateKey) - Log.d(TAG, "🔑 ChaCha key decrypted: ${decryptedKeyAndNonce.size} bytes") // Используем decryptAttachmentBlobWithPlainKey который правильно конвертирует // bytes в password - Log.d(TAG, "🔓 Decrypting image blob with PBKDF2...") val decryptStartTime = System.currentTimeMillis() val decrypted = MessageCrypto.decryptAttachmentBlobWithPlainKey( @@ -615,21 +579,13 @@ fun ImageAttachment( decryptedKeyAndNonce ) val decryptTime = System.currentTimeMillis() - decryptStartTime - Log.d(TAG, "🔓 Decryption completed in ${decryptTime}ms") downloadProgress = 0.8f if (decrypted != null) { - Log.d(TAG, "✅ Decrypted blob: ${decrypted.length} chars") withContext(Dispatchers.IO) { - Log.d(TAG, "🖼️ Converting to bitmap...") imageBitmap = base64ToBitmap(decrypted) - Log.d( - TAG, - "✅ Bitmap created: ${imageBitmap?.width}x${imageBitmap?.height}" - ) // 💾 Сохраняем в файловую систему (как в Desktop) - Log.d(TAG, "💾 Saving to local storage...") val saved = AttachmentFileManager.saveAttachment( context = context, @@ -638,32 +594,18 @@ fun ImageAttachment( publicKey = senderPublicKey, privateKey = privateKey ) - Log.d(TAG, "💾 Image saved to local storage: $saved") } downloadProgress = 1f downloadStatus = DownloadStatus.DOWNLOADED - Log.d(TAG, "=====================================") - Log.d(TAG, "✅ IMAGE DOWNLOAD COMPLETE") - Log.d(TAG, "=====================================") } else { - Log.e(TAG, "=====================================") - Log.e(TAG, "❌ DECRYPTION RETURNED NULL") - Log.e(TAG, "=====================================") downloadStatus = DownloadStatus.ERROR } } catch (e: Exception) { - Log.e(TAG, "=====================================") - Log.e(TAG, "❌ IMAGE DOWNLOAD FAILED") - Log.e(TAG, "📝 Attachment ID: ${attachment.id}") - Log.e(TAG, "🏷️ Download tag: $downloadTag") - Log.e(TAG, "❌ Error: ${e.message}") - Log.e(TAG, "=====================================") e.printStackTrace() downloadStatus = DownloadStatus.ERROR } } } else { - Log.w(TAG, "⚠️ Cannot download image: empty download tag for ${attachment.id}") } } @@ -982,7 +924,6 @@ fun FileAttachment( scope.launch { try { downloadStatus = DownloadStatus.DOWNLOADING - Log.d(TAG, "📥 Downloading file: $fileName") val encryptedContent = TransportManager.downloadFile(attachment.id, downloadTag) downloadProgress = 0.6f @@ -1005,12 +946,10 @@ fun FileAttachment( // TODO: Save to Downloads folder downloadProgress = 1f downloadStatus = DownloadStatus.DOWNLOADED - Log.d(TAG, "✅ File downloaded: $fileName") } else { downloadStatus = DownloadStatus.ERROR } } catch (e: Exception) { - Log.e(TAG, "❌ File download failed", e) downloadStatus = DownloadStatus.ERROR } } @@ -1221,12 +1160,10 @@ fun AvatarAttachment( when { // 1. Если blob уже есть в памяти → DOWNLOADED attachment.blob.isNotEmpty() -> { - Log.d(TAG, "📦 Avatar blob in memory for ${attachment.id}") DownloadStatus.DOWNLOADED } // 2. Если preview НЕ содержит UUID → локальный файл → DOWNLOADED !isDownloadTag(attachment.preview) -> { - Log.d(TAG, "📦 No download tag for avatar ${attachment.id}") DownloadStatus.DOWNLOADED } // 3. Есть UUID (download tag) → проверяем файловую систему @@ -1239,10 +1176,8 @@ fun AvatarAttachment( senderPublicKey ) if (hasLocal) { - Log.d(TAG, "📦 Found local avatar file for ${attachment.id}") DownloadStatus.DOWNLOADED } else { - Log.d(TAG, "📥 Need to download avatar ${attachment.id}") DownloadStatus.NOT_DOWNLOADED } } @@ -1255,7 +1190,6 @@ fun AvatarAttachment( try { blurhashBitmap = BlurHash.decode(preview, 100, 100) } catch (e: Exception) { - Log.e(TAG, "Failed to decode avatar blurhash: ${e.message}") } } } @@ -1265,11 +1199,9 @@ fun AvatarAttachment( withContext(Dispatchers.IO) { // 1. Сначала пробуем blob из памяти if (attachment.blob.isNotEmpty()) { - Log.d(TAG, "🖼️ Loading avatar from blob") avatarBitmap = base64ToBitmap(attachment.blob) } else { // 2. Читаем из файловой системы (как в Desktop getBlob) - Log.d(TAG, "🖼️ Loading avatar from local file") val localBlob = AvatarFileManager.readAvatarByAttachmentId( context, @@ -1278,9 +1210,7 @@ fun AvatarAttachment( ) if (localBlob != null) { avatarBitmap = base64ToBitmap(localBlob) - Log.d(TAG, "✅ Avatar loaded from local file") } else { - Log.w(TAG, "⚠️ Failed to read local avatar file") downloadStatus = DownloadStatus.NOT_DOWNLOADED } } @@ -1293,32 +1223,20 @@ fun AvatarAttachment( scope.launch { try { downloadStatus = DownloadStatus.DOWNLOADING - Log.d(TAG, "=====================================") - Log.d(TAG, "👤 Starting AVATAR download") - Log.d(TAG, "📝 Attachment ID: ${attachment.id}") - Log.d(TAG, "🏷️ Download tag: $downloadTag") - Log.d(TAG, "👤 Sender public key: ${senderPublicKey.take(16)}...") - Log.d(TAG, "=====================================") - Log.d(TAG, "⬇️ Downloading encrypted avatar from CDN...") val startTime = System.currentTimeMillis() val encryptedContent = TransportManager.downloadFile(attachment.id, downloadTag) val downloadTime = System.currentTimeMillis() - startTime - Log.d(TAG, "✅ Downloaded ${encryptedContent.length} chars in ${downloadTime}ms") downloadStatus = DownloadStatus.DECRYPTING - Log.d(TAG, "🔓 Starting decryption...") // КРИТИЧНО: chachaKey ЗАШИФРОВАН в БД (как в Desktop) // Сначала расшифровываем его, получаем raw bytes - Log.d(TAG, "🔑 Decrypting ChaCha key from sender...") val decryptedKeyAndNonce = MessageCrypto.decryptKeyFromSender(chachaKey, privateKey) - Log.d(TAG, "🔑 ChaCha key decrypted: ${decryptedKeyAndNonce.size} bytes") // Используем decryptAttachmentBlobWithPlainKey который правильно конвертирует // bytes в password - Log.d(TAG, "🔓 Decrypting avatar blob with PBKDF2...") val decryptStartTime = System.currentTimeMillis() val decrypted = MessageCrypto.decryptAttachmentBlobWithPlainKey( @@ -1326,21 +1244,13 @@ fun AvatarAttachment( decryptedKeyAndNonce ) val decryptTime = System.currentTimeMillis() - decryptStartTime - Log.d(TAG, "🔓 Decryption completed in ${decryptTime}ms") if (decrypted != null) { - Log.d(TAG, "✅ Decrypted blob: ${decrypted.length} chars") withContext(Dispatchers.IO) { - Log.d(TAG, "🖼️ Converting to bitmap...") avatarBitmap = base64ToBitmap(decrypted) - Log.d( - TAG, - "✅ Bitmap created: ${avatarBitmap?.width}x${avatarBitmap?.height}" - ) // 💾 Сохраняем в файловую систему по attachment.id (как в Desktop) // Desktop: writeFile(`a/${md5(attachment.id + publicKey)}`, encrypted) - Log.d(TAG, "💾 Saving avatar to file system by attachment ID...") val path = AvatarFileManager.saveAvatarByAttachmentId( context = context, @@ -1348,69 +1258,36 @@ fun AvatarAttachment( attachmentId = attachment.id, publicKey = senderPublicKey ) - Log.d(TAG, "💾 Avatar saved to: $path") } // Сохраняем аватар в репозиторий (для UI обновления) // Если это исходящее сообщение с аватаром, сохраняем для текущего // пользователя val targetPublicKey = if (isOutgoing && currentUserPublicKey.isNotEmpty()) { - Log.d( - TAG, - "💾 Saving avatar to repository for CURRENT user ${currentUserPublicKey.take(16)}..." - ) currentUserPublicKey } else { - Log.d( - TAG, - "💾 Saving avatar to repository for SENDER ${senderPublicKey.take(16)}..." - ) senderPublicKey } // ВАЖНО: ждем завершения сохранения в репозиторий if (avatarRepository != null) { try { - Log.d(TAG, "📤 Calling avatarRepository.saveAvatar()...") avatarRepository.saveAvatar(targetPublicKey, decrypted) - Log.d( - TAG, - "✅ Avatar saved to repository for ${targetPublicKey.take(16)}" - ) } catch (e: Exception) { - Log.e(TAG, "❌ Failed to save avatar to repository: ${e.message}", e) } } else { - Log.e( - TAG, - "❌ avatarRepository is NULL! Cannot save avatar for ${targetPublicKey.take(16)}" - ) } downloadStatus = DownloadStatus.DOWNLOADED - Log.d(TAG, "=====================================") - Log.d(TAG, "✅ AVATAR DOWNLOAD COMPLETE") - Log.d(TAG, "=====================================") } else { - Log.e(TAG, "=====================================") - Log.e(TAG, "❌ AVATAR DECRYPTION RETURNED NULL") - Log.e(TAG, "=====================================") downloadStatus = DownloadStatus.ERROR } } catch (e: Exception) { - Log.e(TAG, "=====================================") - Log.e(TAG, "❌ AVATAR DOWNLOAD FAILED") - Log.e(TAG, "📝 Attachment ID: ${attachment.id}") - Log.e(TAG, "🏷️ Download tag: $downloadTag") - Log.e(TAG, "👤 Sender: ${senderPublicKey.take(16)}...") - Log.e(TAG, "❌ Error: ${e.message}") - Log.e(TAG, "=====================================") e.printStackTrace() downloadStatus = DownloadStatus.ERROR } } } else { - Log.w(TAG, "⚠️ Cannot download avatar: empty download tag for ${attachment.id}") } } @@ -1690,7 +1567,6 @@ private fun base64ToBitmap(base64: String): Bitmap? { val bytes = Base64.decode(cleanBase64, Base64.DEFAULT) BitmapFactory.decodeByteArray(bytes, 0, bytes.size) } catch (e: Exception) { - Log.e(TAG, "Failed to decode base64 to bitmap: ${e.message}") null } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt index d08ec20..dc0fe5e 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt @@ -3,7 +3,6 @@ package com.rosetta.messenger.ui.chats.components import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Base64 -import android.util.Log import androidx.compose.animation.* import androidx.compose.animation.core.* import androidx.compose.foundation.ExperimentalFoundationApi @@ -817,7 +816,6 @@ fun ReplyBubble( imageBitmap = decoded } } catch (e: Exception) { - Log.e("ReplyBubble", "Failed to load image: ${e.message}") } } } @@ -1173,7 +1171,6 @@ fun ReplyImagePreview( fullImageBitmap = decoded } } catch (e: Exception) { - Log.e("ReplyImagePreview", "Failed to load full image: ${e.message}") } } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageEditorScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageEditorScreen.kt index 888862c..dd2528b 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageEditorScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageEditorScreen.kt @@ -6,7 +6,6 @@ import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri -import android.util.Log import android.widget.ImageView import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult @@ -692,18 +691,15 @@ private suspend fun saveEditedImage( saveSettings, object : PhotoEditor.OnSaveListener { override fun onSuccess(imagePath: String) { - Log.d(TAG, "Image saved to: $imagePath") onResult(Uri.fromFile(File(imagePath))) } override fun onFailure(exception: Exception) { - Log.e(TAG, "Failed to save image", exception) onResult(null) } } ) } catch (e: Exception) { - Log.e(TAG, "Error saving image", e) withContext(Dispatchers.Main) { onResult(null) } } } @@ -733,19 +729,16 @@ private suspend fun saveEditedImageSync(context: Context, photoEditor: PhotoEdit saveSettings, object : PhotoEditor.OnSaveListener { override fun onSuccess(imagePath: String) { - Log.d(TAG, "Image saved sync to: $imagePath") continuation.resume(Uri.fromFile(File(imagePath))) } override fun onFailure(exception: Exception) { - Log.e(TAG, "Failed to save image sync", exception) continuation.resume(null) } } ) } } catch (e: Exception) { - Log.e(TAG, "Error saving image sync", e) null } } @@ -829,7 +822,6 @@ private fun launchCrop( launcher.launch(intent) } catch (e: Exception) { - Log.e(TAG, "Error launching crop", e) } } @@ -952,7 +944,6 @@ fun MultiImageEditorScreen( photoEditors[page] = editor } } catch (e: Exception) { - Log.e(TAG, "Error loading image for page $page", e) } } } @@ -973,7 +964,6 @@ fun MultiImageEditorScreen( view.source.setImageBitmap(bitmap) } } catch (e: Exception) { - Log.e(TAG, "Error reloading image", e) } } } @@ -1297,7 +1287,6 @@ private fun AsyncImageLoader(uri: Uri, modifier: Modifier = Modifier) { bitmap = BitmapFactory.decodeStream(inputStream) inputStream?.close() } catch (e: Exception) { - Log.e(TAG, "Error loading image", e) } } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageViewerScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageViewerScreen.kt index 3df0af3..1d708bb 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageViewerScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ImageViewerScreen.kt @@ -3,7 +3,6 @@ package com.rosetta.messenger.ui.chats.components import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Base64 -import android.util.Log import androidx.activity.compose.BackHandler import androidx.compose.animation.* import androidx.compose.animation.core.* @@ -341,7 +340,6 @@ private fun ZoomableImage( previewBitmap = base64ToBitmapSafe(blurPart) } } catch (e: Exception) { - Log.e(TAG, "Failed to load preview: ${e.message}") } } } @@ -377,7 +375,6 @@ private fun ZoomableImage( // 3. Скачиваем с CDN val downloadTag = getDownloadTag(image.preview) if (downloadTag.isNotEmpty()) { - Log.d(TAG, "📥 Downloading image from CDN: ${image.attachmentId}") val encryptedContent = TransportManager.downloadFile(image.attachmentId, downloadTag) val decryptedKeyAndNonce = MessageCrypto.decryptKeyFromSender(image.chachaKey, privateKey) @@ -405,7 +402,6 @@ private fun ZoomableImage( } } catch (e: Exception) { - Log.e(TAG, "Failed to load image: ${e.message}", e) loadError = e.message } @@ -598,7 +594,6 @@ private fun base64ToBitmapSafe(base64String: String): Bitmap? { val decodedBytes = Base64.decode(cleanBase64, Base64.DEFAULT) BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size) } catch (e: Exception) { - Log.e(TAG, "Failed to decode base64 to bitmap: ${e.message}") null } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt index d7bcc3e..dcc9337 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/MediaPickerBottomSheet.kt @@ -7,7 +7,6 @@ import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.provider.MediaStore -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.* @@ -918,9 +917,7 @@ private suspend fun loadMediaItems(context: Context): List = withCont // Sort all items by date items.sortByDescending { it.dateModified } - Log.d(TAG, "📸 Loaded ${items.size} media items") } catch (e: Exception) { - Log.e(TAG, "❌ Failed to load media items", e) } items diff --git a/app/src/main/java/com/rosetta/messenger/ui/components/AvatarImage.kt b/app/src/main/java/com/rosetta/messenger/ui/components/AvatarImage.kt index bc85eda..e2c0762 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/components/AvatarImage.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/components/AvatarImage.kt @@ -68,20 +68,16 @@ fun AvatarImage( // Логируем для отладки LaunchedEffect(publicKey, avatars) { - android.util.Log.d("AvatarImage", "📸 publicKey=${publicKey.take(16)}... avatars=${avatars.size} repository=${avatarRepository != null}") } // Декодируем первый аватар LaunchedEffect(avatars) { bitmap = if (avatars.isNotEmpty()) { - android.util.Log.d("AvatarImage", "🔄 Decoding avatar for ${publicKey.take(16)}... base64 length=${avatars.first().base64Data?.length ?: 0}") withContext(Dispatchers.IO) { val result = AvatarFileManager.base64ToBitmap(avatars.first().base64Data) - android.util.Log.d("AvatarImage", "✅ Decoded bitmap for ${publicKey.take(16)}... result=${result != null} size=${result?.width}x${result?.height}") result } } else { - android.util.Log.d("AvatarImage", "⚠️ No avatars for ${publicKey.take(16)}...") null } } @@ -101,7 +97,6 @@ fun AvatarImage( ) { // Log what we're showing LaunchedEffect(bitmap) { - android.util.Log.d("AvatarImage", "🖼️ Showing for ${publicKey.take(16)}... bitmap=${bitmap != null}") } if (bitmap != null) { diff --git a/app/src/main/java/com/rosetta/messenger/ui/settings/OtherProfileScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/settings/OtherProfileScreen.kt index 7a0a0b9..c0cd9f3 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/settings/OtherProfileScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/settings/OtherProfileScreen.kt @@ -232,7 +232,6 @@ fun OtherProfileScreen( val account = viewModel.myPublicKey ?: return@launch database.dialogDao().deleteDialog(account, user.publicKey) } catch (e: Exception) { - android.util.Log.e("OtherProfileScreen", "Failed to delete dialog", e) } } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt index f812aac..c6ce241 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileScreen.kt @@ -4,7 +4,6 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.net.Uri -import android.util.Log import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -191,13 +190,11 @@ fun ProfileScreen( rememberLauncherForActivityResult( contract = ActivityResultContracts.StartActivityForResult() ) { result -> - Log.d(TAG, "✂️ Crop result: resultCode=${result.resultCode}") val croppedUri = ImageCropHelper.getCroppedImageUri(result) val error = ImageCropHelper.getCropError(result) if (croppedUri != null) { - Log.d(TAG, "✅ Cropped image URI: $croppedUri") scope.launch { try { // Читаем обрезанное изображение @@ -205,10 +202,8 @@ fun ProfileScreen( val imageBytes = inputStream?.readBytes() inputStream?.close() - Log.d(TAG, "📊 Cropped image bytes: ${imageBytes?.size ?: 0} bytes") if (imageBytes != null) { - Log.d(TAG, "🔄 Converting cropped image to PNG Base64...") val base64Png = withContext(Dispatchers.IO) { AvatarFileManager.imagePrepareForNetworkTransfer( @@ -217,12 +212,10 @@ fun ProfileScreen( ) } - Log.d(TAG, "✅ Converted to Base64: ${base64Png.length} chars") // Сохраняем аватар через репозиторий avatarRepository?.changeMyAvatar(base64Png) - Log.d(TAG, "🎉 Avatar update completed") android.widget.Toast.makeText( context, @@ -232,7 +225,6 @@ fun ProfileScreen( .show() } } catch (e: Exception) { - Log.e(TAG, "❌ Failed to process cropped avatar", e) android.widget.Toast.makeText( context, "Failed to update avatar: ${e.message}", @@ -242,7 +234,6 @@ fun ProfileScreen( } } } else if (error != null) { - Log.e(TAG, "❌ Crop error", error) android.widget.Toast.makeText( context, "Failed to crop image: ${error.message}", @@ -250,7 +241,6 @@ fun ProfileScreen( ) .show() } else { - Log.w(TAG, "⚠️ Crop cancelled") } } @@ -258,13 +248,11 @@ fun ProfileScreen( val imagePickerLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) { uri: Uri? -> - Log.d(TAG, "🖼️ Image picker result: uri=$uri") uri?.let { // Запускаем uCrop для обрезки val cropIntent = ImageCropHelper.createCropIntent(context, it, isDarkTheme) cropLauncher.launch(cropIntent) } - ?: Log.w(TAG, "⚠️ URI is null, image picker cancelled") } // Цвета в зависимости от темы @@ -749,20 +737,16 @@ private fun CollapsingProfileHeader( var avatarBitmap by remember(avatars) { mutableStateOf(null) } var dominantColor by remember { mutableStateOf(null) } - Log.d(TAG, "🎨 CollapsingProfileHeader: hasAvatar=$hasAvatar, avatars.size=${avatars.size}, dominantColor=$dominantColor") LaunchedEffect(avatars, publicKey) { - Log.d(TAG, "🎨 LaunchedEffect avatars: size=${avatars.size}, publicKey=${publicKey.take(8)}") if (avatars.isNotEmpty()) { val loadedBitmap = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) { AvatarFileManager.base64ToBitmap(avatars.first().base64Data) } avatarBitmap = loadedBitmap - Log.d(TAG, "🎨 Bitmap loaded: ${loadedBitmap?.width}x${loadedBitmap?.height}") // Извлекаем доминантный цвет из нижней части аватарки (где будет текст) loadedBitmap?.let { bitmap -> try { - Log.d(TAG, "🎨 Extracting color from bitmap ${bitmap.width}x${bitmap.height}") // Берем нижнюю треть изображения для более точного определения val bottomThird = android.graphics.Bitmap.createBitmap( @@ -772,20 +756,15 @@ private fun CollapsingProfileHeader( bitmap.width, (bitmap.height / 3).coerceAtLeast(1) ) - Log.d(TAG, "🎨 Bottom third: ${bottomThird.width}x${bottomThird.height}") val palette = AndroidPalette.from(bottomThird).generate() - Log.d(TAG, "🎨 Palette generated, dominantSwatch=${palette.dominantSwatch}, mutedSwatch=${palette.mutedSwatch}") // Используем доминантный цвет или muted swatch val swatch = palette.dominantSwatch ?: palette.mutedSwatch if (swatch != null) { val extractedColor = Color(swatch.rgb) - Log.d(TAG, "🎨 Extracted dominant color: R=${extractedColor.red}, G=${extractedColor.green}, B=${extractedColor.blue}, isLight=${isColorLight(extractedColor)}") dominantColor = extractedColor } else { - Log.w(TAG, "🎨 No swatch found in palette!") } } catch (e: Exception) { - Log.e(TAG, "Failed to extract dominant color: ${e.message}", e) } } } else { @@ -799,7 +778,6 @@ private fun CollapsingProfileHeader( derivedStateOf { if (hasAvatar && dominantColor != null) { val isLight = isColorLight(dominantColor!!) - Log.d(TAG, "🎨 Text color: hasAvatar=$hasAvatar, dominantColor=$dominantColor, isLight=$isLight") if (isLight) Color.Black else Color.White } else { if (isColorLight(avatarColors.backgroundColor)) Color.Black else Color.White diff --git a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileViewModel.kt b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileViewModel.kt index 38fca04..4582fdc 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileViewModel.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/settings/ProfileViewModel.kt @@ -1,7 +1,6 @@ package com.rosetta.messenger.ui.settings import android.app.Application -import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.rosetta.messenger.data.AccountManager @@ -52,7 +51,6 @@ class ProfileViewModel(application: Application) : AndroidViewModel(application) val timestamp = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.getDefault()).format(java.util.Date()) val logMessage = "[$timestamp] $message" _state.value = _state.value.copy(logs = _state.value.logs + logMessage) - Log.d("ProfileViewModel", logMessage) } /** @@ -99,15 +97,10 @@ class ProfileViewModel(application: Application) : AndroidViewModel(application) addLog(" - privateKey: ${privateKeyHash.take(16)}... (length: ${privateKeyHash.length})") // CRITICAL: Log full packet data for debugging - Log.d("ProfileViewModel", "📤 SENDING PacketUserInfo:") - Log.d("ProfileViewModel", " username='$username' (${username.length} chars)") - Log.d("ProfileViewModel", " title='$actualTitle' (${actualTitle.length} chars)") - Log.d("ProfileViewModel", " privateKey='${privateKeyHash.take(32)}...' (${privateKeyHash.length} chars)") addLog("Sending packet to server...") ProtocolManager.send(packet) addLog("Packet sent successfully") - Log.d("ProfileViewModel", "✅ Packet sent to ProtocolManager") addLog("Waiting for PacketResult (0x02) from server...") // Set timeout for server response @@ -135,7 +128,6 @@ class ProfileViewModel(application: Application) : AndroidViewModel(application) // Wait for response (handled in handlePacketResult) } catch (e: Exception) { - Log.e("ProfileViewModel", "Error saving profile", e) addLog("❌ ERROR: ${e.message}") _state.value = _state.value.copy( isSaving = false, @@ -191,9 +183,7 @@ class ProfileViewModel(application: Application) : AndroidViewModel(application) try { accountManager.updateAccountName(publicKey, name) accountManager.updateAccountUsername(publicKey, username) - Log.d("ProfileViewModel", "Local profile updated: name=$name, username=$username") } catch (e: Exception) { - Log.e("ProfileViewModel", "Error updating local profile", e) } } } diff --git a/app/src/main/java/com/rosetta/messenger/utils/AttachmentFileManager.kt b/app/src/main/java/com/rosetta/messenger/utils/AttachmentFileManager.kt index 38701ad..0d055f9 100644 --- a/app/src/main/java/com/rosetta/messenger/utils/AttachmentFileManager.kt +++ b/app/src/main/java/com/rosetta/messenger/utils/AttachmentFileManager.kt @@ -1,7 +1,6 @@ package com.rosetta.messenger.utils import android.content.Context -import android.util.Log import com.rosetta.messenger.crypto.CryptoManager import java.io.File import java.security.MessageDigest @@ -53,12 +52,10 @@ object AttachmentFileManager { ): Boolean { return try { if (blob.isEmpty()) { - Log.w(TAG, "💾 Empty blob, skipping save") return false } val filePath = generatePath(attachmentId, publicKey) - Log.d(TAG, "💾 Saving attachment: $attachmentId -> $filePath") // Шифруем данные приватным ключом (как в desktop) val encrypted = CryptoManager.encryptWithPassword(blob, privateKey) @@ -73,7 +70,6 @@ object AttachmentFileManager { subDir.mkdirs() val file = File(subDir, parts[1]) file.writeText(encrypted) - Log.d(TAG, "💾 Saved to: ${file.absolutePath} (${encrypted.length} bytes)") } else { val file = File(dir, filePath) file.writeText(encrypted) @@ -81,7 +77,6 @@ object AttachmentFileManager { true } catch (e: Exception) { - Log.e(TAG, "❌ Error saving attachment", e) false } } @@ -106,17 +101,14 @@ object AttachmentFileManager { val file = File(dir, filePath) if (!file.exists()) { - Log.d(TAG, "📖 File not found: $filePath") return null } val encrypted = file.readText() val decrypted = CryptoManager.decryptWithPassword(encrypted, privateKey) - Log.d(TAG, "📖 Read attachment: $attachmentId (${decrypted?.length ?: 0} bytes)") decrypted } catch (e: Exception) { - Log.e(TAG, "❌ Error reading attachment", e) null } } @@ -153,7 +145,6 @@ object AttachmentFileManager { true } } catch (e: Exception) { - Log.e(TAG, "❌ Error deleting attachment", e) false } } @@ -165,10 +156,8 @@ object AttachmentFileManager { return try { val dir = File(context.filesDir, ATTACHMENTS_DIR) dir.deleteRecursively() - Log.d(TAG, "🗑️ Cache cleared") true } catch (e: Exception) { - Log.e(TAG, "❌ Error clearing cache", e) false } } diff --git a/app/src/main/java/com/rosetta/messenger/utils/AvatarFileManager.kt b/app/src/main/java/com/rosetta/messenger/utils/AvatarFileManager.kt index ff6d341..3c70b38 100644 --- a/app/src/main/java/com/rosetta/messenger/utils/AvatarFileManager.kt +++ b/app/src/main/java/com/rosetta/messenger/utils/AvatarFileManager.kt @@ -36,23 +36,16 @@ object AvatarFileManager { * @return Путь к файлу (формат: "a/md5hash") */ fun saveAvatar(context: Context, base64Image: String, entityId: String): String { - android.util.Log.d("AvatarFileManager", "💾 saveAvatar called") - android.util.Log.d("AvatarFileManager", "📊 Base64 length: ${base64Image.length}") - android.util.Log.d("AvatarFileManager", "👤 Entity ID: ${entityId.take(16)}...") // Генерируем путь как в desktop версии val filePath = generateMd5Path(base64Image, entityId) - android.util.Log.d("AvatarFileManager", "🔗 Generated file path: $filePath") // Шифруем данные с паролем "rosetta-a" - android.util.Log.d("AvatarFileManager", "🔐 Encrypting with password...") val encrypted = CryptoManager.encryptWithPassword(base64Image, AVATAR_PASSWORD) - android.util.Log.d("AvatarFileManager", "✅ Encrypted length: ${encrypted.length}") // Сохраняем в файловую систему val dir = File(context.filesDir, AVATAR_DIR) dir.mkdirs() - android.util.Log.d("AvatarFileManager", "📁 Base dir: ${dir.absolutePath}") // Путь формата "a/md5hash" -> создаем подпапку "a" val parts = filePath.split("/") @@ -61,14 +54,11 @@ object AvatarFileManager { subDir.mkdirs() val file = File(subDir, parts[1]) file.writeText(encrypted) - android.util.Log.d("AvatarFileManager", "💾 Saved to: ${file.absolutePath}") } else { val file = File(dir, filePath) file.writeText(encrypted) - android.util.Log.d("AvatarFileManager", "💾 Saved to: ${file.absolutePath}") } - android.util.Log.d("AvatarFileManager", "✅ Avatar saved successfully") return filePath } @@ -163,7 +153,6 @@ object AvatarFileManager { subDir.mkdirs() val file = File(subDir, parts[1]) file.writeText(encrypted) - android.util.Log.d("AvatarFileManager", "💾 Avatar saved to: ${file.absolutePath}") } return path @@ -232,19 +221,14 @@ object AvatarFileManager { return try { // Check for data URI prefix val actualBase64 = if (base64.contains(",")) { - android.util.Log.d("AvatarFileManager", "🔍 Removing data URI prefix, orig len=${base64.length}") base64.substringAfter(",") } else { base64 } - android.util.Log.d("AvatarFileManager", "🔍 Decoding base64, len=${actualBase64.length}, prefix=${actualBase64.take(50)}") val imageBytes = Base64.decode(actualBase64, Base64.NO_WRAP) - android.util.Log.d("AvatarFileManager", "🔍 Decoded bytes=${imageBytes.size}") val bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) - android.util.Log.d("AvatarFileManager", "🔍 Bitmap result=${bitmap != null}, size=${bitmap?.width}x${bitmap?.height}") bitmap } catch (e: Exception) { - android.util.Log.e("AvatarFileManager", "❌ base64ToBitmap error: ${e.message}") null } } diff --git a/app/src/main/java/com/rosetta/messenger/utils/CrashReportManager.kt b/app/src/main/java/com/rosetta/messenger/utils/CrashReportManager.kt index 38be667..8e1a485 100644 --- a/app/src/main/java/com/rosetta/messenger/utils/CrashReportManager.kt +++ b/app/src/main/java/com/rosetta/messenger/utils/CrashReportManager.kt @@ -2,7 +2,6 @@ package com.rosetta.messenger.utils import android.content.Context import android.os.Build -import android.util.Log import java.io.File import java.io.PrintWriter import java.io.StringWriter @@ -34,7 +33,6 @@ class CrashReportManager private constructor(private val context: Context) : Thr if (INSTANCE == null) { INSTANCE = CrashReportManager(context.applicationContext) Thread.setDefaultUncaughtExceptionHandler(INSTANCE) - Log.d(TAG, "Crash reporter initialized") } } } @@ -87,7 +85,6 @@ class CrashReportManager private constructor(private val context: Context) : Thr try { saveCrashReport(thread, throwable) } catch (e: Exception) { - Log.e(TAG, "Error saving crash report", e) } // Вызываем дефолтный handler (чтобы система тоже обработала краш) @@ -111,7 +108,6 @@ class CrashReportManager private constructor(private val context: Context) : Thr val report = buildCrashReport(thread, throwable) crashFile.writeText(report) - Log.d(TAG, "Crash report saved: $fileName") // Удаляем старые файлы если их слишком много cleanupOldCrashFiles(crashDir) @@ -199,7 +195,6 @@ class CrashReportManager private constructor(private val context: Context) : Thr if (files.size > MAX_CRASH_FILES) { files.drop(MAX_CRASH_FILES).forEach { file -> file.delete() - Log.d(TAG, "Deleted old crash file: ${file.name}") } } } diff --git a/app/src/main/java/com/rosetta/messenger/utils/MediaUtils.kt b/app/src/main/java/com/rosetta/messenger/utils/MediaUtils.kt index 91f48b6..8828a36 100644 --- a/app/src/main/java/com/rosetta/messenger/utils/MediaUtils.kt +++ b/app/src/main/java/com/rosetta/messenger/utils/MediaUtils.kt @@ -5,7 +5,6 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri import android.util.Base64 -import android.util.Log import com.vanniktech.blurhash.BlurHash import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -33,7 +32,6 @@ object MediaUtils { */ suspend fun uriToBase64Image(context: Context, uri: Uri): String? = withContext(Dispatchers.IO) { try { - Log.d(TAG, "📸 Converting image to Base64: $uri") // Открываем InputStream val inputStream: InputStream = context.contentResolver.openInputStream(uri) @@ -44,11 +42,9 @@ object MediaUtils { inputStream.close() if (originalBitmap == null) { - Log.e(TAG, "📸 Failed to decode image") return@withContext null } - Log.d(TAG, "📸 Original size: ${originalBitmap.width}x${originalBitmap.height}") // Масштабируем если слишком большое val scaledBitmap = scaleDownBitmap(originalBitmap, MAX_IMAGE_SIZE) @@ -56,7 +52,6 @@ object MediaUtils { originalBitmap.recycle() } - Log.d(TAG, "📸 Scaled size: ${scaledBitmap.width}x${scaledBitmap.height}") // Конвертируем в PNG Base64 val outputStream = ByteArrayOutputStream() @@ -67,10 +62,8 @@ object MediaUtils { scaledBitmap.recycle() - Log.d(TAG, "📸 ✅ Image converted to Base64, length: ${base64.length}") base64 } catch (e: Exception) { - Log.e(TAG, "📸 ❌ Failed to convert image to Base64", e) null } } @@ -80,7 +73,6 @@ object MediaUtils { */ suspend fun generateBlurhash(context: Context, uri: Uri): String = withContext(Dispatchers.IO) { try { - Log.d(TAG, "🎨 Generating blurhash for: $uri") val inputStream = context.contentResolver.openInputStream(uri) ?: return@withContext "" @@ -93,7 +85,6 @@ object MediaUtils { inputStream.close() if (bitmap == null) { - Log.e(TAG, "🎨 Failed to decode image for blurhash") return@withContext "" } @@ -101,10 +92,8 @@ object MediaUtils { val blurhash = BlurHash.encode(bitmap, 4, 3) bitmap.recycle() - Log.d(TAG, "🎨 ✅ Blurhash generated: $blurhash") blurhash ?: "" } catch (e: Exception) { - Log.e(TAG, "🎨 ❌ Failed to generate blurhash", e) "" } } @@ -114,7 +103,6 @@ object MediaUtils { */ suspend fun uriToBase64File(context: Context, uri: Uri): String? = withContext(Dispatchers.IO) { try { - Log.d(TAG, "📄 Converting file to Base64: $uri") val inputStream = context.contentResolver.openInputStream(uri) ?: return@withContext null @@ -124,10 +112,8 @@ object MediaUtils { val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP) - Log.d(TAG, "📄 ✅ File converted to Base64, length: ${base64.length}") base64 } catch (e: Exception) { - Log.e(TAG, "📄 ❌ Failed to convert file to Base64", e) null } } @@ -158,7 +144,6 @@ object MediaUtils { } } } catch (e: Exception) { - Log.e(TAG, "Failed to get file name", e) } return name } @@ -212,7 +197,6 @@ object MediaUtils { } hash ?: "" } catch (e: Exception) { - Log.e(TAG, "Failed to generate blurhash from bitmap", e) "" } } @@ -244,10 +228,8 @@ object MediaUtils { } } - Log.d(TAG, "📐 Image dimensions: ${width}x${height}") Pair(width, height) } catch (e: Exception) { - Log.e(TAG, "📐 Failed to get image dimensions", e) Pair(0, 0) } } @@ -270,10 +252,8 @@ object MediaUtils { } BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options) - Log.d(TAG, "📐 Image dimensions from base64: ${options.outWidth}x${options.outHeight}") Pair(options.outWidth, options.outHeight) } catch (e: Exception) { - Log.e(TAG, "📐 Failed to get image dimensions from base64", e) Pair(0, 0) } }