From a055f473cbab604b65c81ce58e81ae2c0dc09bb7 Mon Sep 17 00:00:00 2001 From: davotoula Date: Tue, 21 Oct 2025 15:56:18 +0100 Subject: [PATCH] =?UTF-8?q?prevent=20race=20condition:=20Added=20a=20state?= =?UTF-8?q?-aware=20rememberFirstImageOrientation=20helper=20so=20each=20g?= =?UTF-8?q?allery=20watches=20the=20cache=20until=20the=20first=20image?= =?UTF-8?q?=E2=80=99s=20real=20aspect=20ratio=20is=20known?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../amethyst/ui/components/ImageGallery.kt | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt index 99df5600e..0aad95ea8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ImageGallery.kt @@ -34,6 +34,11 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp @@ -47,6 +52,8 @@ import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.Size5dp import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive private const val ASPECT_RATIO = 4f / 3f private const val PORTRAIT_ASPECT_RATIO = 3f / 4f @@ -81,6 +88,32 @@ private fun MediaUrlImage?.resolveOrientation( ) } +@Composable +private fun rememberFirstImageOrientation(firstImage: MediaUrlImage?): FirstImageOrientation { + val initialOrientation = + remember(firstImage) { + firstImage.resolveOrientation(ASPECT_RATIO, PORTRAIT_ASPECT_RATIO) + } + + var orientation by remember(firstImage) { mutableStateOf(initialOrientation) } + + LaunchedEffect(firstImage) { + if (firstImage == null) return@LaunchedEffect + if (firstImage.dim?.hasSize() == true) return@LaunchedEffect + + while (isActive) { + val ratio = firstImage.resolvedAspectRatio() + if (ratio != null && ratio > 0f) { + orientation = FirstImageOrientation(ratio, ratio >= 1f) + break + } + delay(200) + } + } + + return orientation +} + @Composable private fun GalleryImage( image: MediaUrlImage, @@ -151,7 +184,7 @@ private fun TwoImageGallery( accountViewModel: AccountViewModel, roundedCorner: Boolean, ) { - val orientation = images.firstOrNull().resolveOrientation(ASPECT_RATIO, PORTRAIT_ASPECT_RATIO) + val orientation = rememberFirstImageOrientation(images.firstOrNull()) if (orientation.isLandscape) { Column( @@ -195,7 +228,7 @@ private fun ThreeImageGallery( roundedCorner: Boolean, ) { val firstImage = images.first() - val orientation = firstImage.resolveOrientation(ASPECT_RATIO, PORTRAIT_ASPECT_RATIO) + val orientation = rememberFirstImageOrientation(firstImage) val remainingImages = images.drop(1) if (orientation.isLandscape) {