fix: improve avatar loading and rendering logic to prevent flickering and enhance performance

This commit is contained in:
2026-02-04 04:39:38 +05:00
parent 6d9fe931bb
commit 87067a42e3
3 changed files with 190 additions and 155 deletions

View File

@@ -1047,26 +1047,42 @@ private fun FullSizeAvatar(
avatarRepository?.getAvatars(publicKey, allDecode = false)?.collectAsState()
?: remember { mutableStateOf(emptyList()) }
// Сохраняем bitmap в remember чтобы не мигал при recomposition
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
var isLoading by remember { mutableStateOf(true) }
// 🔥 FIX: Используем стабильный ключ (timestamp) вместо reference списка
// Это предотвращает перезагрузку bitmap при recomposition когда данные не изменились
val avatarKey = remember(avatars) {
avatars.firstOrNull()?.timestamp ?: 0L
}
LaunchedEffect(avatars) {
if (avatars.isNotEmpty()) {
// 🔥 FIX: Сохраняем bitmap БЕЗ сброса при изменении ключа
// Предыдущий bitmap показывается пока загружается новый (double buffering)
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
// 🔥 FIX: isLoading только для первой загрузки, не сбрасываем если bitmap уже есть
var initialLoadComplete by remember { mutableStateOf(false) }
// 🔥 FIX: Декодируем только когда avatarKey (timestamp) реально изменился
// НЕ сбрасываем bitmap в null перед загрузкой - показываем старый пока грузится новый
LaunchedEffect(avatarKey) {
val currentAvatars = avatars
if (currentAvatars.isNotEmpty()) {
val newBitmap = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
com.rosetta.messenger.utils.AvatarFileManager.base64ToBitmap(
avatars.first().base64Data
currentAvatars.first().base64Data
)
}
bitmap = newBitmap
isLoading = false
// Устанавливаем новый bitmap только если декодирование успешно
if (newBitmap != null) {
bitmap = newBitmap
}
initialLoadComplete = true
} else {
isLoading = false
// Нет аватарки - помечаем загрузку завершенной
initialLoadComplete = true
}
}
// Показываем картинку если есть, иначе placeholder
// НО не показываем placeholder пока идёт загрузка (чтобы не мигало)
// 🔥 FIX: Показываем bitmap сразу если он есть (даже во время загрузки нового)
when {
bitmap != null -> {
Image(
@@ -1076,8 +1092,8 @@ private fun FullSizeAvatar(
contentScale = ContentScale.Crop
)
}
!isLoading -> {
// Placeholder только когда точно нет аватарки
initialLoadComplete -> {
// Placeholder только когда точно нет аватарки И загрузка завершена
val avatarColors = getAvatarColor(publicKey, isDarkTheme)
Box(
modifier = Modifier.fillMaxSize().background(avatarColors.backgroundColor),
@@ -1091,7 +1107,8 @@ private fun FullSizeAvatar(
)
}
}
// Пока isLoading=true - ничего не показываем (прозрачно)
// Пока initialLoadComplete=false - ничего не показываем (прозрачно)
// Это только самый первый момент загрузки
}
}