From 6fd810d54ea52aff03f0f9c243bdb92404dfdff5 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Fri, 26 Jun 2026 08:03:31 +0200 Subject: [PATCH 1/2] Add GIF support to Coil ImageLoader --- collect_app/build.gradle | 1 + .../initialization/ApplicationInitializer.kt | 20 +++++++++++++++++++ gradle/libs.versions.toml | 1 + 3 files changed, 22 insertions(+) diff --git a/collect_app/build.gradle b/collect_app/build.gradle index bc8020389b6..4d09adb5143 100644 --- a/collect_app/build.gradle +++ b/collect_app/build.gradle @@ -350,6 +350,7 @@ dependencies { implementation(libs.androidXComposeMaterialIcons) implementation(libs.androidXComposePreview) implementation(libs.coil) + implementation(libs.coil.gif) testImplementation project(':forms-test') diff --git a/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt b/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt index 9fef37d94c5..52fdf5474cb 100644 --- a/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt +++ b/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt @@ -1,8 +1,13 @@ package org.odk.collect.android.application.initialization import android.app.Application +import android.os.Build import androidx.appcompat.app.AppCompatDelegate import androidx.startup.AppInitializer +import coil3.ImageLoader +import coil3.SingletonImageLoader +import coil3.gif.AnimatedImageDecoder +import coil3.gif.GifDecoder import net.danlew.android.joda.JodaTimeInitializer import org.odk.collect.analytics.Analytics import org.odk.collect.android.BuildConfig @@ -63,6 +68,21 @@ class ApplicationInitializer( initializeLogging() AppInitializer.getInstance(context).initializeComponent(JodaTimeInitializer::class.java) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) + initializeImageLoader() + } + + private fun initializeImageLoader() { + SingletonImageLoader.setSafe { context -> + ImageLoader.Builder(context) + .components { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + add(AnimatedImageDecoder.Factory()) + } else { + add(GifDecoder.Factory()) + } + } + .build() + } } private fun initializeLocale() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0a370e8d4ae..721403bdf03 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -101,6 +101,7 @@ jsoup = { group = "org.jsoup", name = "jsoup", version = "1.22.1" } mlkit-barcodescanning = { group = "com.google.android.gms", name = "play-services-mlkit-barcode-scanning", version = "18.3.1" } runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata" } coil = { group = "io.coil-kt.coil3", name = "coil-compose", version = "3.4.0" } +coil-gif = { group = "io.coil-kt.coil3", name = "coil-gif", version = "3.4.0" } # Test dependencies junit = { group = "junit", name = "junit", version = "4.13.2" } From 79c62dd2d3db9f27eedccec042ae2cc0837d2d09 Mon Sep 17 00:00:00 2001 From: Grzegorz Orczykowski Date: Tue, 30 Jun 2026 10:14:29 +0200 Subject: [PATCH 2/2] Extract Coil setup into CoilInitializer --- .../initialization/ApplicationInitializer.kt | 21 +--------------- .../initialization/CoilInitializer.kt | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 collect_app/src/main/java/org/odk/collect/android/application/initialization/CoilInitializer.kt diff --git a/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt b/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt index 52fdf5474cb..acba5b77846 100644 --- a/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt +++ b/collect_app/src/main/java/org/odk/collect/android/application/initialization/ApplicationInitializer.kt @@ -1,13 +1,8 @@ package org.odk.collect.android.application.initialization import android.app.Application -import android.os.Build import androidx.appcompat.app.AppCompatDelegate import androidx.startup.AppInitializer -import coil3.ImageLoader -import coil3.SingletonImageLoader -import coil3.gif.AnimatedImageDecoder -import coil3.gif.GifDecoder import net.danlew.android.joda.JodaTimeInitializer import org.odk.collect.analytics.Analytics import org.odk.collect.android.BuildConfig @@ -61,6 +56,7 @@ class ApplicationInitializer( ).initialize() mapsInitializer.initialize() JavaRosaInitializer(propertyManager, projectsDataService, entitiesRepositoryProvider).initialize() + CoilInitializer().initialize() } private fun initializeFrameworks() { @@ -68,21 +64,6 @@ class ApplicationInitializer( initializeLogging() AppInitializer.getInstance(context).initializeComponent(JodaTimeInitializer::class.java) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - initializeImageLoader() - } - - private fun initializeImageLoader() { - SingletonImageLoader.setSafe { context -> - ImageLoader.Builder(context) - .components { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - add(AnimatedImageDecoder.Factory()) - } else { - add(GifDecoder.Factory()) - } - } - .build() - } } private fun initializeLocale() { diff --git a/collect_app/src/main/java/org/odk/collect/android/application/initialization/CoilInitializer.kt b/collect_app/src/main/java/org/odk/collect/android/application/initialization/CoilInitializer.kt new file mode 100644 index 00000000000..28c46be86ca --- /dev/null +++ b/collect_app/src/main/java/org/odk/collect/android/application/initialization/CoilInitializer.kt @@ -0,0 +1,24 @@ +package org.odk.collect.android.application.initialization + +import android.os.Build +import coil3.ImageLoader +import coil3.SingletonImageLoader +import coil3.gif.AnimatedImageDecoder +import coil3.gif.GifDecoder + +class CoilInitializer { + + fun initialize() { + SingletonImageLoader.setSafe { context -> + ImageLoader.Builder(context) + .components { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + add(AnimatedImageDecoder.Factory()) + } else { + add(GifDecoder.Factory()) + } + } + .build() + } + } +}