Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AmbientRequestManager for GlideImage #129

Merged
merged 5 commits into from Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions glide/README.md
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions 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;
}

Expand Up @@ -20,11 +20,13 @@ 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
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
Expand Down Expand Up @@ -279,6 +281,57 @@ class GlideTest {
.assertIsDisplayed()
}

@Test
fun customRequestManager_param() {
val latch = CountDownLatch(1)
val loaded = mutableListOf<Any>()

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,
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 customRequestManager_ambient() {
val latch = CountDownLatch(1)
val loaded = mutableListOf<Any>()

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(),
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)
Expand Down
@@ -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<Any> {
override fun onLoadFailed(
e: GlideException?,
model: Any,
target: Target<Any>?,
isFirstResource: Boolean
): Boolean {
onComplete(model)
return false
}

override fun onResourceReady(
resource: Any?,
model: Any,
target: Target<Any>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
onComplete(model)
return false
}
}
27 changes: 23 additions & 4 deletions glide/src/main/java/dev/chrisbanes/accompanist/glide/GlideImage.kt
Expand Up @@ -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
Expand All @@ -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<RequestManager?> { null }
chrisbanes marked this conversation as resolved.
Show resolved Hide resolved

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:
Expand All @@ -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.
Expand All @@ -77,7 +95,7 @@ fun GlideImage(
data: Any,
modifier: Modifier = Modifier,
requestBuilder: (RequestBuilder<Drawable>.(size: IntSize) -> RequestBuilder<Drawable>)? = 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
Expand Down Expand Up @@ -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.
Expand All @@ -147,7 +166,7 @@ fun GlideImage(
colorFilter: ColorFilter? = null,
fadeIn: Boolean = false,
requestBuilder: (RequestBuilder<Drawable>.(size: IntSize) -> RequestBuilder<Drawable>)? = 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,
Expand Down