From 1b6b8857980aed8e006c28626dfbc869626b69e8 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:01:09 +0000 Subject: [PATCH] desktop: don't decode animation frames that cannot be seen With media blur on, a blurred image is only revealed while the mouse is over it, so every frame was decoded, uploaded and then blurred away again for nobody - and the blur is a render effect re-run per frame. Frames now decode only while the image can be seen, which also stops motion showing through a blur that is there to hide it. Passing the blur state to the view is why the shared signature changes; coil drives its own animation on Android, so there is nothing to pause there. --- .../simplex/common/views/chat/item/CIImageView.android.kt | 2 ++ .../kotlin/chat/simplex/common/views/chat/item/CIImageView.kt | 3 ++- .../simplex/common/views/chat/item/CIImageView.desktop.kt | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.android.kt index ae5b8043ed..5538655a92 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.android.kt @@ -3,6 +3,7 @@ package chat.simplex.common.views.chat.item import android.os.Build.VERSION.SDK_INT import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.State import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter @@ -24,6 +25,7 @@ actual fun SimpleAndAnimatedImageView( file: CIFile?, imageProvider: () -> ImageGalleryProvider, smallView: Boolean, + blurred: State, // coil drives the animation itself here, so there is nothing to pause ImageView: @Composable (painter: Painter, onClick: () -> Unit) -> Unit ) { val context = LocalContext.current diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.kt index 7ce44475b5..67fc0a038c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.kt @@ -210,7 +210,7 @@ fun CIImageView( val loaded = res.value if (loaded != null && file != null) { val (imageBitmap, data, _) = loaded - SimpleAndAnimatedImageView(data, imageBitmap, file, imageProvider, smallView, @Composable { painter, onClick -> ImageView(painter, image, file.fileSource, onClick) }) + SimpleAndAnimatedImageView(data, imageBitmap, file, imageProvider, smallView, blurred, @Composable { painter, onClick -> ImageView(painter, image, file.fileSource, onClick) }) } else { imageView(previewBitmap, onClick = { if (file != null) { @@ -281,5 +281,6 @@ expect fun SimpleAndAnimatedImageView( file: CIFile?, imageProvider: () -> ImageGalleryProvider, smallView: Boolean, + blurred: State, ImageView: @Composable (painter: Painter, onClick: () -> Unit) -> Unit ) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.desktop.kt index eb81df3ad2..bed6c91219 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIImageView.desktop.kt @@ -1,6 +1,7 @@ package chat.simplex.common.views.chat.item import androidx.compose.runtime.Composable +import androidx.compose.runtime.State import androidx.compose.ui.graphics.* import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter @@ -15,12 +16,13 @@ actual fun SimpleAndAnimatedImageView( file: CIFile?, imageProvider: () -> ImageGalleryProvider, smallView: Boolean, + blurred: State, ImageView: @Composable (painter: Painter, onClick: () -> Unit) -> Unit ) { // The small view is the chat list preview: a 36dp box that the desktop layout keeps on screen the whole // time. Decoding an animation at its own resolution to fill it would hold a raster and spend a frame of // work per listed chat, without pause, so it keeps the still image as it did before. - val frame = if (smallView) null else rememberAnimatedImage(data, imageBitmap) + val frame = if (smallView) null else rememberAnimatedImage(data, imageBitmap, blurred) ImageView(BitmapPainter(frame?.value ?: imageBitmap)) { if (getLoadedFilePath(file) != null) { ModalManager.fullscreen.showCustomModal(animated = false) { close ->