From 01ed966e24ae26fac1dff9ef46b509e6d607b621 Mon Sep 17 00:00:00 2001 From: Sam Judd Date: Sat, 24 Dec 2022 10:12:14 -0800 Subject: [PATCH] Support loading placeholders in compose previews Composable placeholders already worked, but resource and drawable placeholders did not. Presumably some part of the production codepath isn't supported by the Android Studio renderer. The actual display of the resources seems to work fine, we just never get to that point in Glide's code. Debugging exactly what's happening seems mostly impossible. I don't see a way to view logs or debug code running in the Android Studio preview renderer. For now we can work around whatever the issue is by rendering resources and drawables when in preview mode earlier than normal. --- .../glide/integration/compose/GlideImage.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt index b9ad825e6c..6778cf64d7 100644 --- a/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt +++ b/integration/compose/src/main/java/com/bumptech/glide/integration/compose/GlideImage.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.graphics.DefaultAlpha import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.semantics.SemanticsPropertyKey import androidx.compose.ui.semantics.SemanticsPropertyReceiver import androidx.compose.ui.semantics.semantics @@ -28,6 +29,7 @@ import com.bumptech.glide.integration.ktx.InternalGlideApi import com.bumptech.glide.integration.ktx.ResolvableGlideSize import com.bumptech.glide.integration.ktx.Size import com.bumptech.glide.integration.ktx.Status +import com.google.accompanist.drawablepainter.rememberDrawablePainter /** Mutates and returns the given [RequestBuilder] to apply relevant options. */ public typealias RequestBuilderTransform = (RequestBuilder) -> RequestBuilder @@ -111,6 +113,14 @@ public fun GlideImage( val overrideSize: Size? = requestBuilder.overrideSize() val (size, finalModifier) = rememberSizeAndModifier(overrideSize, modifier) + // TODO(judds): It seems like we should be able to use the production paths for + // resource / drawables as well as Composables. It's not totally clear what part of the prod code + // isn't supported. + if (LocalInspectionMode.current && loading?.isResourceOrDrawable() == true) { + PreviewResourceOrDrawable(loading, contentDescription, modifier) + return + } + SizedGlideImage( requestBuilder = requestBuilder, size = size, @@ -125,6 +135,27 @@ public fun GlideImage( ) } +@OptIn(ExperimentalGlideComposeApi::class) +@Composable +private fun PreviewResourceOrDrawable( + loading: Placeholder, + contentDescription: String?, + modifier: Modifier, +) { + val drawable = + when(loading) { + is Placeholder.OfDrawable -> loading.drawable + is Placeholder.OfResourceId -> LocalContext.current.getDrawable(loading.resourceId) + is Placeholder.OfComposable -> + throw IllegalArgumentException("Composables should go through the production codepath") + } + Image( + painter = rememberDrawablePainter(drawable), + modifier = modifier, + contentDescription = contentDescription, + ) +} + /** * Used to specify a [Drawable] to use in conjunction with [GlideImage]'s `loading` or `failure` * parameters. @@ -177,6 +208,13 @@ public sealed class Placeholder { internal class OfResourceId(@DrawableRes internal val resourceId: Int) : Placeholder() internal class OfComposable(internal val composable: @Composable () -> Unit) : Placeholder() + internal fun isResourceOrDrawable() = + when (this) { + is OfDrawable -> true + is OfResourceId -> true + is OfComposable -> false + } + internal fun maybeComposable(): (@Composable () -> Unit)? = when (this) { is OfComposable -> this.composable