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 792f5bb..367c709 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 @@ -977,53 +977,76 @@ private fun ZoomableImage( * 2) из локального encrypted attachment файла * 3) с transport (с последующим сохранением в локальный файл) */ +private fun viewerLog(context: Context, msg: String) { + try { + val ts = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.getDefault()).format(java.util.Date()) + val dir = java.io.File(context.filesDir, "crash_reports") + if (!dir.exists()) dir.mkdirs() + java.io.File(dir, "rosettadev1.txt").appendText("$ts [Viewer] $msg\n") + } catch (_: Exception) {} +} + private suspend fun loadBitmapForViewerImage( context: Context, image: ViewableImage, privateKey: String ): Bitmap? { + val id = image.attachmentId.take(10) + viewerLog(context, "=== LOAD id=$id blob=${image.blob.length} preview=${image.preview.length} chacha=${image.chachaKey.length} tag=${image.transportTag.take(12)} sender=${image.senderPublicKey.take(12)} ===") return try { // 0. In-memory кэш val cached = ImageBitmapCache.get("img_${image.attachmentId}") if (cached != null) { + viewerLog(context, " [0] HIT cache ${cached.width}x${cached.height}") return cached } + viewerLog(context, " [0] MISS cache") // 1. Blob в сообщении if (image.blob.isNotEmpty()) { + viewerLog(context, " [1] blob ${image.blob.length} chars") val bmp = base64ToBitmapSafe(image.blob) - if (bmp != null) { - return bmp - } + if (bmp != null) { viewerLog(context, " [1] OK ${bmp.width}x${bmp.height}"); return bmp } + viewerLog(context, " [1] decode FAIL") } // 2. Локальный encrypted cache + viewerLog(context, " [2] readAttachment sender=${image.senderPublicKey.take(12)}") val localBlob = AttachmentFileManager.readAttachment(context, image.attachmentId, image.senderPublicKey, privateKey) if (localBlob != null) { + viewerLog(context, " [2] local ${localBlob.length} chars") val bmp = base64ToBitmapSafe(localBlob) - if (bmp != null) { - return bmp - } - } + if (bmp != null) { viewerLog(context, " [2] OK ${bmp.width}x${bmp.height}"); return bmp } + viewerLog(context, " [2] decode FAIL") + } else { viewerLog(context, " [2] NOT found") } // 2.5. Ждём bitmap из кеша + viewerLog(context, " [2.5] await 3s...") val awaitedFromCache = ImageBitmapCache.awaitCached("img_${image.attachmentId}", 3000) if (awaitedFromCache != null) { + viewerLog(context, " [2.5] OK ${awaitedFromCache.width}x${awaitedFromCache.height}") return awaitedFromCache } + viewerLog(context, " [2.5] timeout") // 3. CDN download var downloadTag = getDownloadTag(image.preview) if (downloadTag.isEmpty() && image.transportTag.isNotEmpty()) { downloadTag = image.transportTag } + viewerLog(context, " [3] tag=${downloadTag.take(12)} preview=${image.preview.take(20)}") if (downloadTag.isEmpty()) { + viewerLog(context, " [3] NO TAG → FAIL") return null } + val server = TransportManager.getTransportServer() ?: "none" + viewerLog(context, " [3] downloading from $server") val encryptedContent = TransportManager.downloadFile(image.attachmentId, downloadTag) + viewerLog(context, " [3] downloaded ${encryptedContent.length} bytes") if (encryptedContent.isEmpty()) { + viewerLog(context, " [3] EMPTY → FAIL") return null } @@ -1045,11 +1068,14 @@ private suspend fun loadBitmapForViewerImage( null } + viewerLog(context, " [3] decrypt=${if (decrypted != null) "${decrypted.length} chars" else "NULL"} method=${when { image.chachaKeyPlainHex.isNotEmpty() -> "plainHex"; image.chachaKey.startsWith("group:") -> "group"; image.chachaKey.isNotEmpty() -> "chacha"; else -> "none" }}") if (decrypted == null) { + viewerLog(context, " [3] DECRYPT FAIL") return null } val decodedBitmap = base64ToBitmapSafe(decrypted) + viewerLog(context, " [3] bitmap=${if (decodedBitmap != null) "${decodedBitmap.width}x${decodedBitmap.height}" else "NULL"}") if (decodedBitmap == null) { return null } @@ -1062,8 +1088,10 @@ private suspend fun loadBitmapForViewerImage( publicKey = image.senderPublicKey, privateKey = privateKey ) + viewerLog(context, " DONE OK") decodedBitmap } catch (e: Exception) { + viewerLog(context, " EXCEPTION: ${e.javaClass.simpleName}: ${e.message}") 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 a0f553c..f224484 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 @@ -342,7 +342,9 @@ fun OtherProfileScreen( timestamp = Date(media.timestamp), width = media.width, height = media.height, - caption = media.caption + caption = media.caption, + transportTag = media.transportTag, + transportServer = media.transportServer ) } } @@ -1211,7 +1213,9 @@ private data class SharedPhotoItem( val width: Int, val height: Int, val caption: String, - val timestamp: Long + val timestamp: Long, + val transportTag: String = "", + val transportServer: String = "" ) private data class SharedFileItem( @@ -1292,7 +1296,9 @@ private suspend fun buildOtherProfileSharedContent( width = attachment.width, height = attachment.height, caption = decryptedText, - timestamp = message.timestamp + timestamp = message.timestamp, + transportTag = attachment.transportTag, + transportServer = attachment.transportServer ) mediaPhotos.add(mediaItem)