|
|
@ -16,17 +16,24 @@ |
|
|
|
|
|
|
|
|
|
|
|
package io.element.android.features.messages.impl.timeline.components.blurhash |
|
|
|
package io.element.android.features.messages.impl.timeline.components.blurhash |
|
|
|
|
|
|
|
|
|
|
|
import android.graphics.Bitmap |
|
|
|
import androidx.compose.animation.AnimatedVisibility |
|
|
|
|
|
|
|
import androidx.compose.animation.fadeIn |
|
|
|
|
|
|
|
import androidx.compose.animation.fadeOut |
|
|
|
import androidx.compose.foundation.Image |
|
|
|
import androidx.compose.foundation.Image |
|
|
|
|
|
|
|
import androidx.compose.foundation.layout.Box |
|
|
|
import androidx.compose.foundation.layout.fillMaxSize |
|
|
|
import androidx.compose.foundation.layout.fillMaxSize |
|
|
|
import androidx.compose.runtime.Composable |
|
|
|
import androidx.compose.runtime.Composable |
|
|
|
import androidx.compose.runtime.DisposableEffect |
|
|
|
import androidx.compose.runtime.DisposableEffect |
|
|
|
|
|
|
|
import androidx.compose.runtime.getValue |
|
|
|
import androidx.compose.runtime.mutableStateOf |
|
|
|
import androidx.compose.runtime.mutableStateOf |
|
|
|
import androidx.compose.runtime.remember |
|
|
|
import androidx.compose.runtime.remember |
|
|
|
|
|
|
|
import androidx.compose.runtime.saveable.rememberSaveable |
|
|
|
|
|
|
|
import androidx.compose.runtime.setValue |
|
|
|
|
|
|
|
import androidx.compose.ui.Alignment |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
import androidx.compose.ui.graphics.asImageBitmap |
|
|
|
import androidx.compose.ui.graphics.asImageBitmap |
|
|
|
import androidx.compose.ui.layout.ContentScale |
|
|
|
import androidx.compose.ui.layout.ContentScale |
|
|
|
import coil.compose.SubcomposeAsyncImage |
|
|
|
import coil.compose.AsyncImage |
|
|
|
import com.vanniktech.blurhash.BlurHash |
|
|
|
import com.vanniktech.blurhash.BlurHash |
|
|
|
|
|
|
|
|
|
|
|
@Composable |
|
|
|
@Composable |
|
|
@ -37,20 +44,30 @@ fun BlurHashAsyncImage( |
|
|
|
contentScale: ContentScale = ContentScale.Fit, |
|
|
|
contentScale: ContentScale = ContentScale.Fit, |
|
|
|
contentDescription: String? = null, |
|
|
|
contentDescription: String? = null, |
|
|
|
) { |
|
|
|
) { |
|
|
|
SubcomposeAsyncImage( |
|
|
|
var isLoading by rememberSaveable(model) { mutableStateOf(true) } |
|
|
|
model = model, |
|
|
|
Box( |
|
|
|
modifier = modifier, |
|
|
|
modifier = modifier, |
|
|
|
|
|
|
|
contentAlignment = Alignment.Center, |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
AsyncImage( |
|
|
|
|
|
|
|
model = model, |
|
|
|
contentScale = contentScale, |
|
|
|
contentScale = contentScale, |
|
|
|
contentDescription = contentDescription, |
|
|
|
contentDescription = contentDescription, |
|
|
|
loading = { |
|
|
|
onSuccess = { isLoading = false } |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
AnimatedVisibility( |
|
|
|
|
|
|
|
visible = isLoading, |
|
|
|
|
|
|
|
enter = fadeIn(), |
|
|
|
|
|
|
|
exit = fadeOut(), |
|
|
|
|
|
|
|
) { |
|
|
|
BlurHashImage( |
|
|
|
BlurHashImage( |
|
|
|
blurHash = blurHash, |
|
|
|
blurHash = blurHash, |
|
|
|
|
|
|
|
contentDescription = contentDescription, |
|
|
|
contentScale = ContentScale.FillBounds, |
|
|
|
contentScale = ContentScale.FillBounds, |
|
|
|
contentDescription = "Loading placeholder" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Composable |
|
|
|
@Composable |
|
|
|
fun BlurHashImage( |
|
|
|
fun BlurHashImage( |
|
|
@ -60,12 +77,13 @@ fun BlurHashImage( |
|
|
|
contentScale: ContentScale = ContentScale.Fit, |
|
|
|
contentScale: ContentScale = ContentScale.Fit, |
|
|
|
) { |
|
|
|
) { |
|
|
|
if (blurHash == null) return |
|
|
|
if (blurHash == null) return |
|
|
|
val bitmapState = remember { |
|
|
|
val bitmapState = remember(blurHash) { |
|
|
|
mutableStateOf<Bitmap?>(null) |
|
|
|
mutableStateOf( |
|
|
|
|
|
|
|
// Build a small blurhash image so that it's fast |
|
|
|
|
|
|
|
BlurHash.decode(blurHash, 10, 10) |
|
|
|
|
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
DisposableEffect(blurHash) { |
|
|
|
DisposableEffect(blurHash) { |
|
|
|
// Build a small blurhash image so that it's fast |
|
|
|
|
|
|
|
bitmapState.value = BlurHash.decode(blurHash, 10, 10) |
|
|
|
|
|
|
|
onDispose { |
|
|
|
onDispose { |
|
|
|
bitmapState.value?.recycle() |
|
|
|
bitmapState.value?.recycle() |
|
|
|
} |
|
|
|
} |
|
|
|