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 5196866..a1002c2 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 @@ -45,6 +45,7 @@ import com.rosetta.messenger.R import com.rosetta.messenger.repository.AvatarRepository import com.rosetta.messenger.ui.chats.models.MessageStatus import com.rosetta.messenger.ui.onboarding.PrimaryBlue +import com.rosetta.messenger.utils.AttachmentFileManager import com.rosetta.messenger.utils.AvatarFileManager import com.vanniktech.blurhash.BlurHash import kotlinx.coroutines.Dispatchers @@ -98,6 +99,7 @@ fun MessageAttachments( attachments = imageAttachments, chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -152,6 +154,7 @@ fun ImageCollage( attachments: List, chachaKey: String, privateKey: String, + senderPublicKey: String, isOutgoing: Boolean, isDarkTheme: Boolean, timestamp: java.util.Date, @@ -175,6 +178,7 @@ fun ImageCollage( attachment = attachments[0], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -194,6 +198,7 @@ fun ImageCollage( attachment = attachment, chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -219,6 +224,7 @@ fun ImageCollage( attachment = attachments[0], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -237,6 +243,7 @@ fun ImageCollage( attachment = attachments[1], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -250,6 +257,7 @@ fun ImageCollage( attachment = attachments[2], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -276,6 +284,7 @@ fun ImageCollage( attachment = attachments[0], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -289,6 +298,7 @@ fun ImageCollage( attachment = attachments[1], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -307,6 +317,7 @@ fun ImageCollage( attachment = attachments[2], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -320,6 +331,7 @@ fun ImageCollage( attachment = attachments[3], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -347,6 +359,7 @@ fun ImageCollage( attachment = attachments[0], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -360,6 +373,7 @@ fun ImageCollage( attachment = attachments[1], chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -384,6 +398,7 @@ fun ImageCollage( attachment = attachment, chachaKey = chachaKey, privateKey = privateKey, + senderPublicKey = senderPublicKey, isOutgoing = isOutgoing, isDarkTheme = isDarkTheme, timestamp = timestamp, @@ -407,12 +422,19 @@ fun ImageCollage( /** * Image attachment - Telegram style с blurhash placeholder + * + * Логика определения статуса (как в Desktop): + * 1. Если preview НЕ содержит UUID → это локальный файл → DOWNLOADED + * 2. Если есть UUID (download tag) → проверяем файловую систему через AttachmentFileManager + * 3. Если файл есть локально → DOWNLOADED (загружаем из файла) + * 4. Иначе → NOT_DOWNLOADED (нужно скачать с CDN) */ @Composable fun ImageAttachment( attachment: MessageAttachment, chachaKey: String, privateKey: String, + senderPublicKey: String, isOutgoing: Boolean, isDarkTheme: Boolean, timestamp: java.util.Date, @@ -439,19 +461,36 @@ fun ImageAttachment( label = "progress" ) - // Определяем начальный статус и декодируем blurhash + // Определяем начальный статус и декодируем blurhash (как в Desktop calcDownloadStatus) LaunchedEffect(attachment.id) { - // Определяем статус - downloadStatus = when { - attachment.blob.isNotEmpty() && !isDownloadTag(attachment.preview) -> { - // Blob уже есть в сообщении (локальный файл) - DownloadStatus.DOWNLOADED + // Определяем статус (логика из Desktop useAttachment.ts) + withContext(Dispatchers.IO) { + downloadStatus = 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) → проверяем файловую систему + else -> { + // Проверяем есть ли файл локально (как в Desktop: readFile(`m/${md5hash}`)) + val hasLocal = AttachmentFileManager.hasAttachment( + context, attachment.id, 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 + } + } } - isDownloadTag(attachment.preview) -> { - // Нужно скачать с CDN - DownloadStatus.NOT_DOWNLOADED - } - else -> DownloadStatus.DOWNLOADED } // Декодируем blurhash для placeholder (если есть) @@ -473,10 +512,27 @@ fun ImageAttachment( Log.d(TAG, "⚠️ No valid blurhash preview (preview='${preview.take(20)}...', isDownloadTag=${isDownloadTag(preview)})") } - // Декодируем изображение если уже скачано - if (downloadStatus == DownloadStatus.DOWNLOADED && attachment.blob.isNotEmpty()) { + // Загружаем изображение если статус DOWNLOADED + if (downloadStatus == DownloadStatus.DOWNLOADED) { withContext(Dispatchers.IO) { - imageBitmap = base64ToBitmap(attachment.blob) + // 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, attachment.id, senderPublicKey, privateKey + ) + 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 + } + } } } } @@ -511,6 +567,16 @@ fun ImageAttachment( if (decrypted != null) { withContext(Dispatchers.IO) { imageBitmap = base64ToBitmap(decrypted) + + // 💾 Сохраняем в файловую систему (как в Desktop) + AttachmentFileManager.saveAttachment( + context = context, + blob = decrypted, + attachmentId = attachment.id, + publicKey = senderPublicKey, + privateKey = privateKey + ) + Log.d(TAG, "💾 Image saved to local storage") } downloadProgress = 1f downloadStatus = DownloadStatus.DOWNLOADED