Skip to content

Commit

Permalink
Add loading and failure parameters to GlideImage
Browse files Browse the repository at this point in the history
These parameters will override equivalent values set via
requestBuilderTransform if the parameters are non-null. If the
parameters are null, then we'll apply whatever is specified by
requestBuilderTransform. I plan to add similar explicit parameters
for other values settable via requestBuilderTransform over time with
similar override behavior unless someone objects.

The `fallback` on `RequestBuilder` is not replicated. Callers can use
`failure` or if/else to provide custom behavior for null models.

Similarly `loading` is only shown while the request is loading. Unlike
`RequestBuilder.placeholder`, `loading` will never be shown after the
load fail. `failure` should instead be used to explicitly duplicate the
`loading` behavior if that functionality is desired.
  • Loading branch information
sjudd committed Oct 25, 2022
1 parent 4298bb7 commit d5fc241
Show file tree
Hide file tree
Showing 13 changed files with 686 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.test.ResourceIds.raw;
import com.bumptech.glide.test.WaitModelLoader;
import com.bumptech.glide.test.WaitModelLoader.WaitModel;
import com.bumptech.glide.testutil.WaitModelLoader;
import com.bumptech.glide.testutil.WaitModelLoader.WaitModel;
import com.bumptech.glide.testutil.ConcurrencyHelper;
import com.bumptech.glide.testutil.TearDownGlide;
import com.google.common.truth.Truth;
Expand Down Expand Up @@ -308,7 +308,7 @@ public void clearDiskCache_doesNotPreventFutureLoads() {
// Tests #2428.
@Test
public void onlyRetrieveFromCache_withPreviousRequestLoadingFromSource_doesNotBlock() {
final WaitModel<Integer> waitModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
final WaitModel<Integer> waitModel = WaitModelLoader.waitOn(ResourceIds.raw.canonical);

FutureTarget<Drawable> loadFromSourceFuture = GlideApp.with(context).load(waitModel).submit();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.test.WaitModelLoader;
import com.bumptech.glide.test.WaitModelLoader.WaitModel;
import com.bumptech.glide.testutil.WaitModelLoader;
import com.bumptech.glide.testutil.WaitModelLoader.WaitModel;
import com.bumptech.glide.testutil.ConcurrencyHelper;
import com.bumptech.glide.testutil.TearDownGlide;
import java.io.File;
Expand Down Expand Up @@ -114,7 +114,7 @@ public void load_whenLoadSucceeds_butEncoderFails_doesNotCallOnLoadFailed() {

@Test
public void clearRequest_withError_afterPrimaryFails_clearsErrorRequest() {
WaitModel<Integer> errorModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
WaitModel<Integer> errorModel = WaitModelLoader.waitOn(ResourceIds.raw.canonical);

FutureTarget<Drawable> target =
Glide.with(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.test.WaitModelLoader;
import com.bumptech.glide.test.WaitModelLoader.WaitModel;
import com.bumptech.glide.testutil.WaitModelLoader;
import com.bumptech.glide.testutil.WaitModelLoader.WaitModel;
import com.bumptech.glide.testutil.ConcurrencyHelper;
import com.bumptech.glide.testutil.TearDownGlide;
import org.junit.Before;
Expand Down Expand Up @@ -111,7 +111,7 @@ public void run() {

@Test
public void onStop_withSingleRequestInProgress_nullsOutDrawableInView() {
final WaitModel<Integer> model = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
final WaitModel<Integer> model = WaitModelLoader.waitOn(ResourceIds.raw.canonical);
concurrency.runOnMainThread(
new Runnable() {
@Override
Expand All @@ -132,7 +132,7 @@ public void run() {

@Test
public void onStop_withRequestWithThumbnailBothInProgress_nullsOutDrawableInView() {
final WaitModel<Integer> model = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
final WaitModel<Integer> model = WaitModelLoader.waitOn(ResourceIds.raw.canonical);
concurrency.runOnMainThread(
new Runnable() {
@Override
Expand All @@ -158,7 +158,7 @@ public void run() {
/** Tests #2555. */
@Test
public void clear_withRequestWithOnlyFullInProgress_nullsOutDrawableInView() {
final WaitModel<Integer> mainModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
final WaitModel<Integer> mainModel = WaitModelLoader.waitOn(ResourceIds.raw.canonical);
concurrency.loadUntilFirstFinish(
GlideApp.with(context)
.load(mainModel)
Expand Down Expand Up @@ -198,7 +198,7 @@ public void run() {

@Test
public void clear_withRequestWithOnlyFullInProgress_doesNotNullOutDrawableInView() {
final WaitModel<Integer> mainModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
final WaitModel<Integer> mainModel = WaitModelLoader.waitOn(ResourceIds.raw.canonical);
concurrency.loadUntilFirstFinish(
GlideApp.with(context)
.load(mainModel)
Expand Down Expand Up @@ -238,7 +238,7 @@ public void run() {

@Test
public void onStop_withRequestWithOnlyThumbnailInProgress_doesNotNullOutDrawableInView() {
final WaitModel<Integer> thumbModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
final WaitModel<Integer> thumbModel = WaitModelLoader.waitOn(ResourceIds.raw.canonical);
concurrency.loadUntilFirstFinish(
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
Expand Down
9 changes: 8 additions & 1 deletion integration/compose/api/compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ public abstract interface annotation class com/bumptech/glide/integration/compos
}

public final class com/bumptech/glide/integration/compose/GlideImageKt {
public static final fun GlideImage (Ljava/lang/Object;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun GlideImage (Ljava/lang/Object;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;FLandroidx/compose/ui/graphics/ColorFilter;Lcom/bumptech/glide/integration/compose/Placeholder;Lcom/bumptech/glide/integration/compose/Placeholder;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun placeholder (I)Lcom/bumptech/glide/integration/compose/Placeholder;
public static final fun placeholder (Landroid/graphics/drawable/Drawable;)Lcom/bumptech/glide/integration/compose/Placeholder;
public static final fun placeholder (Lkotlin/jvm/functions/Function2;)Lcom/bumptech/glide/integration/compose/Placeholder;
}

public abstract class com/bumptech/glide/integration/compose/Placeholder {
public static final field $stable I
}

public final class com/bumptech/glide/integration/compose/PreloadKt {
Expand Down
1 change: 1 addition & 0 deletions integration/compose/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies {
androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$ANDROID_X_TEST_ESPRESSO_VERSION"
androidTestImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION"
androidTestImplementation "androidx.compose.material:material:$ANDROID_X_COMPOSE_VERSION"
androidTestImplementation project(':testutil')
}

apply from: "${rootProject.projectDir}/scripts/upload.gradle"
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
package com.bumptech.glide.integration.compose

import android.content.Context
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
Expand All @@ -24,29 +20,28 @@ import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.dp
import androidx.test.core.app.ApplicationProvider
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.compose.test.bitmapSize
import com.bumptech.glide.integration.compose.test.expectDisplayedDrawable
import com.bumptech.glide.integration.compose.test.expectDisplayedDrawableSize
import com.bumptech.glide.integration.ktx.InternalGlideApi
import com.bumptech.glide.integration.ktx.Size
import com.bumptech.glide.load.engine.executor.GlideIdlingResourceInit
import com.bumptech.glide.testutil.TearDownGlide
import java.util.concurrent.atomic.AtomicReference
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class GlideComposeTest {
private val context: Context = ApplicationProvider.getApplicationContext()
@get:Rule val composeRule = createComposeRule()
@get:Rule(order = 1) val composeRule = createComposeRule()
@get:Rule(order = 2) val tearDownGlide = TearDownGlide()

@Before
fun setUp() {
GlideIdlingResourceInit.initGlide(composeRule)
}

@After
fun tearDown() {
Glide.tearDown()
}

@Test
fun glideImage_noModifierSize_resourceDrawable_displaysDrawable() {
val description = "test"
Expand Down Expand Up @@ -109,10 +104,9 @@ class GlideComposeTest {
composeRule.onNodeWithText("Swap").performClick()
composeRule.waitForIdle()

val fullsizeBitmap = (secondDrawable as BitmapDrawable).bitmap
composeRule
.onNodeWithContentDescription(description)
.assert(expectDisplayedDrawable(fullsizeBitmap) { (it as BitmapDrawable).bitmap })
.assert(expectDisplayedDrawable(secondDrawable))
}

@Test
Expand Down Expand Up @@ -148,8 +142,6 @@ class GlideComposeTest {
val thumbnailDrawable = context.getDrawable(android.R.drawable.star_big_off)
val fullsizeDrawable = context.getDrawable(android.R.drawable.star_big_on)

val fullsizeBitmap = (fullsizeDrawable as BitmapDrawable).bitmap

composeRule.setContent {
GlideImage(
model = fullsizeDrawable,
Expand All @@ -162,34 +154,6 @@ class GlideComposeTest {

composeRule
.onNodeWithContentDescription(description)
.assert(expectDisplayedDrawable(fullsizeBitmap) { (it as BitmapDrawable).bitmap })
.assert(expectDisplayedDrawable(fullsizeDrawable))
}

private fun Int.bitmapSize() = context.resources.getDrawable(this, context.theme).size()
}

private fun Drawable.size() = (this as BitmapDrawable).bitmap.let { Size(it.width, it.height) }

private fun expectDisplayedDrawableSize(widthPixels: Int, heightPixels: Int): SemanticsMatcher =
expectDisplayedDrawable(Size(widthPixels, heightPixels)) { it?.size() }

private fun expectDisplayedDrawableSize(expectedSize: Size): SemanticsMatcher =
expectDisplayedDrawable(expectedSize) { it?.size() }

private fun <ValueT> expectDisplayedDrawable(
expectedValue: ValueT,
transform: (Drawable?) -> ValueT
): SemanticsMatcher = expectStateValue(DisplayedDrawableKey, expectedValue) { transform(it) }

private fun <ValueT, TransformedValueT> expectStateValue(
key: SemanticsPropertyKey<MutableState<ValueT?>>,
expectedValue: TransformedValueT,
transform: (ValueT?) -> TransformedValueT?
): SemanticsMatcher =
SemanticsMatcher("${key.name} = '$expectedValue'") {
val value = transform(it.config.getOrElseNullable(key) { null }?.value)
if (value != expectedValue) {
throw AssertionError("Expected: $expectedValue, but was: $value")
}
true
}
Loading

0 comments on commit d5fc241

Please sign in to comment.