Skip to content

Commit

Permalink
Merge pull request #80 from chrisbanes/cb/image-loader
Browse files Browse the repository at this point in the history
Add `ImageLoader` parameter
  • Loading branch information
probot-auto-merge[bot] committed Sep 16, 2020
2 parents 4b5e39b + a7bb940 commit 64646f8
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 6 deletions.
Expand Up @@ -80,4 +80,5 @@ object Libs {
const val coil = "io.coil-kt:coil:1.0.0-rc1"

const val truth = "com.google.truth:truth:1.0.1"
const val mockk = "io.mockk:mockk-android:1.10.0"
}
8 changes: 4 additions & 4 deletions coil/api/coil.api
@@ -1,8 +1,8 @@
public final class dev/chrisbanes/accompanist/coil/CoilImage {
public static final fun CoilImage (Lcoil/request/ImageRequest;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;Landroidx/compose/ui/graphics/ColorFilter;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImage (Ljava/lang/Object;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;Landroidx/compose/ui/graphics/ColorFilter;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImageWithCrossfade (Lcoil/request/ImageRequest;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImageWithCrossfade (Ljava/lang/Object;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImage (Lcoil/request/ImageRequest;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;Landroidx/compose/ui/graphics/ColorFilter;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lcoil/ImageLoader;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImage (Ljava/lang/Object;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;Landroidx/compose/ui/graphics/ColorFilter;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lcoil/ImageLoader;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImageWithCrossfade (Lcoil/request/ImageRequest;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lcoil/ImageLoader;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
public static final fun CoilImageWithCrossfade (Ljava/lang/Object;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment;Landroidx/compose/ui/layout/ContentScale;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lcoil/ImageLoader;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
}

public final class dev/chrisbanes/accompanist/coil/ErrorResult : dev/chrisbanes/accompanist/coil/RequestResult {
Expand Down
1 change: 1 addition & 0 deletions coil/build.gradle
Expand Up @@ -91,6 +91,7 @@ dependencies {

androidTestImplementation Libs.junit
androidTestImplementation Libs.truth
androidTestImplementation Libs.mockk

androidTestImplementation Libs.Coroutines.test

Expand Down
Expand Up @@ -31,6 +31,7 @@ import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import androidx.ui.test.assertHeightIsAtLeast
import androidx.ui.test.assertHeightIsEqualTo
import androidx.ui.test.assertIsDisplayed
Expand All @@ -42,10 +43,15 @@ import androidx.ui.test.createComposeRule
import androidx.ui.test.onNodeWithTag
import androidx.ui.test.onNodeWithText
import androidx.ui.test.runOnIdle
import coil.EventListener
import coil.ImageLoader
import coil.annotation.ExperimentalCoilApi
import coil.request.CachePolicy
import coil.request.ImageRequest
import com.google.common.truth.Truth.assertThat
import dev.chrisbanes.accompanist.coil.test.R
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -137,6 +143,35 @@ class CoilTest {
.assertPixels { Color.Red }
}

@OptIn(ExperimentalCoilApi::class)
@Test
fun basicLoad_customImageLoader() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val latch = CountDownLatch(1)

// Build a custom ImageLoader with a mocked EventListener
val eventListener = mockk<EventListener>(relaxed = true)
val imageLoader = ImageLoader.Builder(context)
.eventListener(eventListener)
.build()

composeTestRule.setContent {
CoilImage(
data = resourceUri(R.drawable.red_rectangle),
modifier = Modifier.preferredSize(128.dp, 128.dp),
imageLoader = imageLoader,
onRequestCompleted = { latch.countDown() }
)
}

// Wait for the onRequestCompleted to release the latch
latch.await(5, TimeUnit.SECONDS)

// Verify that our eventListener was invoked
verify(atLeast = 1) { eventListener.fetchStart(any(), any(), any()) }
verify(atLeast = 1) { eventListener.fetchEnd(any(), any(), any(), any()) }
}

@OptIn(ExperimentalCoroutinesApi::class)
@Test
@SdkSuppress(minSdkVersion = 26) // captureToBitmap is SDK 26+
Expand Down
15 changes: 13 additions & 2 deletions coil/src/main/java/dev/chrisbanes/accompanist/coil/Coil.kt
Expand Up @@ -44,6 +44,7 @@ import androidx.compose.ui.platform.ContextAmbient
import androidx.compose.ui.unit.IntSize
import androidx.core.graphics.drawable.toBitmap
import coil.Coil
import coil.ImageLoader
import coil.decode.DataSource
import coil.request.ImageRequest
import coil.request.ImageResult
Expand All @@ -64,6 +65,8 @@ import coil.request.ImageResult
* @param getFailurePainter Optional builder for the [Painter] to be used to draw the failure
* loading result. Passing in `null` will result in falling back to the default [Painter].
* @param loading Content to be displayed when the request is in progress.
* @param imageLoader The [ImageLoader] to use when requesting the image. Defaults to [Coil]'s
* default image loader.
* @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 @@ -78,6 +81,7 @@ fun CoilImage(
getSuccessPainter: @Composable ((SuccessResult) -> Painter)? = null,
getFailurePainter: @Composable ((ErrorResult) -> Painter?)? = null,
loading: @Composable (() -> Unit)? = null,
imageLoader: ImageLoader = Coil.imageLoader(ContextAmbient.current),
shouldRefetchOnSizeChange: (currentResult: RequestResult, size: IntSize) -> Boolean = defaultRefetchOnSizeChangeLambda,
onRequestCompleted: (RequestResult) -> Unit = emptySuccessLambda
) {
Expand All @@ -99,6 +103,7 @@ fun CoilImage(
getSuccessPainter = getSuccessPainter,
getFailurePainter = getFailurePainter,
loading = loading,
imageLoader = imageLoader,
shouldRefetchOnSizeChange = shouldRefetchOnSizeChange,
modifier = modifier
)
Expand All @@ -121,6 +126,8 @@ fun CoilImage(
* @param getFailurePainter Optional builder for the [Painter] to be used to draw the failure
* loading result. Passing in `null` will result in falling back to the default [Painter].
* @param loading Content to be displayed when the request is in progress.
* @param imageLoader The [ImageLoader] to use when requesting the image. Defaults to [Coil]'s
* default image loader.
* @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 @@ -135,6 +142,7 @@ fun CoilImage(
getSuccessPainter: @Composable ((SuccessResult) -> Painter)? = null,
getFailurePainter: @Composable ((ErrorResult) -> Painter?)? = null,
loading: @Composable (() -> Unit)? = null,
imageLoader: ImageLoader = Coil.imageLoader(ContextAmbient.current),
shouldRefetchOnSizeChange: (currentResult: RequestResult, size: IntSize) -> Boolean = defaultRefetchOnSizeChangeLambda,
onRequestCompleted: (RequestResult) -> Unit = emptySuccessLambda
) {
Expand All @@ -153,7 +161,9 @@ fun CoilImage(
val callback = remember { mutableStateOf(onRequestCompleted, referentialEqualityPolicy()) }
callback.value = onRequestCompleted

val requestActor = remember(request) { CoilRequestActor(request) }
val requestActor = remember(imageLoader, request) {
CoilRequestActor(imageLoader, request)
}

launchInComposition(requestActor) {
// Launch the Actor
Expand Down Expand Up @@ -234,6 +244,7 @@ private const val UNSPECIFIED = -1
private data class MutableRef<T>(var value: T)

private fun CoilRequestActor(
imageLoader: ImageLoader,
request: ImageRequest
) = RequestActor<IntSize, RequestResult?> { size ->
when {
Expand All @@ -256,7 +267,7 @@ private fun CoilRequestActor(
}
}?.let { transformedRequest ->
// Now execute the request in Coil...
Coil.imageLoader(transformedRequest.context)
imageLoader
.execute(transformedRequest)
.toResult(size)
.also {
Expand Down
10 changes: 10 additions & 0 deletions coil/src/main/java/dev/chrisbanes/accompanist/coil/Crossfade.kt
Expand Up @@ -42,11 +42,13 @@ import androidx.compose.ui.graphics.drawscope.drawCanvas
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.AnimationClockAmbient
import androidx.compose.ui.platform.ContextAmbient
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.toSize
import androidx.core.util.Pools
import coil.Coil
import coil.ImageLoader
import coil.decode.DataSource
import coil.request.ImageRequest

Expand All @@ -69,6 +71,8 @@ private const val DefaultTransitionDuration = 1000
* @param crossfadeDuration The duration of the crossfade animation in milliseconds.
* @param getFailurePainter Optional builder for the [Painter] to be used to draw the failure
* loading result. Passing in `null` will result in falling back to the default [Painter].
* @param imageLoader The [ImageLoader] to use when requesting the image. Defaults to [Coil]'s
* default image loader.
* @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 @@ -82,6 +86,7 @@ fun CoilImageWithCrossfade(
crossfadeDuration: Int = DefaultTransitionDuration,
getFailurePainter: @Composable ((ErrorResult) -> Painter?)? = null,
loading: @Composable (() -> Unit)? = null,
imageLoader: ImageLoader = Coil.imageLoader(ContextAmbient.current),
shouldRefetchOnSizeChange: (currentResult: RequestResult, size: IntSize) -> Boolean = defaultRefetchOnSizeChangeLambda,
onRequestCompleted: (RequestResult) -> Unit = emptySuccessLambda
) {
Expand All @@ -93,6 +98,7 @@ fun CoilImageWithCrossfade(
getFailurePainter = getFailurePainter,
loading = loading,
modifier = modifier,
imageLoader = imageLoader,
shouldRefetchOnSizeChange = shouldRefetchOnSizeChange,
onRequestCompleted = onRequestCompleted
)
Expand All @@ -116,6 +122,8 @@ fun CoilImageWithCrossfade(
* @param crossfadeDuration The duration of the crossfade animation in milliseconds.
* @param getFailurePainter Optional builder for the [Painter] to be used to draw the failure
* loading result. Passing in `null` will result in falling back to the default [Painter].
* @param imageLoader The [ImageLoader] to use when requesting the image. Defaults to [Coil]'s
* default image loader.
* @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 @@ -129,6 +137,7 @@ fun CoilImageWithCrossfade(
crossfadeDuration: Int = DefaultTransitionDuration,
getFailurePainter: @Composable ((ErrorResult) -> Painter?)? = null,
loading: @Composable (() -> Unit)? = null,
imageLoader: ImageLoader = Coil.imageLoader(ContextAmbient.current),
shouldRefetchOnSizeChange: (currentResult: RequestResult, size: IntSize) -> Boolean = defaultRefetchOnSizeChangeLambda,
onRequestCompleted: (RequestResult) -> Unit = emptySuccessLambda
) {
Expand All @@ -139,6 +148,7 @@ fun CoilImageWithCrossfade(
getSuccessPainter = { crossfadePainter(it, durationMs = crossfadeDuration) },
getFailurePainter = getFailurePainter,
loading = loading,
imageLoader = imageLoader,
shouldRefetchOnSizeChange = shouldRefetchOnSizeChange,
modifier = modifier,
onRequestCompleted = onRequestCompleted
Expand Down

0 comments on commit 64646f8

Please sign in to comment.