feat: Enhance image attachment handling with local file management and download status logic

This commit is contained in:
k1ngsterr1
2026-01-27 19:05:50 +05:00
parent c2b7dab5f1
commit 3ef61700b3

View File

@@ -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<MessageAttachment>,
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