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

Glide integration library #113

Merged
merged 19 commits into from
Oct 15, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/inspectionProfiles/ktlint.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ plugins {
apply plugin: 'binary-compatibility-validator'
apiValidation {
// Ignore the sample from API tracking/checking
ignoredProjects += ["sample"]
ignoredProjects += ["sample", "imageloading-testutils"]
}

subprojects {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ object Libs {

const val picasso = "com.squareup.picasso:picasso:2.8"

const val glide = "com.github.bumptech.glide:glide:4.11.0"

const val truth = "com.google.truth:truth:1.0.1"

object OkHttp {
Expand Down
8 changes: 6 additions & 2 deletions coil/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,15 @@ dependencies {
implementation Libs.Kotlin.stdlib
implementation Libs.Coroutines.android

// ======================
// Test dependencies
// ======================

androidTestImplementation project(':imageloading-testutils')

androidTestImplementation Libs.junit
androidTestImplementation Libs.truth

androidTestImplementation Libs.OkHttp.mockWebServer

androidTestImplementation Libs.Coroutines.test

androidTestImplementation Libs.AndroidX.Compose.test
Expand Down
14 changes: 0 additions & 14 deletions coil/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,8 @@
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="dev.chrisbanes.accompanist.coil.test">

<uses-sdk android:targetSdkVersion="30" />

<!-- Needed for MockWebServer -->
<uses-permission android:name="android.permission.INTERNET" />

<!-- usesCleartextTraffic=true because we use MockWebServer -->
<application
android:name="dev.chrisbanes.accompanist.coil.CoilTestApplication"
android:usesCleartextTraffic="true">
<activity
android:name="androidx.activity.ComponentActivity"
android:theme="@style/Theme.CoilTest"
tools:replace="android:theme" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package dev.chrisbanes.accompanist.coil

import android.content.ContentResolver
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.preferredSize
Expand All @@ -28,7 +26,6 @@ import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.platform.ContextAmbient
import androidx.compose.ui.platform.testTag
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
Expand All @@ -52,18 +49,16 @@ import coil.request.ImageRequest
import com.google.common.truth.Truth.assertThat
import dev.chrisbanes.accompanist.coil.test.R
import dev.chrisbanes.accompanist.imageloading.ImageLoadState
import dev.chrisbanes.accompanist.imageloading.test.ImageMockWebServer
import dev.chrisbanes.accompanist.imageloading.test.awaitNext
import dev.chrisbanes.accompanist.imageloading.test.receiveBlocking
import dev.chrisbanes.accompanist.imageloading.test.resourceUri
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.withTimeoutOrNull
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import okio.Buffer
import org.junit.After
import org.junit.Before
import org.junit.Rule
Expand All @@ -80,7 +75,7 @@ class CoilTest {
val composeTestRule = createComposeRule()

// Our MockWebServer. We use a response delay to simulate real-world conditions
private val server = coilTestWebServer(responseDelayMs = 200)
private val server = ImageMockWebServer()

@Before
fun setup() {
Expand All @@ -102,7 +97,7 @@ class CoilTest {
composeTestRule.setContent {
CoilImage(
request = ImageRequest.Builder(ContextAmbient.current)
.data(resourceUri(R.raw.sample))
.data(server.url("/image"))
.listener { _, _ -> latch.countDown() }
.build(),
modifier = Modifier.preferredSize(128.dp, 128.dp),
Expand All @@ -127,7 +122,7 @@ class CoilTest {

composeTestRule.setContent {
CoilImage(
data = resourceUri(R.raw.sample),
data = server.url("/image"),
requestBuilder = {
listener { _, _ -> latch.countDown() }
},
Expand Down Expand Up @@ -212,7 +207,7 @@ class CoilTest {

composeTestRule.setContent {
CoilImage(
data = resourceUri(R.drawable.red_rectangle),
data = server.url("/image"),
modifier = Modifier.preferredSize(128.dp, 128.dp),
imageLoader = imageLoader,
onRequestCompleted = { latch.countDown() }
Expand All @@ -231,23 +226,19 @@ class CoilTest {
@SdkSuppress(minSdkVersion = 26) // captureToBitmap is SDK 26+
fun basicLoad_switchData() {
val loadCompleteSignal = Channel<Unit>(Channel.UNLIMITED)
val drawableResId = MutableStateFlow(R.drawable.red_rectangle)
val data = MutableStateFlow(server.url("/red"))

composeTestRule.setContent {
val resId = drawableResId.collectAsState()
val resId = data.collectAsState()
CoilImage(
data = resourceUri(resId.value),
data = resId.value,
modifier = Modifier.preferredSize(128.dp, 128.dp).testTag(CoilTestTags.Image),
onRequestCompleted = { loadCompleteSignal.offer(Unit) }
)
}

// Await the first load
runBlocking {
withTimeout(5000) {
loadCompleteSignal.receive()
}
}
loadCompleteSignal.awaitNext(5, TimeUnit.SECONDS)

// Assert that the content is completely Red
composeTestRule.onNodeWithTag(CoilTestTags.Image)
Expand All @@ -258,14 +249,10 @@ class CoilTest {
.assertPixels { Color.Red }

// Now switch the data URI to the blue drawable
drawableResId.value = R.drawable.blue_rectangle
data.value = server.url("/blue")

// Await the second load
runBlocking {
withTimeout(5000) {
loadCompleteSignal.receive()
}
}
loadCompleteSignal.awaitNext(5, TimeUnit.SECONDS)

// Assert that the content is completely Blue
composeTestRule.onNodeWithTag(CoilTestTags.Image)
Expand All @@ -282,22 +269,21 @@ class CoilTest {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun basicLoad_changeSize() {
val loadCompleteSignal = Channel<Unit>(Channel.UNLIMITED)
val loadCompleteSignal = Channel<ImageLoadState>(Channel.UNLIMITED)
val sizeFlow = MutableStateFlow(128.dp)

composeTestRule.setContent {
val size = sizeFlow.collectAsState()
CoilImage(
data = resourceUri(R.drawable.red_rectangle),
data = server.url("/red"),
modifier = Modifier.preferredSize(size.value).testTag(CoilTestTags.Image),
onRequestCompleted = { loadCompleteSignal.offer(Unit) }
onRequestCompleted = { loadCompleteSignal.offer(it) }
)
}

// Await the first load
runBlocking {
loadCompleteSignal.receive()
}
assertThat(loadCompleteSignal.receiveBlocking())
.isInstanceOf(ImageLoadState.Success::class.java)

// Now change the size
sizeFlow.value = 256.dp
Expand All @@ -318,7 +304,7 @@ class CoilTest {

composeTestRule.setContent {
CoilImage(
data = resourceUri(R.raw.sample),
data = server.url("/image"),
modifier = Modifier.testTag(CoilTestTags.Image),
onRequestCompleted = { latch.countDown() }
)
Expand Down Expand Up @@ -420,7 +406,7 @@ class CoilTest {

composeTestRule.setContent {
CoilImage(
data = resourceUri(R.raw.sample),
data = server.url("/image"),
modifier = Modifier.preferredSize(128.dp, 128.dp).testTag(CoilTestTags.Image),
onRequestCompleted = { latch.countDown() }
) { _ ->
Expand Down Expand Up @@ -520,40 +506,3 @@ private fun noCacheImageLoader(): ImageLoader {
.diskCachePolicy(CachePolicy.DISABLED)
.build()
}

private fun resourceUri(id: Int): Uri {
val packageName = InstrumentationRegistry.getInstrumentation().targetContext.packageName
return "${ContentResolver.SCHEME_ANDROID_RESOURCE}://$packageName/$id".toUri()
}

/**
* [MockWebServer] which returns a valid response at the path `/image`, and a 404 for anything else.
* We add a small delay to simulate 'real-world' network conditions.
*/
private fun coilTestWebServer(responseDelayMs: Long = 0): MockWebServer {
val dispatcher = object : Dispatcher() {
override fun dispatch(request: RecordedRequest): MockResponse = when (request.path) {
"/image" -> {
val res = InstrumentationRegistry.getInstrumentation().targetContext.resources

// Load the image into a Buffer
val imageBuffer = Buffer().apply {
readFrom(res.openRawResource(R.raw.sample))
}

MockResponse()
.setHeadersDelay(responseDelayMs, TimeUnit.MILLISECONDS)
.addHeader("Content-Type", "image/jpeg")
.setBody(imageBuffer)
}
else ->
MockResponse()
.setHeadersDelay(responseDelayMs, TimeUnit.MILLISECONDS)
.setResponseCode(404)
}
}

return MockWebServer().apply {
setDispatcher(dispatcher)
}
}
5 changes: 5 additions & 0 deletions generate_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ mkdir -p $DOCS_ROOT/picasso
cp picasso/images/crossfade.gif $DOCS_ROOT/picasso/crossfade.gif
sed -i.bak 's/images\/crossfade.gif/crossfade.gif/' $DOCS_ROOT/picasso.md

cp glide/README.md $DOCS_ROOT/glide.md
mkdir -p $DOCS_ROOT/glide
cp glide/images/crossfade.gif $DOCS_ROOT/glide/crossfade.gif
sed -i.bak 's/images\/crossfade.gif/crossfade.gif/' $DOCS_ROOT/glide.md

# Convert docs/xxx.md links to just xxx/
sed -i.bak 's/docs\/\([a-zA-Z-]*\).md/\1/' $DOCS_ROOT/index.md

Expand Down
Loading