fix(android): skip reactions for temp messages and fallback gif upload
Some checks failed
Android CI / android (push) Has started running
Android Release / release (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
Codex
2026-03-10 21:06:07 +03:00
parent 27fba86915
commit 3844875d36
2 changed files with 52 additions and 1 deletions

View File

@@ -2,6 +2,8 @@ package ru.daemonlord.messenger.data.media.repository
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Movie
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@@ -96,7 +98,26 @@ class NetworkMediaRepository @Inject constructor(
return UploadPayload(fileName = fileName, mimeType = mimeType, bytes = bytes) return UploadPayload(fileName = fileName, mimeType = mimeType, bytes = bytes)
} }
if (mimeType.equals("image/gif", ignoreCase = true)) { if (mimeType.equals("image/gif", ignoreCase = true)) {
return UploadPayload(fileName = fileName, mimeType = mimeType, bytes = bytes) val still = gifToPngPayload(fileName = fileName, bytes = bytes)
if (still != null) return still
val bitmapFallback = runCatching { BitmapFactory.decodeByteArray(bytes, 0, bytes.size) }.getOrNull()
if (bitmapFallback != null) {
val output = ByteArrayOutputStream()
val compressed = bitmapFallback.compress(Bitmap.CompressFormat.PNG, 100, output)
bitmapFallback.recycle()
if (compressed) {
val pngBytes = output.toByteArray()
if (pngBytes.isNotEmpty()) {
val baseName = fileName.substringBeforeLast('.').ifBlank { "gif" }
return UploadPayload(
fileName = "${baseName}-still.png",
mimeType = "image/png",
bytes = pngBytes,
)
}
}
}
return UploadPayload(fileName = fileName, mimeType = "application/octet-stream", bytes = bytes)
} }
val source = runCatching { BitmapFactory.decodeByteArray(bytes, 0, bytes.size) }.getOrNull() val source = runCatching { BitmapFactory.decodeByteArray(bytes, 0, bytes.size) }.getOrNull()
?: return UploadPayload(fileName = fileName, mimeType = mimeType, bytes = bytes) ?: return UploadPayload(fileName = fileName, mimeType = mimeType, bytes = bytes)
@@ -140,4 +161,32 @@ class NetworkMediaRepository @Inject constructor(
val mimeType: String, val mimeType: String,
val bytes: ByteArray, val bytes: ByteArray,
) )
private fun gifToPngPayload(
fileName: String,
bytes: ByteArray,
): UploadPayload? {
val movie = runCatching { Movie.decodeByteArray(bytes, 0, bytes.size) }.getOrNull() ?: return null
val width = movie.width().coerceAtLeast(1)
val height = movie.height().coerceAtLeast(1)
val bitmap = runCatching { Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) }.getOrNull() ?: return null
return try {
val canvas = Canvas(bitmap)
movie.setTime(0)
movie.draw(canvas, 0f, 0f)
val output = ByteArrayOutputStream()
val compressed = bitmap.compress(Bitmap.CompressFormat.PNG, 100, output)
if (!compressed) return null
val pngBytes = output.toByteArray()
if (pngBytes.isEmpty()) return null
val baseName = fileName.substringBeforeLast('.').ifBlank { "gif" }
UploadPayload(
fileName = "${baseName}-still.png",
mimeType = "image/png",
bytes = pngBytes,
)
} finally {
bitmap.recycle()
}
}
} }

View File

@@ -650,6 +650,7 @@ class ChatViewModel @Inject constructor(
} }
private fun loadReactions(messageId: Long) { private fun loadReactions(messageId: Long) {
if (messageId <= 0L) return
viewModelScope.launch { viewModelScope.launch {
when (val result = listMessageReactionsUseCase(messageId = messageId)) { when (val result = listMessageReactionsUseCase(messageId = messageId)) {
is AppResult.Success -> { is AppResult.Success -> {
@@ -666,6 +667,7 @@ class ChatViewModel @Inject constructor(
val toRequest = messages val toRequest = messages
.asReversed() .asReversed()
.map { it.id } .map { it.id }
.filter { it > 0L }
.filter { reactionsRequestedMessageIds.add(it) } .filter { reactionsRequestedMessageIds.add(it) }
if (toRequest.isEmpty()) return if (toRequest.isEmpty()) return