Migrate to coil3

This commit is contained in:
Benoit Marty 2025-03-03 12:30:17 +01:00
parent 491bb1d8fe
commit a70249769d
43 changed files with 148 additions and 117 deletions

View file

@ -24,8 +24,8 @@ import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight

View file

@ -7,9 +7,9 @@
package io.element.android.libraries.matrix.ui.media
import coil.ImageLoader
import coil.fetch.Fetcher
import coil.request.Options
import coil3.ImageLoader
import coil3.fetch.Fetcher
import coil3.request.Options
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.matrix.api.MatrixClient
@ -24,7 +24,6 @@ internal class AvatarDataFetcherFactory(
return CoilMediaFetcher(
mediaLoader = client.mediaLoader,
mediaData = data.toMediaRequestData(),
options = options
)
}
}

View file

@ -7,16 +7,16 @@
package io.element.android.libraries.matrix.ui.media
import coil.decode.DataSource
import coil.decode.ImageSource
import coil.fetch.FetchResult
import coil.fetch.Fetcher
import coil.fetch.SourceResult
import coil.request.Options
import coil3.decode.DataSource
import coil3.decode.ImageSource
import coil3.fetch.FetchResult
import coil3.fetch.Fetcher
import coil3.fetch.SourceFetchResult
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.media.toFile
import okio.Buffer
import okio.FileSystem
import okio.Path.Companion.toOkioPath
import timber.log.Timber
import java.nio.ByteBuffer
@ -24,7 +24,6 @@ import java.nio.ByteBuffer
internal class CoilMediaFetcher(
private val mediaLoader: MatrixMediaLoader,
private val mediaData: MediaRequestData,
private val options: Options
) : Fetcher {
override suspend fun fetch(): FetchResult? {
if (mediaData.source == null) {
@ -32,8 +31,8 @@ internal class CoilMediaFetcher(
return null
}
return when (mediaData.kind) {
is MediaRequestData.Kind.Content -> fetchContent(mediaData.source, options)
is MediaRequestData.Kind.Thumbnail -> fetchThumbnail(mediaData.source, mediaData.kind, options)
is MediaRequestData.Kind.Content -> fetchContent(mediaData.source)
is MediaRequestData.Kind.Thumbnail -> fetchThumbnail(mediaData.source, mediaData.kind)
is MediaRequestData.Kind.File -> fetchFile(mediaData.source, mediaData.kind)
}
}
@ -47,8 +46,12 @@ internal class CoilMediaFetcher(
return mediaLoader.downloadMediaFile(mediaSource, kind.mimeType, kind.fileName)
.map { mediaFile ->
val file = mediaFile.toFile()
SourceResult(
source = ImageSource(file = file.toOkioPath(), closeable = mediaFile),
SourceFetchResult(
source = ImageSource(
file = file.toOkioPath(),
fileSystem = FileSystem.SYSTEM,
closeable = mediaFile,
),
mimeType = null,
dataSource = DataSource.DISK
)
@ -59,37 +62,40 @@ internal class CoilMediaFetcher(
.getOrNull()
}
private suspend fun fetchContent(mediaSource: MediaSource, options: Options): FetchResult? {
private suspend fun fetchContent(mediaSource: MediaSource): FetchResult? {
return mediaLoader.loadMediaContent(
source = mediaSource,
).map { byteArray ->
byteArray.asSourceResult(options)
byteArray.asSourceResult()
}.onFailure {
Timber.e(it)
}.getOrNull()
}
private suspend fun fetchThumbnail(mediaSource: MediaSource, kind: MediaRequestData.Kind.Thumbnail, options: Options): FetchResult? {
private suspend fun fetchThumbnail(mediaSource: MediaSource, kind: MediaRequestData.Kind.Thumbnail): FetchResult? {
return mediaLoader.loadMediaThumbnail(
source = mediaSource,
width = kind.width,
height = kind.height,
).map { byteArray ->
byteArray.asSourceResult(options)
byteArray.asSourceResult()
}.onFailure {
Timber.e(it)
}.getOrNull()
}
private fun ByteArray.asSourceResult(options: Options): SourceResult {
private fun ByteArray.asSourceResult(): SourceFetchResult {
val byteBuffer = ByteBuffer.wrap(this)
val bufferedSource = try {
Buffer().apply { write(byteBuffer) }
} finally {
byteBuffer.position(0)
}
return SourceResult(
source = ImageSource(bufferedSource, options.context),
return SourceFetchResult(
source = ImageSource(
source = bufferedSource,
fileSystem = FileSystem.SYSTEM,
),
mimeType = null,
dataSource = DataSource.MEMORY
)

View file

@ -9,10 +9,10 @@ package io.element.android.libraries.matrix.ui.media
import android.content.Context
import android.os.Build
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil3.ImageLoader
import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
@ -33,11 +33,17 @@ class DefaultLoggedInImageLoaderFactory @Inject constructor(
override fun newImageLoader(matrixClient: MatrixClient): ImageLoader {
return ImageLoader
.Builder(context)
.okHttpClient { okHttpClient.get() }
.components {
add(
OkHttpNetworkFetcherFactory(
callFactory = {
okHttpClient.get()
}
)
)
// Add gif support
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
add(ImageDecoderDecoder.Factory())
add(AnimatedImageDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
@ -53,11 +59,19 @@ class DefaultLoggedInImageLoaderFactory @Inject constructor(
class NotLoggedInImageLoaderFactory @Inject constructor(
@ApplicationContext private val context: Context,
private val okHttpClient: Provider<OkHttpClient>,
) : ImageLoaderFactory {
override fun newImageLoader(): ImageLoader {
) {
fun newImageLoader(): ImageLoader {
return ImageLoader
.Builder(context)
.okHttpClient { okHttpClient.get() }
.components {
add(
OkHttpNetworkFetcherFactory(
callFactory = {
okHttpClient.get()
}
)
)
}
.build()
}
}

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.matrix.ui.media
import coil.ImageLoader
import coil3.ImageLoader
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn

View file

@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.ui.media
import io.element.android.libraries.matrix.api.media.MediaSource
/**
* Can be use with [coil.compose.AsyncImage] to load a [MediaSource].
* Can be use with [coil3.compose.AsyncImage] to load a [MediaSource].
* This will go internally through our [CoilMediaFetcher].
*
* Example of usage:

View file

@ -7,9 +7,9 @@
package io.element.android.libraries.matrix.ui.media
import coil.ImageLoader
import coil.fetch.Fetcher
import coil.request.Options
import coil3.ImageLoader
import coil3.fetch.Fetcher
import coil3.request.Options
import io.element.android.libraries.matrix.api.MatrixClient
internal class MediaRequestDataFetcherFactory(
@ -23,7 +23,6 @@ internal class MediaRequestDataFetcherFactory(
return CoilMediaFetcher(
mediaLoader = client.mediaLoader,
mediaData = data,
options = options
)
}
}

View file

@ -7,8 +7,8 @@
package io.element.android.libraries.matrix.ui.media
import coil.key.Keyer
import coil.request.Options
import coil3.key.Keyer
import coil3.request.Options
import io.element.android.libraries.designsystem.components.avatar.AvatarData
internal class AvatarDataKeyer : Keyer<AvatarData> {

View file

@ -8,7 +8,7 @@
package io.element.android.libraries.matrix.ui.media
import androidx.test.platform.app.InstrumentationRegistry
import coil.ImageLoader
import coil3.ImageLoader
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.test.A_SESSION_ID

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.matrix.ui.media
import coil.ImageLoader
import coil3.ImageLoader
import io.element.android.libraries.matrix.api.MatrixClient
class FakeLoggedInImageLoaderFactory(