From 6ad6695927abdaae76e9de0ed58d4029b43010f7 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Fri, 23 Oct 2020 14:00:25 +0100 Subject: [PATCH 1/5] Add AmbientRequestManager for GlideImage Similar to what has been added to Coil + Picasso --- glide/README.md | 22 ++++++++ glide/api/glide.api | 6 +++ .../chrisbanes/accompanist/glide/GlideTest.kt | 54 +++++++++++++++++++ .../glide/SimpleRequestListener.kt | 50 +++++++++++++++++ .../accompanist/glide/GlideImage.kt | 27 ++++++++-- 5 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/SimpleRequestListener.kt diff --git a/glide/README.md b/glide/README.md index 2c2acf869..623fecb66 100644 --- a/glide/README.md +++ b/glide/README.md @@ -98,6 +98,28 @@ Accompanist Glide supports GIFs through Glide's own GIF support. There's nothing ![Example GIF](https://media.giphy.com/media/6oMKugqovQnjW/giphy.gif) +## Custom RequestManager + +If you wish to provide a default `RequestManager` to use across all of your `GlideImage` +calls, we provide the `AmbientRequestManager` ambient. + +You can use it like so: + +``` kotlin +val requestManager = Glide.with(...) + // customize the RequestManager as needed + .build() + +Providers(AmbientRequestManager provides requestManager) { + // This will automatically use the value of AmbientRequestManager + GlideImage( + data = ... + ) +} +``` + +For more information on ambients, see [here](https://developer.android.com/reference/kotlin/androidx/compose/runtime/Ambient). + ## Download ```groovy diff --git a/glide/api/glide.api b/glide/api/glide.api index 21ac1d742..afed00c7e 100644 --- a/glide/api/glide.api +++ b/glide/api/glide.api @@ -1,5 +1,11 @@ public final class dev/chrisbanes/accompanist/glide/GlideImage { public static final fun GlideImage (Ljava/lang/Object;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;Landroidx/compose/ui/graphics/ColorFilter;ZLkotlin/jvm/functions/Function2;Lcom/bumptech/glide/RequestManager;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V public static final fun GlideImage (Ljava/lang/Object;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Lcom/bumptech/glide/RequestManager;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V + public static final fun getAmbientRequestManager ()Landroidx/compose/runtime/ProvidableAmbient; +} + +public final class dev/chrisbanes/accompanist/glide/GlideImageConstants { + public static final field INSTANCE Ldev/chrisbanes/accompanist/glide/GlideImageConstants; + public final fun defaultRequestManager (Landroidx/compose/runtime/Composer;I)Lcom/bumptech/glide/RequestManager; } diff --git a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt index 27336f8db..91d3bb717 100644 --- a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt +++ b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt @@ -20,6 +20,7 @@ import android.graphics.drawable.Drawable import androidx.compose.foundation.Image import androidx.compose.foundation.Text import androidx.compose.foundation.layout.preferredSize +import androidx.compose.runtime.Providers import androidx.compose.runtime.collectAsState import androidx.compose.runtime.onCommit import androidx.compose.ui.Modifier @@ -279,6 +280,59 @@ class GlideTest { .assertIsDisplayed() } + @SdkSuppress(minSdkVersion = 26) // captureToBitmap + @Test + fun customPicasso_param() { + val latch = CountDownLatch(1) + val loaded = mutableListOf() + + // Create a RequestManager with a listener which updates our loaded list + val glide = Glide.with(InstrumentationRegistry.getInstrumentation().targetContext) + .addDefaultRequestListener(SimpleRequestListener { model -> loaded += model }) + + composeTestRule.setContent { + GlideImage( + data = server.url("/image").toString(), + requestManager = glide, + modifier = Modifier.preferredSize(128.dp, 128.dp), + onRequestCompleted = { latch.countDown() } + ) + } + + // Wait for the onRequestCompleted to release the latch + latch.await(5, TimeUnit.SECONDS) + + // Assert that the listener was called + assertThat(loaded).hasSize(1) + } + + @SdkSuppress(minSdkVersion = 26) // captureToBitmap + @Test + fun customPicasso_ambient() { + val latch = CountDownLatch(1) + val loaded = mutableListOf() + + // Create a RequestManager with a listener which updates our loaded list + val glide = Glide.with(InstrumentationRegistry.getInstrumentation().targetContext) + .addDefaultRequestListener(SimpleRequestListener { model -> loaded += model }) + + composeTestRule.setContent { + Providers(AmbientRequestManager provides glide) { + GlideImage( + data = server.url("/image").toString(), + modifier = Modifier.preferredSize(128.dp, 128.dp), + onRequestCompleted = { latch.countDown() } + ) + } + } + + // Wait for the onRequestCompleted to release the latch + latch.await(5, TimeUnit.SECONDS) + + // Assert that the listener was called + assertThat(loaded).hasSize(1) + } + @Test fun errorStillHasSize() { val latch = CountDownLatch(1) diff --git a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/SimpleRequestListener.kt b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/SimpleRequestListener.kt new file mode 100644 index 000000000..b2b568a74 --- /dev/null +++ b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/SimpleRequestListener.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.chrisbanes.accompanist.glide + +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target + +/** + * Simple wrapper around RequestListener for use in tests + */ +internal class SimpleRequestListener( + private val onComplete: (Any) -> Unit +) : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any, + target: Target?, + isFirstResource: Boolean + ): Boolean { + onComplete(model) + return false + } + + override fun onResourceReady( + resource: Any?, + model: Any, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + onComplete(model) + return false + } +} diff --git a/glide/src/main/java/dev/chrisbanes/accompanist/glide/GlideImage.kt b/glide/src/main/java/dev/chrisbanes/accompanist/glide/GlideImage.kt index f1f8bd87d..f9a0c68ac 100644 --- a/glide/src/main/java/dev/chrisbanes/accompanist/glide/GlideImage.kt +++ b/glide/src/main/java/dev/chrisbanes/accompanist/glide/GlideImage.kt @@ -22,6 +22,7 @@ package dev.chrisbanes.accompanist.glide import android.graphics.drawable.Drawable import androidx.compose.foundation.Image import androidx.compose.runtime.Composable +import androidx.compose.runtime.staticAmbientOf import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter @@ -46,6 +47,22 @@ import dev.chrisbanes.accompanist.imageloading.toPainter import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.suspendCancellableCoroutine +/** + * Ambient containing the preferred [RequestManager] to use in [GlideImage]. + */ +val AmbientRequestManager = staticAmbientOf { null } + +object GlideImageConstants { + /** + * Returns the default [RequestManager] value for the `requestManager` parameter + * in [GlideImage]. + */ + @Composable + fun defaultRequestManager(): RequestManager { + return AmbientRequestManager.current ?: Glide.with(ViewAmbient.current) + } +} + /** * Creates a composable that will attempt to load the given [data] using [Glide], and provides * complete content of how the current state is displayed: @@ -66,7 +83,8 @@ import kotlinx.coroutines.suspendCancellableCoroutine * @param data The data to load. * @param modifier [Modifier] used to adjust the layout algorithm or draw decoration content. * @param requestBuilder Optional builder for the [RequestBuilder]. - * @param requestManager The [RequestManager] to use when requesting the image. Defaults to `Glide.with(view)` + * @param requestManager The [RequestManager] to use when requesting the image. Defaults to the + * current value of [AmbientRequestManager]. * @param shouldRefetchOnSizeChange Lambda which will be invoked when the size changes, allowing * optional re-fetching of the image. Return true to re-fetch the image. * @param onRequestCompleted Listener which will be called when the loading request has finished. @@ -77,7 +95,7 @@ fun GlideImage( data: Any, modifier: Modifier = Modifier, requestBuilder: (RequestBuilder.(size: IntSize) -> RequestBuilder)? = null, - requestManager: RequestManager = Glide.with(ViewAmbient.current), + requestManager: RequestManager = GlideImageConstants.defaultRequestManager(), shouldRefetchOnSizeChange: (currentResult: ImageLoadState, size: IntSize) -> Boolean = DefaultRefetchOnSizeChangeLambda, onRequestCompleted: (ImageLoadState) -> Unit = EmptyRequestCompleteLambda, content: @Composable (imageLoadState: ImageLoadState) -> Unit @@ -133,7 +151,8 @@ fun GlideImage( * @param fadeIn Whether to run a fade-in animation when images are successfully loaded. * Default: `false`. * @param requestBuilder Optional builder for the [RequestBuilder]. - * @param requestManager The [RequestManager] to use when requesting the image. Defaults to `Glide.with(view)` + * @param requestManager The [RequestManager] to use when requesting the image. Defaults to the + * current value of [AmbientRequestManager]. * @param shouldRefetchOnSizeChange Lambda which will be invoked when the size changes, allowing * optional re-fetching of the image. Return true to re-fetch the image. * @param onRequestCompleted Listener which will be called when the loading request has finished. @@ -147,7 +166,7 @@ fun GlideImage( colorFilter: ColorFilter? = null, fadeIn: Boolean = false, requestBuilder: (RequestBuilder.(size: IntSize) -> RequestBuilder)? = null, - requestManager: RequestManager = Glide.with(ViewAmbient.current), + requestManager: RequestManager = GlideImageConstants.defaultRequestManager(), shouldRefetchOnSizeChange: (currentResult: ImageLoadState, size: IntSize) -> Boolean = DefaultRefetchOnSizeChangeLambda, onRequestCompleted: (ImageLoadState) -> Unit = EmptyRequestCompleteLambda, error: @Composable ((ImageLoadState.Error) -> Unit)? = null, From 9b78fca0faaa7c11e6905a1aa69641aee8b941e9 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Mon, 26 Oct 2020 11:17:31 +0000 Subject: [PATCH 2/5] Fix tests --- .../chrisbanes/accompanist/glide/GlideTest.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt index 91d3bb717..53b179305 100644 --- a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt +++ b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.onCommit import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.ColorPainter +import androidx.compose.ui.platform.ViewAmbient import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import androidx.test.filters.LargeTest @@ -286,11 +287,11 @@ class GlideTest { val latch = CountDownLatch(1) val loaded = mutableListOf() - // Create a RequestManager with a listener which updates our loaded list - val glide = Glide.with(InstrumentationRegistry.getInstrumentation().targetContext) - .addDefaultRequestListener(SimpleRequestListener { model -> loaded += model }) - composeTestRule.setContent { + // Create a RequestManager with a listener which updates our loaded list + val glide = Glide.with(ViewAmbient.current) + .addDefaultRequestListener(SimpleRequestListener { model -> loaded += model }) + GlideImage( data = server.url("/image").toString(), requestManager = glide, @@ -312,11 +313,11 @@ class GlideTest { val latch = CountDownLatch(1) val loaded = mutableListOf() - // Create a RequestManager with a listener which updates our loaded list - val glide = Glide.with(InstrumentationRegistry.getInstrumentation().targetContext) - .addDefaultRequestListener(SimpleRequestListener { model -> loaded += model }) - composeTestRule.setContent { + // Create a RequestManager with a listener which updates our loaded list + val glide = Glide.with(ViewAmbient.current) + .addDefaultRequestListener(SimpleRequestListener { model -> loaded += model }) + Providers(AmbientRequestManager provides glide) { GlideImage( data = server.url("/image").toString(), From 812479a2449325eca54d653ef8b53f40e6c0a721 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Mon, 26 Oct 2020 11:19:28 +0000 Subject: [PATCH 3/5] Remove unnecessary SdkSuppress --- .../java/dev/chrisbanes/accompanist/glide/GlideTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt index 53b179305..4fbde9c45 100644 --- a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt +++ b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt @@ -281,7 +281,6 @@ class GlideTest { .assertIsDisplayed() } - @SdkSuppress(minSdkVersion = 26) // captureToBitmap @Test fun customPicasso_param() { val latch = CountDownLatch(1) @@ -307,7 +306,6 @@ class GlideTest { assertThat(loaded).hasSize(1) } - @SdkSuppress(minSdkVersion = 26) // captureToBitmap @Test fun customPicasso_ambient() { val latch = CountDownLatch(1) From b16ad59eed784f2019c66e7ecf6fa93e64620432 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Mon, 26 Oct 2020 11:22:53 +0000 Subject: [PATCH 4/5] Update glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt Co-authored-by: Nick Butcher --- .../java/dev/chrisbanes/accompanist/glide/GlideTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt index 4fbde9c45..b0dfaaf72 100644 --- a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt +++ b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt @@ -282,7 +282,7 @@ class GlideTest { } @Test - fun customPicasso_param() { + fun customRequestManager_param() { val latch = CountDownLatch(1) val loaded = mutableListOf() From af057876f48fa67d2ffd1fd94a0b3807904c4bdf Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Mon, 26 Oct 2020 11:23:43 +0000 Subject: [PATCH 5/5] Update glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt Co-authored-by: Nick Butcher --- .../java/dev/chrisbanes/accompanist/glide/GlideTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt index b0dfaaf72..805745718 100644 --- a/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt +++ b/glide/src/androidTest/java/dev/chrisbanes/accompanist/glide/GlideTest.kt @@ -307,7 +307,7 @@ class GlideTest { } @Test - fun customPicasso_ambient() { + fun customRequestManager_ambient() { val latch = CountDownLatch(1) val loaded = mutableListOf()