From d859b3cfc76b87d531c4dcab2505d59597407bdc Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 5 Apr 2025 12:12:55 +0200 Subject: [PATCH] Migrate from coil2 to coil3 - Use BOM platform dependency. - Remove -kt suffix from dependency name has they serve no real purpose. - Add `coil-network` artifact to configure `CallFactory`. - Although "First party Decoder" `SvgDecoder` is now automatically added to each new ImageLoader through a service loader, keeping it in code prevents us from removing the dependency that would appear unused otherwise. - Replace explicit `respectCacheHeaders(false)` with `CacheStrategy::DEFAULT` which does not respect cache-control headers. - Migrate `ImageLoaderFactory` to `SingletonImageLoader.Factory` - Inline TOML dependencies (see https://github.com/android/nowinandroid/pull/1856) docs: https://coil-kt.github.io/coil/upgrading_to_coil3/ --- .../dependencies/releaseRuntimeClasspath.txt | 58 +++++++++++++------ app/build.gradle.kts | 3 +- .../prodReleaseRuntimeClasspath.txt | 50 ++++++++++++---- .../apps/nowinandroid/NiaApplication.kt | 9 +-- core/designsystem/build.gradle.kts | 3 +- .../component/DynamicAsyncImage.kt | 8 +-- core/network/build.gradle.kts | 5 +- .../core/network/di/NetworkModule.kt | 26 ++++++--- core/ui/build.gradle.kts | 4 +- .../nowinandroid/core/ui/NewsResourceCard.kt | 4 +- gradle/libs.versions.toml | 9 +-- 11 files changed, 123 insertions(+), 56 deletions(-) diff --git a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt index 587e4feba..e5dbd284f 100644 --- a/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt +++ b/app-nia-catalog/dependencies/releaseRuntimeClasspath.txt @@ -4,7 +4,7 @@ androidx.activity:activity:1.9.3 androidx.annotation:annotation-experimental:1.4.1 androidx.annotation:annotation-jvm:1.9.1 androidx.annotation:annotation:1.9.1 -androidx.appcompat:appcompat-resources:1.6.1 +androidx.appcompat:appcompat-resources:1.7.0 androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-runtime:2.2.0 androidx.autofill:autofill:1.0.0 @@ -52,8 +52,8 @@ androidx.compose.ui:ui-util:1.8.0-beta02 androidx.compose.ui:ui:1.8.0-beta02 androidx.compose:compose-bom-alpha:2025.02.00 androidx.concurrent:concurrent-futures:1.1.0 -androidx.core:core-ktx:1.13.1 -androidx.core:core:1.13.1 +androidx.core:core-ktx:1.15.0 +androidx.core:core:1.15.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.0.0 androidx.emoji2:emoji2:1.4.0 @@ -82,7 +82,7 @@ androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7 androidx.lifecycle:lifecycle-viewmodel:2.8.7 androidx.loader:loader:1.0.0 androidx.metrics:metrics-performance:1.0.0-beta01 -androidx.profileinstaller:profileinstaller:1.4.0 +androidx.profileinstaller:profileinstaller:1.4.1 androidx.savedstate:savedstate-ktx:1.2.1 androidx.savedstate:savedstate:1.2.1 androidx.startup:startup-runtime:1.1.1 @@ -96,30 +96,52 @@ androidx.window.extensions.core:core:1.0.0 androidx.window:window-core-android:1.3.0 androidx.window:window-core:1.3.0 androidx.window:window:1.3.0 -com.google.accompanist:accompanist-drawablepainter:0.32.0 +com.google.accompanist:accompanist-drawablepainter:0.36.0 com.google.code.findbugs:jsr305:3.0.2 com.google.dagger:dagger-lint-aar:2.56 com.google.dagger:dagger:2.56 com.google.dagger:hilt-android:2.56 com.google.dagger:hilt-core:2.56 com.google.guava:listenablefuture:1.0 -com.squareup.okhttp3:okhttp:4.12.0 -com.squareup.okio:okio-jvm:3.9.0 -com.squareup.okio:okio:3.9.0 -io.coil-kt:coil-base:2.7.0 -io.coil-kt:coil-compose-base:2.7.0 -io.coil-kt:coil-compose:2.7.0 -io.coil-kt:coil:2.7.0 +com.squareup.okio:okio-jvm:3.10.2 +com.squareup.okio:okio:3.10.2 +io.coil-kt.coil3:coil-android:3.1.0 +io.coil-kt.coil3:coil-bom:3.1.0 +io.coil-kt.coil3:coil-compose-android:3.1.0 +io.coil-kt.coil3:coil-compose-core-android:3.1.0 +io.coil-kt.coil3:coil-compose-core:3.1.0 +io.coil-kt.coil3:coil-compose:3.1.0 +io.coil-kt.coil3:coil-core-android:3.1.0 +io.coil-kt.coil3:coil-core:3.1.0 +io.coil-kt.coil3:coil:3.1.0 jakarta.inject:jakarta.inject-api:2.0.1 javax.inject:javax.inject:1 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.4 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.4 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.4 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.4 +org.jetbrains.compose.animation:animation-core:1.7.3 +org.jetbrains.compose.animation:animation:1.7.3 +org.jetbrains.compose.annotation-internal:annotation:1.7.3 +org.jetbrains.compose.collection-internal:collection:1.7.3 +org.jetbrains.compose.foundation:foundation-layout:1.7.3 +org.jetbrains.compose.foundation:foundation:1.7.3 +org.jetbrains.compose.runtime:runtime-saveable:1.7.3 +org.jetbrains.compose.runtime:runtime:1.7.3 +org.jetbrains.compose.ui:ui-geometry:1.7.3 +org.jetbrains.compose.ui:ui-graphics:1.7.3 +org.jetbrains.compose.ui:ui-text:1.7.3 +org.jetbrains.compose.ui:ui-unit:1.7.3 +org.jetbrains.compose.ui:ui-util:1.7.3 +org.jetbrains.compose.ui:ui:1.7.3 org.jetbrains.kotlin:kotlin-stdlib-common:2.1.10 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0 org.jetbrains.kotlin:kotlin-stdlib:2.1.10 -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 +org.jetbrains.kotlinx:atomicfu-jvm:0.23.2 +org.jetbrains.kotlinx:atomicfu:0.23.2 +org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1 +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1 +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1 +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1 org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1 org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 org.jetbrains:annotations:23.0.0 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6aec2d1bc..5b6374396 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -101,7 +101,8 @@ dependencies { implementation(libs.androidx.tracing.ktx) implementation(libs.androidx.window.core) implementation(libs.kotlinx.coroutines.guava) - implementation(libs.coil.kt) + implementation(platform(libs.coil.bom)) + implementation(libs.coil) implementation(libs.kotlinx.serialization.json) ksp(libs.hilt.compiler) diff --git a/app/dependencies/prodReleaseRuntimeClasspath.txt b/app/dependencies/prodReleaseRuntimeClasspath.txt index 5d55c5a67..1708d217d 100644 --- a/app/dependencies/prodReleaseRuntimeClasspath.txt +++ b/app/dependencies/prodReleaseRuntimeClasspath.txt @@ -147,7 +147,7 @@ androidx.window:window:1.3.0 androidx.work:work-runtime-ktx:2.10.0 androidx.work:work-runtime:2.10.0 com.caverock:androidsvg-aar:1.4 -com.google.accompanist:accompanist-drawablepainter:0.32.0 +com.google.accompanist:accompanist-drawablepainter:0.36.0 com.google.accompanist:accompanist-permissions:0.37.0 com.google.android.datatransport:transport-api:3.2.0 com.google.android.datatransport:transport-backend-cct:3.3.0 @@ -200,24 +200,54 @@ com.google.protobuf:protobuf-javalite:4.29.2 com.google.protobuf:protobuf-kotlin-lite:4.29.2 com.squareup.okhttp3:logging-interceptor:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 -com.squareup.okio:okio-jvm:3.9.0 -com.squareup.okio:okio:3.9.0 +com.squareup.okio:okio-jvm:3.10.2 +com.squareup.okio:okio:3.10.2 com.squareup.retrofit2:converter-kotlinx-serialization:2.11.0 com.squareup.retrofit2:retrofit:2.11.0 -io.coil-kt:coil-base:2.7.0 -io.coil-kt:coil-compose-base:2.7.0 -io.coil-kt:coil-compose:2.7.0 -io.coil-kt:coil-svg:2.7.0 -io.coil-kt:coil:2.7.0 +io.coil-kt.coil3:coil-android:3.1.0 +io.coil-kt.coil3:coil-bom:3.1.0 +io.coil-kt.coil3:coil-compose-android:3.1.0 +io.coil-kt.coil3:coil-compose-core-android:3.1.0 +io.coil-kt.coil3:coil-compose-core:3.1.0 +io.coil-kt.coil3:coil-compose:3.1.0 +io.coil-kt.coil3:coil-core-android:3.1.0 +io.coil-kt.coil3:coil-core:3.1.0 +io.coil-kt.coil3:coil-network-core-android:3.1.0 +io.coil-kt.coil3:coil-network-core:3.1.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.1.0 +io.coil-kt.coil3:coil-network-okhttp:3.1.0 +io.coil-kt.coil3:coil-svg-android:3.1.0 +io.coil-kt.coil3:coil-svg:3.1.0 +io.coil-kt.coil3:coil:3.1.0 jakarta.inject:jakarta.inject-api:2.0.1 javax.inject:javax.inject:1 org.checkerframework:checker-qual:3.12.0 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.4 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.4 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.4 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.4 +org.jetbrains.compose.animation:animation-core:1.7.3 +org.jetbrains.compose.animation:animation:1.7.3 +org.jetbrains.compose.annotation-internal:annotation:1.7.3 +org.jetbrains.compose.collection-internal:collection:1.7.3 +org.jetbrains.compose.foundation:foundation-layout:1.7.3 +org.jetbrains.compose.foundation:foundation:1.7.3 +org.jetbrains.compose.runtime:runtime-saveable:1.7.3 +org.jetbrains.compose.runtime:runtime:1.7.3 +org.jetbrains.compose.ui:ui-geometry:1.7.3 +org.jetbrains.compose.ui:ui-graphics:1.7.3 +org.jetbrains.compose.ui:ui-text:1.7.3 +org.jetbrains.compose.ui:ui-unit:1.7.3 +org.jetbrains.compose.ui:ui-util:1.7.3 +org.jetbrains.compose.ui:ui:1.7.3 org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.9.22 org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 org.jetbrains.kotlin:kotlin-stdlib-common:2.1.10 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 org.jetbrains.kotlin:kotlin-stdlib:2.1.10 +org.jetbrains.kotlinx:atomicfu-jvm:0.23.2 +org.jetbrains.kotlinx:atomicfu:0.23.2 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1 org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1 diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt index 4975e5d65..5c3bafaf9 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/NiaApplication.kt @@ -20,8 +20,9 @@ import android.app.Application import android.content.pm.ApplicationInfo import android.os.StrictMode import android.os.StrictMode.ThreadPolicy.Builder -import coil.ImageLoader -import coil.ImageLoaderFactory +import coil3.ImageLoader +import coil3.PlatformContext +import coil3.SingletonImageLoader import com.google.samples.apps.nowinandroid.sync.initializers.Sync import com.google.samples.apps.nowinandroid.util.ProfileVerifierLogger import dagger.hilt.android.HiltAndroidApp @@ -31,7 +32,7 @@ import javax.inject.Inject * [Application] class for NiA */ @HiltAndroidApp -class NiaApplication : Application(), ImageLoaderFactory { +class NiaApplication : Application(), SingletonImageLoader.Factory { @Inject lateinit var imageLoader: dagger.Lazy @@ -48,7 +49,7 @@ class NiaApplication : Application(), ImageLoaderFactory { profileVerifierLogger() } - override fun newImageLoader(): ImageLoader = imageLoader.get() + override fun newImageLoader(context: PlatformContext): ImageLoader = imageLoader.get() /** * Return true if the application is debuggable. diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index aac2ddb8f..a32daf773 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -36,7 +36,8 @@ dependencies { api(libs.androidx.compose.runtime) api(libs.androidx.compose.ui.util) - implementation(libs.coil.kt.compose) + implementation(platform(libs.coil.bom)) + implementation(libs.coil.compose) testImplementation(libs.androidx.compose.ui.test) testImplementation(libs.androidx.compose.ui.testManifest) diff --git a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt index 1557cac06..fb7d15cf9 100644 --- a/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt +++ b/core/designsystem/src/main/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/component/DynamicAsyncImage.kt @@ -35,10 +35,10 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import coil.compose.AsyncImagePainter.State.Error -import coil.compose.AsyncImagePainter.State.Loading -import coil.compose.rememberAsyncImagePainter +import coil3.compose.AsyncImage +import coil3.compose.AsyncImagePainter.State.Error +import coil3.compose.AsyncImagePainter.State.Loading +import coil3.compose.rememberAsyncImagePainter import com.google.samples.apps.nowinandroid.core.designsystem.R import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index d12482a56..3923c03b8 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -43,8 +43,9 @@ dependencies { api(projects.core.common) api(projects.core.model) - implementation(libs.coil.kt) - implementation(libs.coil.kt.svg) + implementation(platform(libs.coil.bom)) + implementation(libs.coil.network) + implementation(libs.coil.svg) implementation(libs.kotlinx.serialization.json) implementation(libs.okhttp.logging) implementation(libs.retrofit.core) diff --git a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt index a97540f2b..105f6c714 100644 --- a/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/google/samples/apps/nowinandroid/core/network/di/NetworkModule.kt @@ -18,9 +18,12 @@ package com.google.samples.apps.nowinandroid.core.network.di import android.content.Context import androidx.tracing.trace -import coil.ImageLoader -import coil.decode.SvgDecoder -import coil.util.DebugLogger +import coil3.ImageLoader +import coil3.annotation.ExperimentalCoilApi +import coil3.network.CacheStrategy +import coil3.network.okhttp.OkHttpNetworkFetcherFactory +import coil3.svg.SvgDecoder +import coil3.util.DebugLogger import com.google.samples.apps.nowinandroid.core.network.BuildConfig import com.google.samples.apps.nowinandroid.core.network.demo.DemoAssetManager import dagger.Module @@ -80,11 +83,18 @@ internal object NetworkModule { @ApplicationContext application: Context, ): ImageLoader = trace("NiaImageLoader") { ImageLoader.Builder(application) - .callFactory { okHttpCallFactory.get() } - .components { add(SvgDecoder.Factory()) } - // Assume most content images are versioned urls - // but some problematic images are fetching each time - .respectCacheHeaders(false) + .components { + add( + @OptIn(ExperimentalCoilApi::class) + OkHttpNetworkFetcherFactory( + callFactory = okHttpCallFactory::get, + // Assume most content images are versioned urls + // but some problematic images are fetching each time + cacheStrategy = CacheStrategy::DEFAULT, + ), + ) + add(SvgDecoder.Factory()) + } .apply { if (BuildConfig.DEBUG) { logger(DebugLogger()) diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 5606cb5d1..3a78af1bc 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -30,8 +30,8 @@ dependencies { api(projects.core.model) implementation(libs.androidx.browser) - implementation(libs.coil.kt) - implementation(libs.coil.kt.compose) + implementation(platform(libs.coil.bom)) + implementation(libs.coil.compose) androidTestImplementation(libs.bundles.androidx.compose.ui.test) androidTestImplementation(projects.core.testing) diff --git a/core/ui/src/main/kotlin/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core/ui/src/main/kotlin/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index 862aec6b2..baa86159d 100644 --- a/core/ui/src/main/kotlin/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core/ui/src/main/kotlin/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -64,8 +64,8 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import coil.compose.AsyncImagePainter -import coil.compose.rememberAsyncImagePainter +import coil3.compose.AsyncImagePainter +import coil3.compose.rememberAsyncImagePainter import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 477dde916..930f44b44 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,6 @@ androidxTracing = "1.3.0-alpha02" androidxUiAutomator = "2.3.0" androidxWindowManager = "1.3.0" androidxWork = "2.10.0" -coil = "2.7.0" dependencyGuard = "0.5.0" firebaseBom = "33.7.0" firebaseCrashlyticsPlugin = "3.0.2" @@ -110,9 +109,11 @@ androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", versi androidx-window-core = { group = "androidx.window", name = "window-core", version.ref = "androidxWindowManager" } androidx-work-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidxWork" } androidx-work-testing = { group = "androidx.work", name = "work-testing", version.ref = "androidxWork" } -coil-kt = { group = "io.coil-kt", name = "coil", version.ref = "coil" } -coil-kt-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } -coil-kt-svg = { group = "io.coil-kt", name = "coil-svg", version.ref = "coil" } +coil = { module = "io.coil-kt.coil3:coil" } +coil-bom = "io.coil-kt.coil3:coil-bom:3.1.0" +coil-compose = { module = "io.coil-kt.coil3:coil-compose" } +coil-network = { module = "io.coil-kt.coil3:coil-network-okhttp" } +coil-svg = { module = "io.coil-kt.coil3:coil-svg" } firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" } firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" } firebase-cloud-messaging = { group = "com.google.firebase", name = "firebase-messaging" }