From 545d807f9aed27a83ef6a0fb1be807161c5ee330 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:39:21 +0000 Subject: [PATCH 01/99] Update plugin org.jetbrains.intellij to v1.16.0 --- app/intellij-plugin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/intellij-plugin/build.gradle.kts b/app/intellij-plugin/build.gradle.kts index 94387650..591b17c3 100644 --- a/app/intellij-plugin/build.gradle.kts +++ b/app/intellij-plugin/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.jetbrains.intellij") version "1.15.0" + id("org.jetbrains.intellij") version "1.16.0" java id("app.kotlin.jvm") id("app.compose.multiplatform") From 9527fe760fa00639400973943cc04149d9082e1a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Oct 2023 04:15:10 +0000 Subject: [PATCH 02/99] Update roborazzi to v1.6.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c2f8986e..6d92df67 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ androidx-test-junit = "1.1.5" androidx-test-espresso = "3.5.1" androidx-test-uiautomator = "2.2.0" profileinstaller = "1.3.1" -roborazzi = "1.6.0-rc-1" +roborazzi = "1.6.0" robolectric = "4.10.3" poko = "0.15.0" turbine = "1.0.0" From 5c7171395a5dce2f36eb067ebd3f64c2da9edd69 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:04:49 +0800 Subject: [PATCH 03/99] remove suspend for Decoder.Factory --- .../imageloader/component/decoder/BitmapFactoryDecoder.kt | 2 +- .../com/seiko/imageloader/component/decoder/GifDecoder.kt | 2 +- .../imageloader/component/decoder/ImageDecoderDecoder.kt | 2 +- .../com/seiko/imageloader/component/decoder/SvgDecoder.kt | 2 +- .../kotlin/com/seiko/imageloader/component/decoder/Decoder.kt | 4 ++-- .../com/seiko/imageloader/component/decoder/GifDecoder.kt | 2 +- .../seiko/imageloader/component/decoder/SkiaImageDecoder.kt | 2 +- .../com/seiko/imageloader/component/decoder/SvgDecoder.kt | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 4dddf97c..3a3b0f3f 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -163,7 +163,7 @@ class BitmapFactoryDecoder private constructor( private val parallelismLock = Semaphore(maxParallelism) - override suspend fun create(source: DecodeSource, options: Options): Decoder { + override fun create(source: DecodeSource, options: Options): Decoder { return BitmapFactoryDecoder( context = context ?: options.androidContext, source = source, diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 5902c5b7..c67ec4eb 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -72,7 +72,7 @@ class GifDecoder private constructor( class Factory @JvmOverloads constructor( private val enforceMinimumFrameDelay: Boolean = true, ) : Decoder.Factory { - override suspend fun create(source: DecodeSource, options: Options): Decoder? { + override fun create(source: DecodeSource, options: Options): Decoder? { if (!options.playAnimate) return null if (!isGif(source.source)) return null return GifDecoder(source, options, enforceMinimumFrameDelay) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 624efb92..9da950f5 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -175,7 +175,7 @@ class ImageDecoderDecoder private constructor( private val enforceMinimumFrameDelay: Boolean = true, ) : Decoder.Factory { - override suspend fun create(source: DecodeSource, options: Options): Decoder? { + override fun create(source: DecodeSource, options: Options): Decoder? { if (!options.playAnimate) return null if (!isApplicable(source.source)) return null return ImageDecoderDecoder( diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 9a6584ad..70361082 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -32,7 +32,7 @@ class SvgDecoder private constructor( private val density: Density? = null, ) : Decoder.Factory { - override suspend fun create(source: DecodeSource, options: Options): Decoder? { + override fun create(source: DecodeSource, options: Options): Decoder? { if (!isApplicable(source)) return null return SvgDecoder( source = source, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt index 9944c65a..c31c9222 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt @@ -8,8 +8,8 @@ typealias DecodeSource = ImageResult.Source interface Decoder { suspend fun decode(): DecodeResult? - interface Factory { - suspend fun create(source: DecodeSource, options: Options): Decoder? + fun interface Factory { + fun create(source: DecodeSource, options: Options): Decoder? } } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 0f36064d..3f2d3f52 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -25,7 +25,7 @@ class GifDecoder private constructor( } class Factory : Decoder.Factory { - override suspend fun create(source: DecodeSource, options: Options): Decoder? { + override fun create(source: DecodeSource, options: Options): Decoder? { if (!options.playAnimate) return null if (!isGif(source.source)) return null return GifDecoder(source.source, options) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index 160dda00..06414aed 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -54,7 +54,7 @@ class SkiaImageDecoder private constructor( private val parallelismLock = Semaphore(maxParallelism) - override suspend fun create(source: DecodeSource, options: Options): Decoder { + override fun create(source: DecodeSource, options: Options): Decoder { return SkiaImageDecoder( source = source.source, options = options, diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 84caa2ee..f83e6482 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -31,7 +31,7 @@ class SvgDecoder private constructor( class Factory( private val density: Density, ) : Decoder.Factory { - override suspend fun create(source: DecodeSource, options: Options): Decoder? { + override fun create(source: DecodeSource, options: Options): Decoder? { if (!isApplicable(source)) return null return SvgDecoder( source = source.source, From 53b1319cbfce6923c953113718fd2cfbf8503066 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:04:56 +0800 Subject: [PATCH 04/99] add Fetcher&Decoder lambda factory --- .../kotlin/com/seiko/imageloader/component/decoder/Decoder.kt | 4 ++++ .../kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt index c31c9222..47880587 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt @@ -13,6 +13,10 @@ interface Decoder { } } +fun Decoder(block: () -> DecodeResult?) = object : Decoder { + override suspend fun decode(): DecodeResult? = block() +} + sealed interface DecodeResult { @Poko class Bitmap( val bitmap: com.seiko.imageloader.Bitmap, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt index 9bbb4ca5..d6e1c948 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt @@ -13,6 +13,10 @@ interface Fetcher { } } +fun Fetcher(block: suspend () -> FetchResult?) = object : Fetcher { + override suspend fun fetch(): FetchResult? = block() +} + sealed interface FetchResult { @Poko class Source( val source: BufferedSource, From 7e8dc35ad73ae9ced6ec5afb3be1ca636478f9a2 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:06:22 +0800 Subject: [PATCH 05/99] refactor ComponentRegistry --- .../component/ComponentRegistry.kt | 20 +++++-------- .../component/ComponentRegistryBuilder.kt | 28 +++++++++++-------- .../seiko/imageloader/model/ImageRequest.kt | 2 +- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistry.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistry.kt index 96317dd3..1ac0a18a 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistry.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistry.kt @@ -1,5 +1,6 @@ package com.seiko.imageloader.component +import com.seiko.imageloader.Poko import com.seiko.imageloader.component.decoder.DecodeSource import com.seiko.imageloader.component.decoder.Decoder import com.seiko.imageloader.component.fetcher.Fetcher @@ -8,11 +9,11 @@ import com.seiko.imageloader.component.mapper.Mapper import com.seiko.imageloader.option.Options import com.seiko.imageloader.util.forEachIndices -class ComponentRegistry internal constructor( - private val mappers: List>, - private val keyers: List, - private val fetcherFactories: List, - private val decoderFactories: List, +@Poko class ComponentRegistry internal constructor( + val mappers: List>, + val keyers: List, + val fetcherFactories: List, + val decoderFactories: List, ) { internal fun merge(component: ComponentRegistry) = ComponentRegistry( mappers = mappers + component.mappers, @@ -21,13 +22,6 @@ class ComponentRegistry internal constructor( decoderFactories = decoderFactories + component.decoderFactories, ) - internal fun newBuilder() = ComponentRegistryBuilder( - mappers = mappers.toMutableList(), - keyers = keyers.toMutableList(), - fetcherFactories = fetcherFactories.toMutableList(), - decoderFactories = decoderFactories.toMutableList(), - ) - fun map(data: Any, options: Options): Any { var mappedData = data mappers.forEachIndices { mapper -> @@ -55,7 +49,7 @@ class ComponentRegistry internal constructor( throw RuntimeException("Unable to create a fetcher that supports: $data") } - suspend fun decode( + fun decode( source: DecodeSource, options: Options, startIndex: Int = 0, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistryBuilder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistryBuilder.kt index 73d6a62c..55ad49a5 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistryBuilder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/ComponentRegistryBuilder.kt @@ -5,29 +5,33 @@ import com.seiko.imageloader.component.fetcher.Fetcher import com.seiko.imageloader.component.keyer.Keyer import com.seiko.imageloader.component.mapper.Mapper -class ComponentRegistryBuilder( +class ComponentRegistryBuilder internal constructor( private val mappers: MutableList> = mutableListOf(), private val keyers: MutableList = mutableListOf(), private val fetcherFactories: MutableList = mutableListOf(), private val decoderFactories: MutableList = mutableListOf(), ) { + internal constructor(componentRegistry: ComponentRegistry) : this( + mappers = componentRegistry.mappers.toMutableList(), + keyers = componentRegistry.keyers.toMutableList(), + fetcherFactories = componentRegistry.fetcherFactories.toMutableList(), + decoderFactories = componentRegistry.decoderFactories.toMutableList(), + ) fun takeFrom( componentRegistry: ComponentRegistry, clearComponents: Boolean = false, ) { - componentRegistry.newBuilder().let { - if (clearComponents) { - mappers.clear() - keyers.clear() - fetcherFactories.clear() - decoderFactories.clear() - } - mappers.addAll(it.mappers) - keyers.addAll(it.keyers) - fetcherFactories.addAll(it.fetcherFactories) - decoderFactories.addAll(it.decoderFactories) + if (clearComponents) { + mappers.clear() + keyers.clear() + fetcherFactories.clear() + decoderFactories.clear() } + mappers.addAll(componentRegistry.mappers) + keyers.addAll(componentRegistry.keyers) + fetcherFactories.addAll(componentRegistry.fetcherFactories) + decoderFactories.addAll(componentRegistry.decoderFactories) } fun add(mapper: Mapper) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index 720aff3e..3e2dcdca 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -43,7 +43,7 @@ class ImageRequestBuilder internal constructor() { extraData = request.extra placeholderPainter = request.placeholderPainter errorPainter = request.errorPainter - componentBuilder = request.components?.newBuilder() + componentBuilder = request.components?.let { ComponentRegistryBuilder(it) } interceptors = request.interceptors?.toMutableList() skipEvent = request.skipEvent } From a5f4830f80a56f6ea3ba490a4c9f1c00ca123882 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:06:44 +0800 Subject: [PATCH 06/99] add OptionsBuilder.takeFrom(ImageRequest) --- .../seiko/imageloader/intercept/InterceptorChainHelper.kt | 5 ++--- .../kotlin/com/seiko/imageloader/option/Options.kt | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt index f8e21a50..c1c0d75f 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt @@ -4,6 +4,7 @@ import com.seiko.imageloader.ImageLoaderConfig import com.seiko.imageloader.model.ImageAction import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.option.Options +import com.seiko.imageloader.option.takeFrom import kotlinx.coroutines.flow.FlowCollector internal class InterceptorChainHelper( @@ -25,9 +26,7 @@ internal class InterceptorChainHelper( fun getOptions(request: ImageRequest): Options { return Options(config.defaultOptions) { - request.optionsBuilders.forEach { builder -> - builder.invoke(this) - } + takeFrom(request) } } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt index c60f3378..b48361a7 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt @@ -5,6 +5,7 @@ import com.seiko.imageloader.cache.CachePolicy import com.seiko.imageloader.model.EmptyExtraData import com.seiko.imageloader.model.ExtraData import com.seiko.imageloader.model.ExtraDataBuilder +import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.extraData import com.seiko.imageloader.util.DEFAULT_MAX_IMAGE_SIZE @@ -106,6 +107,12 @@ class OptionsBuilder internal constructor() { ) } +internal fun OptionsBuilder.takeFrom(request: ImageRequest) { + request.optionsBuilders.forEach { builder -> + builder.invoke(this) + } +} + fun Options(block: OptionsBuilder.() -> Unit = {}) = OptionsBuilder().apply(block).build() From 24b60104180b0d2e1116971d68924c1d32233a3e Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:07:11 +0800 Subject: [PATCH 07/99] add clearOptions param for ImageRequest.takeFrom --- .../kotlin/com/seiko/imageloader/model/ImageRequest.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index 3e2dcdca..0f855f6a 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -36,9 +36,14 @@ class ImageRequestBuilder internal constructor() { private var interceptors: MutableList? = null var skipEvent: Boolean = false - fun takeFrom(request: ImageRequest) { + fun takeFrom( + request: ImageRequest, + clearOptions: Boolean = false, + ) { data = request.data - optionsBuilders.clear() + if (clearOptions) { + optionsBuilders.clear() + } optionsBuilders.addAll(request.optionsBuilders) extraData = request.extra placeholderPainter = request.placeholderPainter From 553966f1322c8f1831f88198c406a9c2dd90c56a Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:07:30 +0800 Subject: [PATCH 08/99] sort ImageRequest params --- .../kotlin/com/seiko/imageloader/model/ImageRequest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index 0f855f6a..c7128251 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -13,11 +13,11 @@ import com.seiko.imageloader.option.SizeResolver @Immutable class ImageRequest internal constructor( val data: Any, - val optionsBuilders: List Unit>, val extra: ExtraData, val placeholderPainter: (@Composable () -> Painter)?, val errorPainter: (@Composable () -> Painter)?, val skipEvent: Boolean, + internal val optionsBuilders: List Unit>, internal val components: ComponentRegistry?, internal val interceptors: List?, ) { From df7e80b167133e4a79cfe17e68388b57558dd107 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:08:13 +0800 Subject: [PATCH 09/99] add ImageRequestTest --- .../imageloader/model/ImageRequestTest.kt | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt new file mode 100644 index 00000000..3630ca49 --- /dev/null +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt @@ -0,0 +1,104 @@ +package com.seiko.imageloader.model + +import androidx.compose.runtime.Composable +import androidx.compose.ui.geometry.Size +import com.seiko.imageloader.EmptyPainter +import com.seiko.imageloader.cache.CachePolicy +import com.seiko.imageloader.component.decoder.Decoder +import com.seiko.imageloader.component.fetcher.Fetcher +import com.seiko.imageloader.component.keyer.Keyer +import com.seiko.imageloader.component.mapper.Mapper +import com.seiko.imageloader.option.Options +import com.seiko.imageloader.option.Scale +import com.seiko.imageloader.option.SizeResolver +import com.seiko.imageloader.option.takeFrom +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +class ImageRequestTest { + + @Test + fun image_request_data_test() { + assertEquals(ImageRequest {}.data, NullRequestData) + assertEquals(ImageRequest(1).data, 1) + assertEquals(ImageRequest("data").data, "data") + assertEquals(ImageRequest(ImageRequest("data")).data, "data") + assertEquals(ImageRequest(ImageRequest("data")) {}.data, "data") + } + + @Test + fun image_request_options_test() { + val onePxSizeResolver = SizeResolver(Size(1f, 1f)) + val request = ImageRequest { + options { + allowInexactSize = true + premultipliedAlpha = false + retryIfDiskDecodeError = false + imageConfig = Options.ImageConfig.ALPHA_8 + scale = Scale.FIT + sizeResolver = onePxSizeResolver + memoryCachePolicy = CachePolicy.DISABLED + diskCachePolicy = CachePolicy.READ_ONLY + repeatCount = 5 + maxImageSize = 100 + extra { + put("a", "aa") + } + } + } + val options = Options { + takeFrom(request) + } + assertTrue(options.allowInexactSize) + assertFalse(options.premultipliedAlpha) + assertFalse(options.retryIfDiskDecodeError) + assertEquals(options.imageConfig, Options.ImageConfig.ALPHA_8) + assertEquals(options.scale, Scale.FIT) + assertEquals(options.sizeResolver, onePxSizeResolver) + assertEquals(options.memoryCachePolicy, CachePolicy.DISABLED) + assertEquals(options.diskCachePolicy, CachePolicy.READ_ONLY) + assertEquals(options.repeatCount, 5) + assertEquals(options.maxImageSize, 100) + assertEquals(options.extra["a"], "aa") + } + + @Test + fun image_request_other_params_test() { + val placeholderPainterFactory = @Composable { EmptyPainter } + val errorPainterFactory = @Composable { EmptyPainter } + val mapperFactory = Mapper { _, _ -> } + val keyerFactory = Keyer { _, _, _ -> null } + val fetcherFactory = Fetcher.Factory { _, _ -> + Fetcher { null } + } + val decoderFactory = Decoder.Factory { _, _ -> + Decoder { null } + } + val request = ImageRequest { + extra { + put("a", "aaa") + } + placeholderPainter(placeholderPainterFactory) + errorPainter(errorPainterFactory) + skipEvent = true + components { + add(mapperFactory) + add(keyerFactory) + add(fetcherFactory) + add(decoderFactory) + } + } + assertEquals(request.extra["a"], "aaa") + assertEquals(request.placeholderPainter, placeholderPainterFactory) + assertEquals(request.errorPainter, errorPainterFactory) + assertEquals(request.skipEvent, true) + assertNotNull(request.components) + assertEquals(request.components.mappers.first(), mapperFactory) + assertEquals(request.components.keyers.first(), keyerFactory) + assertEquals(request.components.fetcherFactories.first(), fetcherFactory) + assertEquals(request.components.decoderFactories.first(), decoderFactory) + } +} From ea620c445c46ab49241cf975517e0d0f7ca66341 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 12 Oct 2023 18:08:23 +0800 Subject: [PATCH 10/99] update ImageLoaderTest --- .../kotlin/com/seiko/imageloader/ImageLoaderTest.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index 3ca2a074..4a702983 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -30,10 +30,10 @@ class ImageLoaderTest { resultPainter3 = ColorPainter(Color.Blue) imageLoader = ImageLoader { components { - add { data, _ -> - object : Fetcher { - override suspend fun fetch(): FetchResult { - return FetchResult.Painter( + add( + Fetcher.Factory { data, _ -> + Fetcher { + FetchResult.Painter( when (data) { "1" -> resultPainter1 "2" -> resultPainter2 @@ -41,8 +41,8 @@ class ImageLoaderTest { }, ) } - } - } + }, + ) } } } From 77220d7e6f9ea3ba36b64a87aef132cbd1daa404 Mon Sep 17 00:00:00 2001 From: seiko Date: Fri, 13 Oct 2023 09:36:22 +0800 Subject: [PATCH 11/99] fix jvm build --- .../com/seiko/imageloader/component/decoder/ImageIODecoder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt index 85884517..d6254c28 100644 --- a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt +++ b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt @@ -21,7 +21,7 @@ class ImageIODecoder( } class Factory : Decoder.Factory { - override suspend fun create(source: DecodeSource, options: Options): Decoder? { + override fun create(source: DecodeSource, options: Options): Decoder? { if (isGif(source.source)) return null return ImageIODecoder(source.source) } From 217d61d2b8cc7990a3b882764183644ad6362caf Mon Sep 17 00:00:00 2001 From: seiko Date: Fri, 13 Oct 2023 11:19:49 +0800 Subject: [PATCH 12/99] remove Base64Mapper --- .../imageloader/component/SetupComponents.kt | 2 -- .../component/fetcher/Base64Fetcher.kt | 31 ++++++++++++------- .../component/mapper/Base64Mapper.kt | 28 ----------------- 3 files changed, 20 insertions(+), 41 deletions(-) delete mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/Base64Mapper.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/SetupComponents.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/SetupComponents.kt index 3a2e9cdd..9a27fe35 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/SetupComponents.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/SetupComponents.kt @@ -4,7 +4,6 @@ import com.seiko.imageloader.component.fetcher.Base64Fetcher import com.seiko.imageloader.component.fetcher.BitmapFetcher import com.seiko.imageloader.component.fetcher.KtorUrlFetcher import com.seiko.imageloader.component.keyer.KtorUrlKeyer -import com.seiko.imageloader.component.mapper.Base64Mapper import com.seiko.imageloader.component.mapper.KtorUrlMapper import com.seiko.imageloader.component.mapper.StringUriMapper import com.seiko.imageloader.util.httpEngineFactory @@ -19,7 +18,6 @@ fun ComponentRegistryBuilder.setupKtorComponents( } fun ComponentRegistryBuilder.setupBase64Components() { - add(Base64Mapper()) add(Base64Fetcher.Factory()) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt index d73518c1..31465f94 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt @@ -1,29 +1,38 @@ package com.seiko.imageloader.component.fetcher -import com.seiko.imageloader.component.mapper.Base64Image import com.seiko.imageloader.model.extraData import com.seiko.imageloader.model.mimeType import com.seiko.imageloader.option.Options +import io.ktor.util.decodeBase64Bytes import okio.Buffer class Base64Fetcher private constructor( - private val data: Base64Image, + private val data: String, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Source( - source = Buffer().apply { - write(data.content) - }, - extra = extraData { - mimeType(data.contentType) - }, - ) + return data.split(',').let { + val contentType = it.firstOrNull()?.removePrefix("data:")?.removeSuffix(";base64") + val content = it.last() + FetchResult.Source( + source = Buffer().apply { + write(content.decodeBase64Bytes()) + }, + extra = extraData { + mimeType(contentType) + }, + ) + } } class Factory : Fetcher.Factory { override fun create(data: Any, options: Options): Fetcher? { - if (data !is Base64Image) return null + if (data !is String) return null + if (!isApplicable(data)) return null return Base64Fetcher(data) } + + private fun isApplicable(data: String): Boolean { + return data.startsWith("data:") + } } } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/Base64Mapper.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/Base64Mapper.kt deleted file mode 100644 index 56c57e80..00000000 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/Base64Mapper.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.seiko.imageloader.component.mapper - -import com.seiko.imageloader.option.Options -import io.ktor.util.decodeBase64Bytes - -class Base64Image( - val contentType: String?, - val content: ByteArray, -) - -class Base64Mapper : Mapper { - override fun map(data: Any, options: Options): Base64Image? { - if (data !is String) return null - if (!isApplicable(data)) return null - return data.split(",").let { - val contentType = it.firstOrNull()?.removePrefix("data:")?.removeSuffix(";base64") - val content = it.last() - Base64Image( - contentType = contentType, - content = content.decodeBase64Bytes(), - ) - } - } - - private fun isApplicable(data: String): Boolean { - return data.startsWith("data:") - } -} From 2713584b7528cc687bb628e641ada338d446a45a Mon Sep 17 00:00:00 2001 From: seiko Date: Fri, 13 Oct 2023 11:20:40 +0800 Subject: [PATCH 13/99] optimise string mapper --- .../component/mapper/KtorUrlMapper.kt | 2 +- .../component/mapper/StringUriMapper.kt | 5 +++++ .../component/mapper/BaseMapperTest.kt | 18 ++++++++++++++++ .../component/mapper/KtorUrlMapperTest.kt | 21 +++++++++++++++++++ .../component/mapper/StringUriMapperTest.kt | 21 +++++++++++++++++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/BaseMapperTest.kt create mode 100644 image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapperTest.kt create mode 100644 image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/StringUriMapperTest.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapper.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapper.kt index 663606f7..744d92b2 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapper.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapper.kt @@ -11,6 +11,6 @@ class KtorUrlMapper : Mapper { } private fun isApplicable(data: String): Boolean { - return data.startsWith("http") + return data.startsWith("http:") || data.startsWith("https:") } } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/StringUriMapper.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/StringUriMapper.kt index 6cd496aa..4d5dae7d 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/StringUriMapper.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/mapper/StringUriMapper.kt @@ -6,6 +6,11 @@ import com.seiko.imageloader.option.Options class StringUriMapper : Mapper { override fun map(data: Any, options: Options): Uri? { if (data !is String) return null + // ignore data uri, see: https://en.wikipedia.org/wiki/Data_URI_scheme + if (data.startsWith("data:")) return null + // ignore http url + if (data.startsWith("http:")) return null + if (data.startsWith("https:")) return null return Uri.parseOrNull(data) } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/BaseMapperTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/BaseMapperTest.kt new file mode 100644 index 00000000..dfda284b --- /dev/null +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/BaseMapperTest.kt @@ -0,0 +1,18 @@ +package com.seiko.imageloader.component.mapper + +import com.seiko.imageloader.option.Options +import kotlin.test.BeforeTest + +abstract class BaseMapperTest> { + + abstract fun createMapper(): M + + private lateinit var mapper: M + + @BeforeTest + fun onBefore() { + mapper = createMapper() + } + + fun map(data: Any, options: Options = Options()) = mapper.map(data, options) +} diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapperTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapperTest.kt new file mode 100644 index 00000000..ca09d41e --- /dev/null +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/KtorUrlMapperTest.kt @@ -0,0 +1,21 @@ +package com.seiko.imageloader.component.mapper + +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class KtorUrlMapperTest : BaseMapperTest() { + + override fun createMapper() = KtorUrlMapper() + + @Test + fun test() { + assertNull(map("data:image/png;base64,iVBOR...")) + assertNotNull(map("http://www.google.com")) + assertNotNull(map("https://www.google.com")) + assertNull(map("content://com.example.project:80/folder/etc")) + assertNull(map("imarsthink://www.marsthink.com/travel/oversea?id=1000")) + assertNull(map("tel:10086")) + assertNull(map("geo:52.76,-79.0342")) + } +} diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/StringUriMapperTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/StringUriMapperTest.kt new file mode 100644 index 00000000..0e408b8e --- /dev/null +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/component/mapper/StringUriMapperTest.kt @@ -0,0 +1,21 @@ +package com.seiko.imageloader.component.mapper + +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class StringUriMapperTest : BaseMapperTest() { + + override fun createMapper() = StringUriMapper() + + @Test + fun test() { + assertNull(map("data:image/png;base64,iVBOR...")) + assertNull(map("http://www.google.com")) + assertNull(map("https://www.google.com")) + assertNotNull(map("content://com.example.project:80/folder/etc")) + assertNotNull(map("imarsthink://www.marsthink.com/travel/oversea?id=1000")) + assertNotNull(map("tel:10086")) + assertNotNull(map("geo:52.76,-79.0342")) + } +} From fe69d8d660ee82f2a94b9795bae7c0c14cbd3cb2 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 16 Oct 2023 14:36:45 +0800 Subject: [PATCH 14/99] add ImageAction Loading&Success&Failure --- .../kotlin/com/seiko/imageloader/Remember.kt | 35 +++++++------ .../seiko/imageloader/model/ImageAction.kt | 49 +++++++++++-------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt index 795760b7..e1a99186 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt @@ -57,12 +57,9 @@ fun rememberImageActionPainter( errorPainter: (@Composable () -> Painter)? = null, ): Painter { return when (action) { - is ImageEvent -> placeholderPainter?.invoke() ?: EmptyPainter - is ImageResult -> rememberImageResultPainter( - result = action, - filterQuality = filterQuality, - errorPainter = errorPainter, - ) + is ImageAction.Success -> rememberImageSuccessPainter(action, filterQuality) + is ImageAction.Loading -> placeholderPainter?.invoke() ?: EmptyPainter + is ImageAction.Failure -> errorPainter?.invoke() ?: EmptyPainter } } @@ -73,18 +70,26 @@ fun rememberImageResultPainter( errorPainter: (@Composable () -> Painter)? = null, ): Painter { return when (result) { - is ImageResult.Painter -> remember(result) { - result.painter + is ImageAction.Success -> rememberImageSuccessPainter(result, filterQuality) + is ImageAction.Failure -> errorPainter?.invoke() ?: EmptyPainter + } +} + +@Composable +fun rememberImageSuccessPainter( + action: ImageAction.Success, + filterQuality: FilterQuality = DefaultFilterQuality, +): Painter { + return when (action) { + is ImageResult.Painter -> remember(action) { + action.painter } - is ImageResult.Bitmap -> remember(result, filterQuality) { - result.bitmap.toPainter(filterQuality) + is ImageResult.Bitmap -> remember(action, filterQuality) { + action.bitmap.toPainter(filterQuality) } - is ImageResult.Image -> remember(result) { - result.image.toPainter() + is ImageResult.Image -> remember(action) { + action.image.toPainter() } - is ImageResult.Error, - is ImageResult.Source, - -> errorPainter?.invoke() ?: EmptyPainter }.also { painter -> if (painter is AnimationPainter) { LaunchedEffect(painter) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt index 2876fdf5..4c95eea8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt @@ -5,50 +5,57 @@ import com.seiko.imageloader.Poko import okio.BufferedSource @Immutable -sealed interface ImageAction +sealed interface ImageAction { + sealed interface Loading : ImageAction + sealed interface Success : ImageAction + sealed interface Failure : ImageAction { + val error: Throwable + } +} @Immutable -sealed interface ImageEvent : ImageAction { - object Start : ImageEvent - object StartWithMemory : ImageEvent - object StartWithDisk : ImageEvent - object StartWithFetch : ImageEvent - - @Poko class Progress(val progress: Float) : ImageEvent +sealed interface ImageEvent : ImageAction.Loading { + data object Start : ImageEvent + data object StartWithMemory : ImageEvent + data object StartWithDisk : ImageEvent + data object StartWithFetch : ImageEvent } @Immutable sealed interface ImageResult : ImageAction { - @Immutable - @Poko - class Source( - val source: BufferedSource, - val dataSource: DataSource, - val extra: ExtraData = EmptyExtraData, - ) : ImageResult - @Immutable @Poko class Bitmap( val bitmap: com.seiko.imageloader.Bitmap, - ) : ImageResult + ) : ImageResult, ImageAction.Success @Immutable @Poko class Image( val image: com.seiko.imageloader.Image, - ) : ImageResult + ) : ImageResult, ImageAction.Success @Immutable @Poko class Painter( val painter: androidx.compose.ui.graphics.painter.Painter, - ) : ImageResult + ) : ImageResult, ImageAction.Success @Immutable @Poko class Error( - val error: Throwable, - ) : ImageResult + override val error: Throwable, + ) : ImageResult, ImageAction.Failure + + @Immutable + @Poko + class Source( + val source: BufferedSource, + val dataSource: DataSource, + val extra: ExtraData = EmptyExtraData, + ) : ImageResult, ImageAction.Failure{ + override val error: Throwable + get() = IllegalStateException("failure to decode image source") + } } From 6ee158289b6b0feb4e40270d17336dfc5ed3bf9e Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 16 Oct 2023 14:36:58 +0800 Subject: [PATCH 15/99] add ImageAction Test --- .../imageloader/model/ImageActionTest.kt | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt new file mode 100644 index 00000000..b1fb7377 --- /dev/null +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt @@ -0,0 +1,99 @@ +package com.seiko.imageloader.model + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.rememberImageAction +import com.seiko.imageloader.rememberImageActionPainter +import com.seiko.imageloader.rememberImageSuccessPainter + +class ImageActionTest { + + @Composable + fun test() { + val request = remember { ImageRequest("") } + val action by rememberImageAction(request) + when_normal_test(action) + when_image_action_test(action) + when_image_event_test(action) + when_image_result_test(action) + when_all_test(action) + } + + @Composable + private fun when_normal_test(action: ImageAction) { + when (action) { + is ImageAction.Loading -> LoadingUI() + is ImageAction.Success -> SuccessUI(rememberImageActionPainter(action)) + is ImageAction.Failure -> ErrorUI(action.error) + } + } + + @Composable + private fun when_image_action_test(action: ImageAction) { + when (action) { + is ImageEvent -> LoadingUI() + is ImageResult -> { + when (action) { + is ImageAction.Success -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageAction.Failure -> ErrorUI(action.error) + } + } + } + } + + @Composable + private fun when_image_event_test(action: ImageAction) { + when (action) { + is ImageEvent.Start, + is ImageEvent.StartWithMemory, + is ImageEvent.StartWithDisk, + is ImageEvent.StartWithFetch -> LoadingUI() + is ImageResult -> { + when (action) { + is ImageAction.Success -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageAction.Failure -> ErrorUI(action.error) + } + } + } + } + + @Composable + private fun when_image_result_test(action: ImageAction) { + when (action) { + is ImageEvent -> LoadingUI() + is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Error -> ErrorUI(action.error) + is ImageResult.Source -> ErrorUI(action.error) + } + } + + @Composable + private fun when_all_test(action: ImageAction) { + when (action) { + is ImageEvent.Start, + is ImageEvent.StartWithMemory, + is ImageEvent.StartWithDisk, + is ImageEvent.StartWithFetch -> LoadingUI() + is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Error -> ErrorUI(action.error) + is ImageResult.Source -> ErrorUI(action.error) + } + } + + @Composable + private fun LoadingUI() = Unit + + @Suppress("UNUSED_PARAMETER") + @Composable + private fun SuccessUI(painter: Painter) = Unit + + @Suppress("UNUSED_PARAMETER") + @Composable + private fun ErrorUI(error: Throwable) = Unit +} From b93c6ae0a77b8e71bdc22e87b00d59e15a800ed9 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 16 Oct 2023 15:20:17 +0800 Subject: [PATCH 16/99] update ImageAction Test --- .../imageloader/model/ImageActionTest.kt | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt index b1fb7377..3cacba1c 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt @@ -16,8 +16,11 @@ class ImageActionTest { val action by rememberImageAction(request) when_normal_test(action) when_image_action_test(action) + when_image_action_no_result_test(action) when_image_event_test(action) + when_image_event_no_result_test(action) when_image_result_test(action) + when_image_result_success_no_result_failure_test(action) when_all_test(action) } @@ -43,13 +46,23 @@ class ImageActionTest { } } + @Composable + private fun when_image_action_no_result_test(action: ImageAction) { + when (action) { + is ImageEvent -> LoadingUI() + is ImageAction.Success -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageAction.Failure -> ErrorUI(action.error) + } + } + @Composable private fun when_image_event_test(action: ImageAction) { when (action) { is ImageEvent.Start, is ImageEvent.StartWithMemory, is ImageEvent.StartWithDisk, - is ImageEvent.StartWithFetch -> LoadingUI() + is ImageEvent.StartWithFetch, + -> LoadingUI() is ImageResult -> { when (action) { is ImageAction.Success -> SuccessUI(rememberImageSuccessPainter(action)) @@ -59,6 +72,19 @@ class ImageActionTest { } } + @Composable + private fun when_image_event_no_result_test(action: ImageAction) { + when (action) { + is ImageEvent.Start, + is ImageEvent.StartWithMemory, + is ImageEvent.StartWithDisk, + is ImageEvent.StartWithFetch, + -> LoadingUI() + is ImageAction.Success -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageAction.Failure -> ErrorUI(action.error) + } + } + @Composable private fun when_image_result_test(action: ImageAction) { when (action) { @@ -71,13 +97,25 @@ class ImageActionTest { } } + @Composable + private fun when_image_result_success_no_result_failure_test(action: ImageAction) { + when (action) { + is ImageAction.Loading -> LoadingUI() + is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageAction.Failure -> ErrorUI(action.error) + } + } + @Composable private fun when_all_test(action: ImageAction) { when (action) { is ImageEvent.Start, is ImageEvent.StartWithMemory, is ImageEvent.StartWithDisk, - is ImageEvent.StartWithFetch -> LoadingUI() + is ImageEvent.StartWithFetch, + -> LoadingUI() is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) From e6318d56c1d688f0e5e7e7d794b78c01db91d7f7 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 16 Oct 2023 15:20:25 +0800 Subject: [PATCH 17/99] apply spotless --- .../kotlin/com/seiko/imageloader/model/ImageAction.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt index 4c95eea8..511b83c4 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt @@ -54,7 +54,7 @@ sealed interface ImageResult : ImageAction { val source: BufferedSource, val dataSource: DataSource, val extra: ExtraData = EmptyExtraData, - ) : ImageResult, ImageAction.Failure{ + ) : ImageResult, ImageAction.Failure { override val error: Throwable get() = IllegalStateException("failure to decode image source") } From 83a99a2629baa0ad71a67e0d1a0b954adb61eab6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 14:49:51 +0000 Subject: [PATCH 18/99] Update dependency org.jetbrains.dokka to v1.9.10 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6d92df67..6f621239 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ androidx-lifecycle-runtime-ktx = "2.6.2" spotless = "6.22.0" ktlint = "0.50.0" publish = "0.25.3" -dokka = "1.9.0" +dokka = "1.9.10" moko-resources = "0.23.0" ktor = "2.3.5" okio = "3.6.0" From 86c1d02d36fec9185c9f7fb9e8f89159dcd6daf2 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 17 Oct 2023 11:20:54 +0800 Subject: [PATCH 19/99] fix build --- .../kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt index 00855d19..5e19e907 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt @@ -68,7 +68,7 @@ class DecodeInterceptor : Interceptor { } } -private fun DecodeResult.toImageResult() = when (this) { +private fun DecodeResult.toImageResult(): ImageResult = when (this) { is DecodeResult.Bitmap -> ImageResult.Bitmap(bitmap = bitmap) is DecodeResult.Image -> ImageResult.Image(image = image) is DecodeResult.Painter -> ImageResult.Painter(painter = painter) From fdd5824e001ddfe29d8a7da8b5fc0dfcf8852070 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 19:33:24 +0000 Subject: [PATCH 20/99] Update actions/checkout action to v4.1.1 --- .github/workflows/StoreScreenshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/StoreScreenshot.yml b/.github/workflows/StoreScreenshot.yml index 6b25faa8..d04b08ad 100644 --- a/.github/workflows/StoreScreenshot.yml +++ b/.github/workflows/StoreScreenshot.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Set up JDK 17 uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 From 08e3bd73d6a41c1728a7313ad9483bb5e058e2a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 17:09:20 +0000 Subject: [PATCH 21/99] Update benchmark to v1.2.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6d92df67..6ff813fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ okio = "3.6.0" uri-kmp = "0.0.15" kermit = "2.0.1" androidsvg = "1.4" -benchmark = "1.2.0-rc02" +benchmark = "1.2.0" junit = "4.13.2" androidx-test-junit = "1.1.5" androidx-test-espresso = "3.5.1" From 48f66fc08f043c163e0a1abe07b82e9d222b5a07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 22:24:11 +0000 Subject: [PATCH 22/99] Update dependency com.twelvemonkeys.imageio:imageio-batik to v3.10.0 --- extension/imageio/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/imageio/build.gradle.kts b/extension/imageio/build.gradle.kts index 499ac873..77b15943 100644 --- a/extension/imageio/build.gradle.kts +++ b/extension/imageio/build.gradle.kts @@ -11,7 +11,7 @@ kotlin { dependencies { implementation(projects.imageLoader) // svg - implementation("com.twelvemonkeys.imageio:imageio-batik:3.9.4") + implementation("com.twelvemonkeys.imageio:imageio-batik:3.10.0") implementation("org.apache.xmlgraphics:batik-transcoder:1.17") } } From 5f7405c068e95d5da751eb73cbcf86aa1bfd8e17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 18:06:12 +0000 Subject: [PATCH 23/99] Update actions/setup-node action to v4 --- .github/workflows/DocsDeploy.yml | 2 +- .github/workflows/DocsTest.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/DocsDeploy.yml b/.github/workflows/DocsDeploy.yml index b5a66cb2..86a96b16 100644 --- a/.github/workflows/DocsDeploy.yml +++ b/.github/workflows/DocsDeploy.yml @@ -34,7 +34,7 @@ jobs: run: ./gradlew dokkaHtmlMultiModule --stacktrace - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: yarn diff --git a/.github/workflows/DocsTest.yml b/.github/workflows/DocsTest.yml index bfd3cd22..8a2f518a 100644 --- a/.github/workflows/DocsTest.yml +++ b/.github/workflows/DocsTest.yml @@ -34,7 +34,7 @@ jobs: run: ./gradlew dokkaHtmlMultiModule --stacktrace - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: yarn From c03a5bc3b7a1e6b9b7178df1302e648beb10dac7 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 11:27:13 +0800 Subject: [PATCH 24/99] unfls screenshot images --- .gitattributes | 1 - app/ios-combine/build.gradle.kts | 2 +- ...eloader.screenshot.ChangeImageUrlTest.test_image_change.png | 3 --- ...oader.screenshot.ChangeImageUrlTest.test_image_change_2.png | 3 --- ...oader.screenshot.ChangeImageUrlTest.test_image_change_3.png | 3 --- ...oader.screenshot.ChangeImageUrlTest.test_image_change_4.png | 3 --- ...der.screenshot.ComposeScreenShotTest.test_error_painter.png | 3 --- ...loader.screenshot.ComposeScreenShotTest.test_load_image.png | 3 --- ...reenshot.ComposeScreenShotTest.test_placeholder_painter.png | 3 --- ...eloader.screenshot.ChangeImageUrlTest.test_image_change.png | 3 --- ...oader.screenshot.ChangeImageUrlTest.test_image_change_2.png | 3 --- ...oader.screenshot.ChangeImageUrlTest.test_image_change_3.png | 3 --- ...oader.screenshot.ChangeImageUrlTest.test_image_change_4.png | 3 --- ...der.screenshot.ComposeScreenShotTest.test_error_painter.png | 3 --- ...loader.screenshot.ComposeScreenShotTest.test_load_image.png | 3 --- ...reenshot.ComposeScreenShotTest.test_placeholder_painter.png | 3 --- 16 files changed, 1 insertion(+), 44 deletions(-) delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png delete mode 100644 image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png delete mode 100644 image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png diff --git a/.gitattributes b/.gitattributes index 17dde093..dd66c79c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,2 @@ **/baseline-prof.txt linguist-generated=true -**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text **/yarn.lock -diff diff --git a/app/ios-combine/build.gradle.kts b/app/ios-combine/build.gradle.kts index edbf3cfc..b8f15588 100644 --- a/app/ios-combine/build.gradle.kts +++ b/app/ios-combine/build.gradle.kts @@ -21,7 +21,7 @@ kotlin { version = "1.0.0" summary = "Shared code for the sample" homepage = "https://github.com/qdsfdhvh/compose-imageloader" - ios.deploymentTarget = "16.0" + ios.deploymentTarget = "14.0" podfile = project.file("../ios/Podfile") framework { baseName = "combine" diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png deleted file mode 100644 index bab35f16..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8efefc34190788fa550753f68a91e24901c35db9d9f5aae00f037c6d93ee6a81 -size 244 diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png deleted file mode 100644 index 7089e409..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bb405b2da07222a107615a7a375d4334e87061124154af487fa7e259df788e51 -size 245 diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png deleted file mode 100644 index c99cc537..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:93e0b25a633563cf1482934edd6776f144b5b88d92e1e88d71a3c17672266470 -size 243 diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png deleted file mode 100644 index 4cc5ca44..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:925fd1a1dccd1de52e89bd601b5854664362a5803caf491163e0f67505d347d6 -size 246 diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png deleted file mode 100644 index cd24e6a4..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e025c7f7560d3dcef1bb0d7371573048c5fc10f35435f30733f31ee5a55d6340 -size 310 diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png deleted file mode 100644 index ccfa73b3..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4af898ef87c20b18fcafb2deaa5d50689182ff9f29e3ee8d79bb245778e56256 -size 816 diff --git a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png b/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png deleted file mode 100644 index e2aeb82a..00000000 --- a/image-loader/src/androidUnitTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a5154ac23b0ee9042e5f107c05782349f9aa544a8b0367b4145d2b767ef9480f -size 311 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png deleted file mode 100644 index bab35f16..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8efefc34190788fa550753f68a91e24901c35db9d9f5aae00f037c6d93ee6a81 -size 244 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png deleted file mode 100644 index 0a6a9b59..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_2.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0a0ddfea35a63c2e68784a0ce1eb7830e96e36b304476b480321cdfbdb165cb7 -size 246 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png deleted file mode 100644 index 1a366673..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_3.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:71a17cd9e761a358e8d6d3ee1d9549a21bf897c8d986f44eb443aea5c9fbfcb9 -size 246 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png deleted file mode 100644 index f2765a23..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ChangeImageUrlTest.test_image_change_4.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c517fa85a7044189415cde4815296aefb0a3cae686cffcb3f62a8552ad96ba90 -size 246 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png deleted file mode 100644 index cd24e6a4..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_error_painter.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e025c7f7560d3dcef1bb0d7371573048c5fc10f35435f30733f31ee5a55d6340 -size 310 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png deleted file mode 100644 index 5a1c6035..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_load_image.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6016a459f91e28f88dd32a57658a4897d0bf18ff17594a3ab585b2449698b642 -size 661 diff --git a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png b/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png deleted file mode 100644 index e2aeb82a..00000000 --- a/image-loader/src/desktopTest/snapshots/images/com.seiko.imageloader.screenshot.ComposeScreenShotTest.test_placeholder_painter.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a5154ac23b0ee9042e5f107c05782349f9aa544a8b0367b4145d2b767ef9480f -size 311 From 3c8f6a280bc8cc1f057314ff036182b0202a5994 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 13:44:39 +0800 Subject: [PATCH 25/99] set roborazzi output directory path --- .../com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt | 2 +- .../com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt | 2 +- .../com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt | 2 +- .../com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt b/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt index 72df9e62..be3a331d 100644 --- a/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt +++ b/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt @@ -30,7 +30,7 @@ class ChangeImageUrlTest : ChangeImageUrlCommonTest() { @Before fun initRoborazziConfig() { RoborazziContext.setRuleOverrideOutputDirectory( - outputDirectory = "src/androidUnitTest/snapshots/images", + outputDirectory = "build/outputs/roborazzi/android", ) } diff --git a/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt b/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt index 939bcc8e..c1eff7aa 100644 --- a/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt +++ b/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt @@ -25,7 +25,7 @@ class ComposeScreenShotTest : ComposeScreenShotCommonTest() { captureRoot = composeTestRule.onRoot(), options = RoborazziRule.Options( captureType = RoborazziRule.CaptureType.LastImage(), - outputDirectoryPath = "src/androidUnitTest/snapshots/images", + outputDirectoryPath = "build/outputs/roborazzi/android", ), ) diff --git a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt index 113e7076..76be3329 100644 --- a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt +++ b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt @@ -19,7 +19,7 @@ class ChangeImageUrlTest : ChangeImageUrlCommonTest() { @Before fun initRoborazziConfig() { RoborazziContext.setRuleOverrideOutputDirectory( - outputDirectory = "src/desktopTest/snapshots/images", + outputDirectory = "build/outputs/roborazzi/desktop", ) } diff --git a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt index 431ed763..33fb7854 100644 --- a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt +++ b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt @@ -18,7 +18,7 @@ class ComposeScreenShotTest : ComposeScreenShotCommonTest() { @Before fun initRoborazziConfig() { RoborazziContext.setRuleOverrideOutputDirectory( - outputDirectory = "src/desktopTest/snapshots/images", + outputDirectory = "build/outputs/roborazzi/desktop", ) } From 2f1beaf4fa737d7b418c803efc58ba10226e3b5f Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 13:44:55 +0800 Subject: [PATCH 26/99] update screenshot ci --- ...{Screenshots.yml => CompareScreenshot.yml} | 31 ++-- .../workflows/CompareScreenshotComment.yml | 150 ++++++++++++++++++ .github/workflows/StoreScreenshot.yml | 6 +- 3 files changed, 172 insertions(+), 15 deletions(-) rename .github/workflows/{Screenshots.yml => CompareScreenshot.yml} (66%) create mode 100644 .github/workflows/CompareScreenshotComment.yml diff --git a/.github/workflows/Screenshots.yml b/.github/workflows/CompareScreenshot.yml similarity index 66% rename from .github/workflows/Screenshots.yml rename to .github/workflows/CompareScreenshot.yml index a4e7ffd5..c33b5e64 100644 --- a/.github/workflows/Screenshots.yml +++ b/.github/workflows/CompareScreenshot.yml @@ -4,26 +4,33 @@ on: push: paths: - 'image-loader/**' + pull_request: -env: - GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" +permissions: {} jobs: test: - runs-on: macos-latest + runs-on: ubuntu-latest + timeout-minutes: 20 + + permissions: + contents: read # for clone + actions: write # for upload-artifact steps: - - uses: actions/checkout@v4 - with: - lfs: true + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/setup-java@v3.13.0 + - name: Set up JDK 17 + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0 with: - distribution: 'zulu' - java-version: 19 + distribution: temurin + java-version: 17 - - name: Gradle cache - uses: gradle/gradle-build-action@v2 + - name: Setup Gradle + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0 + with: + gradle-version: wrapper # Download screenshots from main branch - uses: dawidd6/action-download-artifact@v2 @@ -35,7 +42,7 @@ jobs: - name: compare screenshot test id: compare-screenshot-test - run: ./gradlew compareRoborazziDebug --stacktrace --info + run: ./gradlew compareRoborazzi --stacktrace --info - uses: actions/upload-artifact@v3 if: ${{ always() }} diff --git a/.github/workflows/CompareScreenshotComment.yml b/.github/workflows/CompareScreenshotComment.yml new file mode 100644 index 00000000..693d6fc9 --- /dev/null +++ b/.github/workflows/CompareScreenshotComment.yml @@ -0,0 +1,150 @@ +name: Screenshot compare comment + +on: + workflow_run: + workflows: + - CompareScreenshot + types: + - completed + +permissions: { } + +jobs: + Comment-CompareScreenshot: + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + + timeout-minutes: 2 + + permissions: + actions: read # for downloading artifacts + contents: write # for pushing screenshot-diff to companion branch + pull-requests: write # for creating a comment on pull requests + + runs-on: ubuntu-latest + + steps: + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0 + with: + name: pr + run_id: ${{ github.event.workflow_run.id }} + - id: get-pull-request-number + name: Get pull request number + shell: bash + run: | + echo "pull_request_number=$(cat NR)" >> "$GITHUB_OUTPUT" + - name: master checkout + id: checkout-master + uses: actions/checkout@v3 + with: + ref: master + - id: switch-companion-branch + env: + BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} + run: | + # orphan means it will create no history branch + git branch -D "$BRANCH_NAME" || true + git checkout --orphan "$BRANCH_NAME" + git rm -rf . + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0 + with: + run_id: ${{ github.event.workflow_run.id }} + name: screenshot-diff + path: screenshot-diff + - id: check-if-there-are-valid-files + name: Check if there are valid files + shell: bash + run: | + # Find all the files ending with _compare.png + mapfile -t files_to_add < <(find . -type f -name "*_compare.png") + + # Check for invalid file names and add only valid ones + exist_valid_files="false" + for file in "${files_to_add[@]}"; do + if [[ $file =~ ^[a-zA-Z0-9_./-]+$ ]]; then + exist_valid_files="true" + break + fi + done + echo "exist_valid_files=$exist_valid_files" >> "$GITHUB_OUTPUT" + - id: push-screenshot-diff + shell: bash + if: steps.check-if-there-are-valid-files.outputs.exist_valid_files == 'true' + env: + BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} + run: | + # Find all the files ending with _compare.png + files_to_add=$(find . -type f -name "*_compare.png") + + # Check for invalid file names and add only valid ones + for file in $files_to_add; do + if [[ "$file" =~ ^[a-zA-Z0-9_./-]+$ ]]; then + git add "$file" + fi + done + git config --global user.name ScreenshotBot + git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com + git commit -m "Add screenshot diff" + git push origin HEAD:"$BRANCH_NAME" -f + - id: generate-diff-reports + name: Generate diff reports + if: steps.check-if-there-are-valid-files.outputs.exist_valid_files == 'true' + env: + BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} + shell: bash + run: | + # Find all the files ending with _compare.png in roborazzi folder + files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./-]+$") + delimiter="$(openssl rand -hex 8)" + { + echo "reports<<${delimiter}" + + # Create markdown table header + echo "Snapshot diff report" + echo "| File name | Image |" + echo "|-------|-------|" + } >> "$GITHUB_OUTPUT" + + # Iterate over the files and create table rows + for file in $files; do + # Get the file name and insert newlines every 20 characters + fileName=$(basename "$file" | sed -r 's/(.{20})/\1
/g') + echo "| [$fileName](https://github.com/${{ github.repository }}/blob/$BRANCH_NAME/$file) | ![](https://github.com/${{ github.repository }}/blob/$BRANCH_NAME/$file?raw=true) |" >> "$GITHUB_OUTPUT" + done + echo "${delimiter}" >> "$GITHUB_OUTPUT" + - name: Find Comment + uses: peter-evans/find-comment@v2 + id: fc + if: steps.generate-diff-reports.outputs.reports != '' + with: + issue-number: ${{ steps.get-pull-request-number.outputs.pull_request_number }} + comment-author: 'github-actions[bot]' + body-includes: Snapshot diff report + + - name: Add or update comment on PR + uses: peter-evans/create-or-update-comment@v3 + if: steps.generate-diff-reports.outputs.reports != '' + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ steps.get-pull-request-number.outputs.pull_request_number }} + body: ${{ steps.generate-diff-reports.outputs.reports }} + edit-mode: replace + + - name: Cleanup outdated companion branches + run: | + # Find outdated companion branches with last commit date + git branch -r --format="%(refname:lstrip=3)" | grep companion_ | while read -r branch; do + last_commit_date_timestamp=$(git log -1 --format=%ct "origin/$branch") + now_timestamp=$(date +%s) + # Delete branch if it's older than 1 month + # if [ $((now_timestamp - last_commit_date_timestamp)) -gt 2592000 ]; then + # For testing purpose, delete branch if it's older than 1 second + echo "branch: $branch now_timestamp: $now_timestamp last_commit_date_timestamp: $last_commit_date_timestamp" + if [ $((now_timestamp - last_commit_date_timestamp)) -gt 1 ]; then + # Comment out for demonstration purpose + echo "Deleting $branch" + + # git push origin --delete "$branch" + fi + done diff --git a/.github/workflows/StoreScreenshot.yml b/.github/workflows/StoreScreenshot.yml index d04b08ad..50e3dd42 100644 --- a/.github/workflows/StoreScreenshot.yml +++ b/.github/workflows/StoreScreenshot.yml @@ -3,7 +3,7 @@ name: StoreScreenshot on: push: branches: - - main + - master pull_request: permissions: { } @@ -35,7 +35,7 @@ jobs: - name: record screenshot id: record-test - run: ./gradlew recordRoborazziDebug --stacktrace + run: ./gradlew recordRoborazzi --stacktrace - uses: actions/upload-artifact@v3 if: ${{ always() }} @@ -59,4 +59,4 @@ jobs: name: screenshot-test-results path: | **/build/test-results - retention-days: 30 \ No newline at end of file + retention-days: 30 From e2299cb4603649c35d33d09acf2418da96a906d3 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 14:04:00 +0800 Subject: [PATCH 27/99] format yml --- .editorconfig | 3 + .github/workflows/CompareScreenshot.yml | 12 +- .../workflows/CompareScreenshotComment.yml | 264 +++++++++--------- 3 files changed, 141 insertions(+), 138 deletions(-) diff --git a/.editorconfig b/.editorconfig index a1c8aaad..5ce188c5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -20,3 +20,6 @@ ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 # @see https://youtrack.jetbrains.com/issue/KTIJ-21944 ij_kotlin_blank_lines_around_block_when_branches = 0 ij_kotlin_line_break_after_multiline_when_entry = false + +[*.yml] +indent_size = 2 diff --git a/.github/workflows/CompareScreenshot.yml b/.github/workflows/CompareScreenshot.yml index c33b5e64..83e95a37 100644 --- a/.github/workflows/CompareScreenshot.yml +++ b/.github/workflows/CompareScreenshot.yml @@ -2,20 +2,20 @@ name: CompareScreenshot on: push: - paths: - - 'image-loader/**' + branches: + - master pull_request: -permissions: {} +permissions: { } jobs: - test: + CompareScreenshot: runs-on: ubuntu-latest timeout-minutes: 20 permissions: - contents: read # for clone - actions: write # for upload-artifact + contents: read # for clone + actions: write # for upload-artifact steps: - name: Checkout diff --git a/.github/workflows/CompareScreenshotComment.yml b/.github/workflows/CompareScreenshotComment.yml index 693d6fc9..82314645 100644 --- a/.github/workflows/CompareScreenshotComment.yml +++ b/.github/workflows/CompareScreenshotComment.yml @@ -1,150 +1,150 @@ name: Screenshot compare comment on: - workflow_run: - workflows: - - CompareScreenshot - types: - - completed + workflow_run: + workflows: + - CompareScreenshot + types: + - completed permissions: { } jobs: - Comment-CompareScreenshot: - if: > - github.event.workflow_run.event == 'pull_request' && - github.event.workflow_run.conclusion == 'success' + Comment-CompareScreenshot: + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' - timeout-minutes: 2 + timeout-minutes: 2 - permissions: - actions: read # for downloading artifacts - contents: write # for pushing screenshot-diff to companion branch - pull-requests: write # for creating a comment on pull requests + permissions: + actions: read # for downloading artifacts + contents: write # for pushing screenshot-diff to companion branch + pull-requests: write # for creating a comment on pull requests - runs-on: ubuntu-latest + runs-on: ubuntu-latest - steps: - - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0 - with: - name: pr - run_id: ${{ github.event.workflow_run.id }} - - id: get-pull-request-number - name: Get pull request number - shell: bash - run: | - echo "pull_request_number=$(cat NR)" >> "$GITHUB_OUTPUT" - - name: master checkout - id: checkout-master - uses: actions/checkout@v3 - with: - ref: master - - id: switch-companion-branch - env: - BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} - run: | - # orphan means it will create no history branch - git branch -D "$BRANCH_NAME" || true - git checkout --orphan "$BRANCH_NAME" - git rm -rf . - - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0 - with: - run_id: ${{ github.event.workflow_run.id }} - name: screenshot-diff - path: screenshot-diff - - id: check-if-there-are-valid-files - name: Check if there are valid files - shell: bash - run: | - # Find all the files ending with _compare.png - mapfile -t files_to_add < <(find . -type f -name "*_compare.png") + steps: + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0 + with: + name: pr + run_id: ${{ github.event.workflow_run.id }} + - id: get-pull-request-number + name: Get pull request number + shell: bash + run: | + echo "pull_request_number=$(cat NR)" >> "$GITHUB_OUTPUT" + - name: master checkout + id: checkout-master + uses: actions/checkout@v3 + with: + ref: master + - id: switch-companion-branch + env: + BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} + run: | + # orphan means it will create no history branch + git branch -D "$BRANCH_NAME" || true + git checkout --orphan "$BRANCH_NAME" + git rm -rf . + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0 + with: + run_id: ${{ github.event.workflow_run.id }} + name: screenshot-diff + path: screenshot-diff + - id: check-if-there-are-valid-files + name: Check if there are valid files + shell: bash + run: | + # Find all the files ending with _compare.png + mapfile -t files_to_add < <(find . -type f -name "*_compare.png") - # Check for invalid file names and add only valid ones - exist_valid_files="false" - for file in "${files_to_add[@]}"; do - if [[ $file =~ ^[a-zA-Z0-9_./-]+$ ]]; then - exist_valid_files="true" - break - fi - done - echo "exist_valid_files=$exist_valid_files" >> "$GITHUB_OUTPUT" - - id: push-screenshot-diff - shell: bash - if: steps.check-if-there-are-valid-files.outputs.exist_valid_files == 'true' - env: - BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} - run: | - # Find all the files ending with _compare.png - files_to_add=$(find . -type f -name "*_compare.png") + # Check for invalid file names and add only valid ones + exist_valid_files="false" + for file in "${files_to_add[@]}"; do + if [[ $file =~ ^[a-zA-Z0-9_./-]+$ ]]; then + exist_valid_files="true" + break + fi + done + echo "exist_valid_files=$exist_valid_files" >> "$GITHUB_OUTPUT" + - id: push-screenshot-diff + shell: bash + if: steps.check-if-there-are-valid-files.outputs.exist_valid_files == 'true' + env: + BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} + run: | + # Find all the files ending with _compare.png + files_to_add=$(find . -type f -name "*_compare.png") - # Check for invalid file names and add only valid ones - for file in $files_to_add; do - if [[ "$file" =~ ^[a-zA-Z0-9_./-]+$ ]]; then - git add "$file" - fi - done - git config --global user.name ScreenshotBot - git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com - git commit -m "Add screenshot diff" - git push origin HEAD:"$BRANCH_NAME" -f - - id: generate-diff-reports - name: Generate diff reports - if: steps.check-if-there-are-valid-files.outputs.exist_valid_files == 'true' - env: - BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} - shell: bash - run: | - # Find all the files ending with _compare.png in roborazzi folder - files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./-]+$") - delimiter="$(openssl rand -hex 8)" - { - echo "reports<<${delimiter}" + # Check for invalid file names and add only valid ones + for file in $files_to_add; do + if [[ "$file" =~ ^[a-zA-Z0-9_./-]+$ ]]; then + git add "$file" + fi + done + git config --global user.name ScreenshotBot + git config --global user.email 41898282+github-actions[bot]@users.noreply.github.com + git commit -m "Add screenshot diff" + git push origin HEAD:"$BRANCH_NAME" -f + - id: generate-diff-reports + name: Generate diff reports + if: steps.check-if-there-are-valid-files.outputs.exist_valid_files == 'true' + env: + BRANCH_NAME: companion_${{ github.event.workflow_run.head_branch }} + shell: bash + run: | + # Find all the files ending with _compare.png in roborazzi folder + files=$(find . -type f -name "*_compare.png" | grep "roborazzi/" | grep -E "^[a-zA-Z0-9_./-]+$") + delimiter="$(openssl rand -hex 8)" + { + echo "reports<<${delimiter}" - # Create markdown table header - echo "Snapshot diff report" - echo "| File name | Image |" - echo "|-------|-------|" - } >> "$GITHUB_OUTPUT" + # Create markdown table header + echo "Snapshot diff report" + echo "| File name | Image |" + echo "|-------|-------|" + } >> "$GITHUB_OUTPUT" - # Iterate over the files and create table rows - for file in $files; do - # Get the file name and insert newlines every 20 characters - fileName=$(basename "$file" | sed -r 's/(.{20})/\1
/g') - echo "| [$fileName](https://github.com/${{ github.repository }}/blob/$BRANCH_NAME/$file) | ![](https://github.com/${{ github.repository }}/blob/$BRANCH_NAME/$file?raw=true) |" >> "$GITHUB_OUTPUT" - done - echo "${delimiter}" >> "$GITHUB_OUTPUT" - - name: Find Comment - uses: peter-evans/find-comment@v2 - id: fc - if: steps.generate-diff-reports.outputs.reports != '' - with: - issue-number: ${{ steps.get-pull-request-number.outputs.pull_request_number }} - comment-author: 'github-actions[bot]' - body-includes: Snapshot diff report + # Iterate over the files and create table rows + for file in $files; do + # Get the file name and insert newlines every 20 characters + fileName=$(basename "$file" | sed -r 's/(.{20})/\1
/g') + echo "| [$fileName](https://github.com/${{ github.repository }}/blob/$BRANCH_NAME/$file) | ![](https://github.com/${{ github.repository }}/blob/$BRANCH_NAME/$file?raw=true) |" >> "$GITHUB_OUTPUT" + done + echo "${delimiter}" >> "$GITHUB_OUTPUT" + - name: Find Comment + uses: peter-evans/find-comment@v2 + id: fc + if: steps.generate-diff-reports.outputs.reports != '' + with: + issue-number: ${{ steps.get-pull-request-number.outputs.pull_request_number }} + comment-author: 'github-actions[bot]' + body-includes: Snapshot diff report - - name: Add or update comment on PR - uses: peter-evans/create-or-update-comment@v3 - if: steps.generate-diff-reports.outputs.reports != '' - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ steps.get-pull-request-number.outputs.pull_request_number }} - body: ${{ steps.generate-diff-reports.outputs.reports }} - edit-mode: replace + - name: Add or update comment on PR + uses: peter-evans/create-or-update-comment@v3 + if: steps.generate-diff-reports.outputs.reports != '' + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ steps.get-pull-request-number.outputs.pull_request_number }} + body: ${{ steps.generate-diff-reports.outputs.reports }} + edit-mode: replace - - name: Cleanup outdated companion branches - run: | - # Find outdated companion branches with last commit date - git branch -r --format="%(refname:lstrip=3)" | grep companion_ | while read -r branch; do - last_commit_date_timestamp=$(git log -1 --format=%ct "origin/$branch") - now_timestamp=$(date +%s) - # Delete branch if it's older than 1 month - # if [ $((now_timestamp - last_commit_date_timestamp)) -gt 2592000 ]; then - # For testing purpose, delete branch if it's older than 1 second - echo "branch: $branch now_timestamp: $now_timestamp last_commit_date_timestamp: $last_commit_date_timestamp" - if [ $((now_timestamp - last_commit_date_timestamp)) -gt 1 ]; then - # Comment out for demonstration purpose - echo "Deleting $branch" + - name: Cleanup outdated companion branches + run: | + # Find outdated companion branches with last commit date + git branch -r --format="%(refname:lstrip=3)" | grep companion_ | while read -r branch; do + last_commit_date_timestamp=$(git log -1 --format=%ct "origin/$branch") + now_timestamp=$(date +%s) + # Delete branch if it's older than 1 month + # if [ $((now_timestamp - last_commit_date_timestamp)) -gt 2592000 ]; then + # For testing purpose, delete branch if it's older than 1 second + echo "branch: $branch now_timestamp: $now_timestamp last_commit_date_timestamp: $last_commit_date_timestamp" + if [ $((now_timestamp - last_commit_date_timestamp)) -gt 1 ]; then + # Comment out for demonstration purpose + echo "Deleting $branch" - # git push origin --delete "$branch" - fi - done + # git push origin --delete "$branch" + fi + done From 1db3354c46752c1090530fca69111551dcdcfbd3 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 14:10:57 +0800 Subject: [PATCH 28/99] update screenshot test name --- .github/workflows/CompareScreenshot.yml | 2 +- .github/workflows/CompareScreenshotComment.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CompareScreenshot.yml b/.github/workflows/CompareScreenshot.yml index 83e95a37..67658d8f 100644 --- a/.github/workflows/CompareScreenshot.yml +++ b/.github/workflows/CompareScreenshot.yml @@ -9,7 +9,7 @@ on: permissions: { } jobs: - CompareScreenshot: + compare-screenshot-test: runs-on: ubuntu-latest timeout-minutes: 20 diff --git a/.github/workflows/CompareScreenshotComment.yml b/.github/workflows/CompareScreenshotComment.yml index 82314645..760e431f 100644 --- a/.github/workflows/CompareScreenshotComment.yml +++ b/.github/workflows/CompareScreenshotComment.yml @@ -10,7 +10,7 @@ on: permissions: { } jobs: - Comment-CompareScreenshot: + comment-compare-screenshot-test: if: > github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' From 836e4e93af0f1e58a73f8f51de271a58a765c4f3 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 17:45:55 +0800 Subject: [PATCH 29/99] remove default ktor client --- image-loader/build.gradle.kts | 18 +++--------------- .../seiko/imageloader/util/Platform.apple.kt | 4 ---- .../com/seiko/imageloader/util/Platform.kt | 5 +---- .../com/seiko/imageloader/util/Platform.js.kt | 4 ---- .../com/seiko/imageloader/util/Platform.jvm.kt | 4 ---- 5 files changed, 4 insertions(+), 31 deletions(-) diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 96d2ab20..78ffaf59 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -31,11 +31,7 @@ kotlin { implementation(compose.ui) } } - val jvmMain by getting { - dependencies { - implementation(libs.ktor.client.okhttp) - } - } + val jvmMain by getting val androidMain by getting { dependencies { implementation(libs.kotlinx.coroutines.android) @@ -69,16 +65,8 @@ kotlin { } } } - val appleMain by getting { - dependencies { - implementation(libs.ktor.client.darwin) - } - } - val jsMain by getting { - dependencies { - implementation(libs.ktor.client.js) - } - } + val appleMain by getting + val jsMain by getting val noJsMain by creating { dependsOn(commonMain) jvmMain.dependsOn(this) diff --git a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt index fee06707..49c482de 100644 --- a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt +++ b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt @@ -1,7 +1,5 @@ package com.seiko.imageloader.util -import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.engine.darwin.Darwin import kotlinx.atomicfu.locks.SynchronizedObject import okio.FileSystem import kotlin.experimental.ExperimentalNativeApi @@ -15,6 +13,4 @@ internal actual inline fun synchronized(lock: LockObject, block: () -> R): R return kotlinx.atomicfu.locks.synchronized(lock, block) } -internal actual val httpEngine: HttpClientEngine get() = Darwin.create() - internal actual val defaultFileSystem: FileSystem? get() = FileSystem.SYSTEM diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt index 59f958f7..92406aac 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt @@ -1,7 +1,6 @@ package com.seiko.imageloader.util import io.ktor.client.HttpClient -import io.ktor.client.engine.HttpClientEngine import io.ktor.utils.io.ByteReadChannel import kotlinx.coroutines.CoroutineDispatcher import okio.BufferedSource @@ -21,9 +20,7 @@ internal expect suspend fun ByteReadChannel.source(): BufferedSource internal expect val ioDispatcher: CoroutineDispatcher -internal expect val httpEngine: HttpClientEngine - internal expect val defaultFileSystem: FileSystem? internal val httpEngineFactory: () -> HttpClient - get() = { HttpClient(httpEngine) } + get() = { HttpClient() } diff --git a/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt b/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt index 2622cab4..8bee442c 100644 --- a/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt +++ b/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt @@ -1,7 +1,5 @@ package com.seiko.imageloader.util -import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.engine.js.Js import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import okio.FileSystem @@ -36,6 +34,4 @@ internal actual inline fun synchronized(lock: LockObject, block: () -> R): R internal actual val ioDispatcher: CoroutineDispatcher get() = Dispatchers.Default -internal actual val httpEngine: HttpClientEngine get() = Js.create() - internal actual val defaultFileSystem: FileSystem? get() = null diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt index a566ac14..1dca5a93 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt @@ -1,7 +1,5 @@ package com.seiko.imageloader.util -import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.engine.okhttp.OkHttp import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.jvm.javaio.toInputStream import okio.BufferedSource @@ -21,8 +19,6 @@ internal actual suspend fun ByteReadChannel.source(): BufferedSource { return toInputStream().source().buffer() } -internal actual val httpEngine: HttpClientEngine get() = OkHttp.create() - internal actual val defaultFileSystem: FileSystem? get() = FileSystem.SYSTEM internal expect fun getMimeTypeFromExtension(extension: String): String? From 66c1bbf579f79ef41d3b24d3cd53e89c3dbc109e Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:50:31 +0800 Subject: [PATCH 30/99] move sizeResolver into ImageRequest --- .../kotlin/com/seiko/imageloader/model/ImageRequest.kt | 7 ++++--- .../kotlin/com/seiko/imageloader/option/Options.kt | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index c7128251..c88a12d0 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -14,6 +14,7 @@ import com.seiko.imageloader.option.SizeResolver class ImageRequest internal constructor( val data: Any, val extra: ExtraData, + val sizeResolver: SizeResolver, val placeholderPainter: (@Composable () -> Painter)?, val errorPainter: (@Composable () -> Painter)?, val skipEvent: Boolean, @@ -28,6 +29,7 @@ class ImageRequest internal constructor( class ImageRequestBuilder internal constructor() { private var data: Any? = null + private var sizeResolver: SizeResolver = SizeResolver.Unspecified private val optionsBuilders: MutableList Unit> = mutableListOf() private var extraData: ExtraData? = null private var placeholderPainter: (@Composable () -> Painter)? = null @@ -58,9 +60,7 @@ class ImageRequestBuilder internal constructor() { } fun size(sizeResolver: SizeResolver) { - optionsBuilders.add { - this.sizeResolver = sizeResolver - } + this.sizeResolver = sizeResolver } fun scale(scale: Scale) { @@ -99,6 +99,7 @@ class ImageRequestBuilder internal constructor() { internal fun build() = ImageRequest( data = data ?: NullRequestData, + sizeResolver = sizeResolver, optionsBuilders = optionsBuilders, extra = extraData ?: EmptyExtraData, placeholderPainter = placeholderPainter, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt index b48361a7..e8597a97 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt @@ -1,5 +1,6 @@ package com.seiko.imageloader.option +import androidx.compose.ui.geometry.Size import com.seiko.imageloader.Poko import com.seiko.imageloader.cache.CachePolicy import com.seiko.imageloader.model.EmptyExtraData @@ -14,8 +15,8 @@ import com.seiko.imageloader.util.DEFAULT_MAX_IMAGE_SIZE val premultipliedAlpha: Boolean, val retryIfDiskDecodeError: Boolean, val imageConfig: ImageConfig, + val size: Size, val scale: Scale, - val sizeResolver: SizeResolver, val memoryCachePolicy: CachePolicy, val diskCachePolicy: CachePolicy, val playAnimate: Boolean, @@ -45,8 +46,8 @@ class OptionsBuilder internal constructor() { var premultipliedAlpha: Boolean = true var retryIfDiskDecodeError: Boolean = true var imageConfig: Options.ImageConfig = Options.ImageConfig.ARGB_8888 + var size: Size = Size.Unspecified var scale: Scale = Scale.FILL - var sizeResolver: SizeResolver = SizeResolver.Unspecified var memoryCachePolicy: CachePolicy = CachePolicy.ENABLED var diskCachePolicy: CachePolicy = CachePolicy.ENABLED var playAnimate: Boolean = true @@ -68,8 +69,8 @@ class OptionsBuilder internal constructor() { premultipliedAlpha = options.premultipliedAlpha retryIfDiskDecodeError = options.retryIfDiskDecodeError imageConfig = options.imageConfig + size = options.size scale = options.scale - sizeResolver = options.sizeResolver memoryCachePolicy = options.memoryCachePolicy diskCachePolicy = options.diskCachePolicy playAnimate = options.playAnimate @@ -96,8 +97,8 @@ class OptionsBuilder internal constructor() { premultipliedAlpha = premultipliedAlpha, retryIfDiskDecodeError = retryIfDiskDecodeError, imageConfig = imageConfig, + size = size, scale = scale, - sizeResolver = sizeResolver, memoryCachePolicy = memoryCachePolicy, diskCachePolicy = diskCachePolicy, playAnimate = playAnimate, From 60363ae77715f056b48f0e4234f4fca49eaac93d Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:51:00 +0800 Subject: [PATCH 31/99] remove Density in SizeResolver --- .../com/seiko/imageloader/option/SizeResolver.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt index 0f4abb94..96d912e9 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt @@ -5,7 +5,7 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.DpSize interface SizeResolver { - suspend fun Density.size(): Size + suspend fun size(): Size companion object { val Unspecified = SizeResolver(Size.Unspecified) @@ -13,13 +13,9 @@ interface SizeResolver { } fun SizeResolver(block: suspend () -> Size) = object : SizeResolver { - override suspend fun Density.size(): Size = block() + override suspend fun size(): Size = block() } fun SizeResolver(size: Size): SizeResolver = object : SizeResolver { - override suspend fun Density.size(): Size = size -} - -fun SizeResolver(size: DpSize): SizeResolver = object : SizeResolver { - override suspend fun Density.size(): Size = size.toSize() + override suspend fun size(): Size = size } From 842069550eb902c8ddd83fe072ed029e57194dec Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:51:08 +0800 Subject: [PATCH 32/99] add AsyncSizeResolver --- .../com/seiko/imageloader/option/SizeResolver.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt index 96d912e9..adc0db66 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt @@ -1,8 +1,7 @@ package com.seiko.imageloader.option import androidx.compose.ui.geometry.Size -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.DpSize +import kotlinx.coroutines.CompletableDeferred interface SizeResolver { suspend fun size(): Size @@ -12,6 +11,19 @@ interface SizeResolver { } } +class AsyncSizeResolver : SizeResolver { + + private val sizeObserver = CompletableDeferred() + + override suspend fun size(): Size { + return sizeObserver.await() + } + + fun setSize(size: Size) { + sizeObserver.complete(size) + } +} + fun SizeResolver(block: suspend () -> Size) = object : SizeResolver { override suspend fun size(): Size = block() } From 8c349bb74c4370bbc57d91f66b46b89586854f18 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:52:08 +0800 Subject: [PATCH 33/99] update size use of decoder --- .../imageloader/component/decoder/BitmapFactoryDecoder.kt | 6 +++++- .../com/seiko/imageloader/component/decoder/SvgDecoder.kt | 5 +---- .../seiko/imageloader/component/decoder/SkiaImageDecoder.kt | 6 +++++- .../com/seiko/imageloader/component/decoder/SvgDecoder.kt | 5 +---- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 3a3b0f3f..4b93ee50 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -118,7 +118,11 @@ class BitmapFactoryDecoder private constructor( // EXIF transformations (but before sampling). val srcWidth = if (exifData.isSwapped) outHeight else outWidth val srcHeight = if (exifData.isSwapped) outWidth else outHeight - val (dstWidth, dstHeight) = calculateDstSize(srcWidth, srcHeight, options.maxImageSize) + val (dstWidth, dstHeight) = if (!options.size.isEmpty()) { + options.size.run { width.toInt() to height.toInt() } + } else { + calculateDstSize(srcWidth, srcHeight, options.maxImageSize) + } // Calculate the image's sample size. inSampleSize = calculateInSampleSize( srcWidth = srcWidth, diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 70361082..d33b62e7 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -20,11 +20,8 @@ class SvgDecoder private constructor( override suspend fun decode(): DecodeResult { val svg = SVG.getFromInputStream(source.source.inputStream()) - val requestSize = options.sizeResolver.run { - density.size() - } return DecodeResult.Painter( - painter = SVGPainter(svg, density, requestSize), + painter = SVGPainter(svg, density, options.size), ) } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index 06414aed..45b77996 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -32,7 +32,11 @@ class SkiaImageDecoder private constructor( // TODO wait to fix high probability crash on ios private fun Image.toBitmap(): Bitmap { val bitmap = Bitmap() - val (dstWidth, dstHeight) = calculateDstSize(width, height, options.maxImageSize) + val (dstWidth, dstHeight) = if (!options.size.isEmpty()) { + options.size.run { width.toInt() to height.toInt() } + } else { + calculateDstSize(width, height, options.maxImageSize) + } bitmap.allocN32Pixels(dstWidth, dstHeight) Canvas(bitmap).use { canvas -> canvas.drawImageRect( diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index f83e6482..c05b50c6 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -20,11 +20,8 @@ class SvgDecoder private constructor( val data = source.use { Data.makeFromBytes(it.readByteArray()) } - val requestSize = options.sizeResolver.run { - density.size() - } return DecodeResult.Painter( - painter = SVGPainter(SVGDOM(data), density, requestSize), + painter = SVGPainter(SVGDOM(data), density, options.size), ) } From b0b92ef4437ebd8fa83de7c592b34a2211f01835 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:53:02 +0800 Subject: [PATCH 34/99] use initialOptions for interceptor --- .../kotlin/com/seiko/imageloader/ImageLoader.kt | 8 ++++++-- .../imageloader/intercept/InterceptorChainHelper.kt | 9 +++------ .../seiko/imageloader/intercept/InterceptorChainImpl.kt | 4 +++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 2e4ca4b8..bf8090b5 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -6,13 +6,12 @@ import com.seiko.imageloader.model.ImageAction import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageResult +import com.seiko.imageloader.option.Options import com.seiko.imageloader.util.ioDispatcher import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.transformLatest @@ -53,8 +52,13 @@ private class RealImageLoader( if (!request.skipEvent) { emit(ImageEvent.Start) } + val initialSize = request.sizeResolver.size() + val options = Options(config.defaultOptions) { + size = initialSize + } val chain = InterceptorChainImpl( initialRequest = request, + initialOptions = options, config = config, flowCollector = this, ) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt index c1c0d75f..e1716f89 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainHelper.kt @@ -9,12 +9,13 @@ import kotlinx.coroutines.flow.FlowCollector internal class InterceptorChainHelper( initialImageRequest: ImageRequest, + private val initialOptions: Options, private val config: ImageLoaderConfig, private val flowCollector: FlowCollector, ) { val logger get() = config.logger - private val interceptors by lazy { + val interceptors by lazy { initialImageRequest.interceptors?.plus(config.interceptors.list) ?: config.interceptors.list } @@ -25,15 +26,11 @@ internal class InterceptorChainHelper( } fun getOptions(request: ImageRequest): Options { - return Options(config.defaultOptions) { + return Options(initialOptions) { takeFrom(request) } } - fun getInterceptor(index: Int): Interceptor { - return interceptors[index] - } - suspend fun emit(action: ImageAction) { flowCollector.emit(action) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainImpl.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainImpl.kt index 855e0668..9ea2e51b 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainImpl.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/InterceptorChainImpl.kt @@ -17,11 +17,13 @@ internal class InterceptorChainImpl( constructor( initialRequest: ImageRequest, + initialOptions: Options, config: ImageLoaderConfig, flowCollector: FlowCollector, ) : this( helper = InterceptorChainHelper( initialImageRequest = initialRequest, + initialOptions = initialOptions, config = config, flowCollector = flowCollector, ), @@ -36,7 +38,7 @@ internal class InterceptorChainImpl( ) override suspend fun proceed(request: ImageRequest): ImageResult { - val interceptor = helper.getInterceptor(index) + val interceptor = helper.interceptors[index] val chain = copy(index = index + 1, request = request) return interceptor.intercept(chain) } From 9cd9ae60c7f3c0a171a0bf33ebb7df1ca13e28c0 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:53:13 +0800 Subject: [PATCH 35/99] add Modifier.imageNode --- .../kotlin/com/seiko/imageloader/Modifiers.kt | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt new file mode 100644 index 00000000..f521deab --- /dev/null +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt @@ -0,0 +1,69 @@ +package com.seiko.imageloader + +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.node.LayoutModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.unit.Constraints +import com.seiko.imageloader.model.ImageRequest +import com.seiko.imageloader.option.AsyncSizeResolver + +fun Modifier.imageNode( + requestState: State, +): Modifier = this.then(ImageNodeElement(requestState)) + +private class ImageNodeElement( + private val requestState: State, +) : ModifierNodeElement() { + override fun create(): ImageNode { + return ImageNode(requestState) + } + + override fun equals(other: Any?): Boolean { + val otherModifier = other as? ImageNodeElement ?: return false + return requestState == otherModifier.requestState + } + + override fun hashCode(): Int { + return requestState.hashCode() + } + + override fun update(node: ImageNode) { + node.requestState = requestState + } +} + +private class ImageNode( + var requestState: State, +) : Modifier.Node(), LayoutModifierNode { + + val request: ImageRequest by requestState + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints, + ): MeasureResult { + val sizeResolver = request.sizeResolver + if (sizeResolver is AsyncSizeResolver) { + val inferredSize = constraints.inferredSize() + sizeResolver.setSize(inferredSize) + } + + val placeable = measurable.measure(constraints) + return layout(placeable.width, placeable.height) { + placeable.placeRelative(0, 0) + } + } +} + +private fun Constraints.hasFixedSize() = hasFixedWidth && hasFixedHeight + +internal fun Constraints.inferredSize(): Size { + if (!hasBoundedWidth || !hasBoundedHeight) return Size.Unspecified + return Size(maxWidth.toFloat(), maxHeight.toFloat()) +} From ea0ff58d8919a28ebcd53d48193dc5be0e57b3c3 Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:53:19 +0800 Subject: [PATCH 36/99] update test --- .../kotlin/com/seiko/imageloader/model/ImageRequestTest.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt index 3630ca49..d23a3c5b 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt @@ -1,7 +1,6 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Composable -import androidx.compose.ui.geometry.Size import com.seiko.imageloader.EmptyPainter import com.seiko.imageloader.cache.CachePolicy import com.seiko.imageloader.component.decoder.Decoder @@ -10,7 +9,6 @@ import com.seiko.imageloader.component.keyer.Keyer import com.seiko.imageloader.component.mapper.Mapper import com.seiko.imageloader.option.Options import com.seiko.imageloader.option.Scale -import com.seiko.imageloader.option.SizeResolver import com.seiko.imageloader.option.takeFrom import kotlin.test.Test import kotlin.test.assertEquals @@ -31,7 +29,6 @@ class ImageRequestTest { @Test fun image_request_options_test() { - val onePxSizeResolver = SizeResolver(Size(1f, 1f)) val request = ImageRequest { options { allowInexactSize = true @@ -39,7 +36,6 @@ class ImageRequestTest { retryIfDiskDecodeError = false imageConfig = Options.ImageConfig.ALPHA_8 scale = Scale.FIT - sizeResolver = onePxSizeResolver memoryCachePolicy = CachePolicy.DISABLED diskCachePolicy = CachePolicy.READ_ONLY repeatCount = 5 @@ -57,7 +53,6 @@ class ImageRequestTest { assertFalse(options.retryIfDiskDecodeError) assertEquals(options.imageConfig, Options.ImageConfig.ALPHA_8) assertEquals(options.scale, Scale.FIT) - assertEquals(options.sizeResolver, onePxSizeResolver) assertEquals(options.memoryCachePolicy, CachePolicy.DISABLED) assertEquals(options.diskCachePolicy, CachePolicy.READ_ONLY) assertEquals(options.repeatCount, 5) From cadc66385a52c1ed2b8753b5f51cc948e8a5e95d Mon Sep 17 00:00:00 2001 From: seiko Date: Tue, 24 Oct 2023 21:55:05 +0800 Subject: [PATCH 37/99] remove deprecated --- .../com/seiko/imageloader/ImageLoader.kt | 5 - .../seiko/imageloader/RememberDeprecated.kt | 140 ------------------ .../seiko/imageloader/model/ImageRequest.kt | 5 +- .../com/seiko/imageloader/option/Options.kt | 4 - 4 files changed, 1 insertion(+), 153 deletions(-) delete mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberDeprecated.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 2e4ca4b8..1f121d51 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -26,11 +26,6 @@ interface ImageLoader { fun async(request: ImageRequest): Flow = async(flowOf(request)) - @Deprecated("", ReplaceWith("Use imageloader.async(request).filterIsInstance().first()")) - suspend fun execute(request: ImageRequest): ImageResult { - return async(request).filterIsInstance().first() - } - companion object } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberDeprecated.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberDeprecated.kt deleted file mode 100644 index 0bbb9839..00000000 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberDeprecated.kt +++ /dev/null @@ -1,140 +0,0 @@ -package com.seiko.imageloader - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.graphics.FilterQuality -import androidx.compose.ui.graphics.drawscope.DrawScope.Companion.DefaultFilterQuality -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.layout.ContentScale -import com.seiko.imageloader.model.ImageRequest -import com.seiko.imageloader.option.toScale - -@Deprecated( - message = "move contentScale into ImageRequest", - replaceWith = ReplaceWith("ImageRequest { scale(contentScale.toScale()) }"), -) -@Composable -fun rememberImagePainter( - url: String, - contentScale: ContentScale, - imageLoader: ImageLoader = LocalImageLoader.current, - filterQuality: FilterQuality = DefaultFilterQuality, - placeholderPainter: (@Composable () -> Painter)? = null, - errorPainter: (@Composable () -> Painter)? = null, -): Painter { - return rememberImagePainter( - request = remember(url, contentScale, placeholderPainter, errorPainter) { - ImageRequest { - data(url) - scale(contentScale.toScale()) - placeholderPainter?.let { placeholderPainter(it) } - errorPainter?.let { errorPainter(it) } - } - }, - imageLoader = imageLoader, - filterQuality = filterQuality, - ) -} - -@Deprecated( - message = "move contentScale into ImageRequest", - replaceWith = ReplaceWith("ImageRequest { scale(contentScale.toScale()) }"), -) -@Composable -fun rememberImagePainter( - resId: Int, - contentScale: ContentScale, - imageLoader: ImageLoader = LocalImageLoader.current, - filterQuality: FilterQuality = DefaultFilterQuality, - placeholderPainter: (@Composable () -> Painter)? = null, - errorPainter: (@Composable () -> Painter)? = null, -): Painter { - return rememberImagePainter( - request = remember(resId, contentScale, placeholderPainter, errorPainter) { - ImageRequest { - data(resId) - scale(contentScale.toScale()) - placeholderPainter?.let { placeholderPainter(it) } - errorPainter?.let { errorPainter(it) } - } - }, - imageLoader = imageLoader, - filterQuality = filterQuality, - ) -} - -@Deprecated( - message = "move contentScale into ImageRequest", - replaceWith = ReplaceWith("ImageRequest { scale(contentScale.toScale()) }"), -) -@Composable -fun rememberImagePainter( - request: ImageRequest, - contentScale: ContentScale, - imageLoader: ImageLoader = LocalImageLoader.current, - filterQuality: FilterQuality = DefaultFilterQuality, -): Painter { - return rememberImagePainter( - request = remember(request) { - ImageRequest(request) { - scale(contentScale.toScale()) - } - }, - imageLoader = imageLoader, - filterQuality = filterQuality, - ) -} - -@Deprecated("Use rememberImageAction&rememberImageActionPainter or rememberImagePainter") -@Composable -fun rememberAsyncImagePainter( - url: String, - contentScale: ContentScale = ContentScale.Fit, - imageLoader: ImageLoader = LocalImageLoader.current, - filterQuality: FilterQuality = DefaultFilterQuality, -): Painter { - val request = remember(url) { - ImageRequest { - data(url) - scale(contentScale.toScale()) - } - } - val action by rememberImageAction(request, imageLoader) - return rememberImageActionPainter(action, filterQuality) -} - -@Deprecated("Use rememberImageAction&rememberImageActionPainter or rememberImagePainter") -@Composable -fun rememberAsyncImagePainter( - resId: Int, - contentScale: ContentScale = ContentScale.Fit, - imageLoader: ImageLoader = LocalImageLoader.current, - filterQuality: FilterQuality = DefaultFilterQuality, -): Painter { - val request = remember(resId) { - ImageRequest { - data(resId) - scale(contentScale.toScale()) - } - } - val action by rememberImageAction(request, imageLoader) - return rememberImageActionPainter(action, filterQuality) -} - -@Deprecated("Use rememberImageAction&rememberImageActionPainter or rememberImagePainter") -@Composable -fun rememberAsyncImagePainter( - request: ImageRequest, - contentScale: ContentScale = ContentScale.Fit, - imageLoader: ImageLoader = LocalImageLoader.current, - filterQuality: FilterQuality = DefaultFilterQuality, -): Painter { - val newRequest = remember(request) { - ImageRequest(request) { - scale(contentScale.toScale()) - } - } - val action by rememberImageAction(newRequest, imageLoader) - return rememberImageActionPainter(action, filterQuality) -} diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index c7128251..4f45a18e 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -20,10 +20,7 @@ class ImageRequest internal constructor( internal val optionsBuilders: List Unit>, internal val components: ComponentRegistry?, internal val interceptors: List?, -) { - @Deprecated("", ReplaceWith("ImageRequest(request) {}")) - fun newBuilder(block: ImageRequestBuilder.() -> Unit) = ImageRequest(this, block) -} +) class ImageRequestBuilder internal constructor() { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt index b48361a7..c8c66f8d 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt @@ -23,10 +23,6 @@ import com.seiko.imageloader.util.DEFAULT_MAX_IMAGE_SIZE val maxImageSize: Int, val extra: ExtraData, ) { - - @Deprecated("", ReplaceWith("Options(options) {}")) - fun newBuilder(block: OptionsBuilder.() -> Unit) = Options(this, block) - enum class ImageConfig { ALPHA_8, ARGB_8888, From 854401eabb1fddb8c3a22c3eed93a6d116f9e7a8 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 13:44:18 +0800 Subject: [PATCH 38/99] remove anyMemoryCacheConfig --- .../imageloader/intercept/Interceptors.kt | 34 ++----------------- .../com/seiko/imageloader/LocalImageLoader.kt | 13 ++++--- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt index cc582e8c..e21d48b9 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt @@ -92,16 +92,8 @@ class InterceptorsBuilder internal constructor() { } fun memoryCache( - mapToMemoryValue: (ImageResult) -> Bitmap? = { - if (it is ImageResult.Bitmap) { - it.bitmap - } else { - null - } - }, - mapToImageResult: (Bitmap) -> ImageResult? = { - ImageResult.Bitmap(it) - }, + mapToMemoryValue: (ImageResult) -> Bitmap? = { (it as? ImageResult.Bitmap)?.bitmap }, + mapToImageResult: (Bitmap) -> ImageResult? = { ImageResult.Bitmap(it) }, block: () -> MemoryCache, ) { memoryCaches.add( @@ -113,27 +105,7 @@ class InterceptorsBuilder internal constructor() { ) } - fun anyMemoryCacheConfig( - valueHashProvider: (T) -> Int, - valueSizeProvider: (T) -> Int, - mapToMemoryValue: (ImageResult) -> T?, - mapToImageResult: (T) -> ImageResult?, - block: MemoryCacheBuilder.() -> Unit, - ) { - anyMemoryCache( - mapToMemoryValue = mapToMemoryValue, - mapToImageResult = mapToImageResult, - block = { - MemoryCache( - valueHashProvider = valueHashProvider, - valueSizeProvider = valueSizeProvider, - block = block, - ) - }, - ) - } - - fun anyMemoryCache( + fun memoryCache( mapToMemoryValue: (ImageResult) -> T?, mapToImageResult: (T) -> ImageResult?, block: () -> MemoryCache, diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 001834e6..e8f9fd3f 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -3,6 +3,7 @@ package com.seiko.imageloader import androidx.compose.runtime.Composable import androidx.compose.runtime.ProvidedValue import androidx.compose.runtime.ReadOnlyComposable +import com.seiko.imageloader.cache.memory.MemoryCache import com.seiko.imageloader.component.setupDefaultComponents import com.seiko.imageloader.intercept.InterceptorsBuilder import com.seiko.imageloader.model.ImageResult @@ -53,12 +54,16 @@ fun InterceptorsBuilder.defaultImageResultMemoryCache( }, mapToImageResult: (ImageResult) -> ImageResult? = { it }, ) { - anyMemoryCacheConfig( - valueHashProvider = valueHashProvider, - valueSizeProvider = valueSizeProvider, + memoryCache( mapToMemoryValue = mapToMemoryValue, mapToImageResult = mapToImageResult, ) { - maxSizeBytes(saveSize) + MemoryCache( + valueHashProvider = valueHashProvider, + valueSizeProvider = valueSizeProvider, + block = { + maxSizeBytes(saveSize) + }, + ) } } From e4dba17177ba93e441a701505a8ebdb3175873a3 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 14:09:19 +0800 Subject: [PATCH 39/99] use kotlinx.coroutines synchronized --- .../kotlin/com/seiko/imageloader/util/Platform.apple.kt | 7 ------- .../com/seiko/imageloader/cache/disk/DiskLruCache.kt | 9 +++++---- .../seiko/imageloader/cache/memory/WeakMemoryCache.kt | 8 +++++--- .../kotlin/com/seiko/imageloader/util/Platform.kt | 4 ---- .../jsMain/kotlin/com/seiko/imageloader/util/LruCache.kt | 7 ++++++- .../kotlin/com/seiko/imageloader/util/Platform.js.kt | 6 ------ .../kotlin/com/seiko/imageloader/util/Platform.jvm.kt | 6 ------ 7 files changed, 16 insertions(+), 31 deletions(-) diff --git a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt index fee06707..7c5af2a6 100644 --- a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt +++ b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt @@ -2,19 +2,12 @@ package com.seiko.imageloader.util import io.ktor.client.engine.HttpClientEngine import io.ktor.client.engine.darwin.Darwin -import kotlinx.atomicfu.locks.SynchronizedObject import okio.FileSystem import kotlin.experimental.ExperimentalNativeApi @OptIn(ExperimentalNativeApi::class) actual typealias WeakReference = kotlin.native.ref.WeakReference -actual typealias LockObject = SynchronizedObject - -internal actual inline fun synchronized(lock: LockObject, block: () -> R): R { - return kotlinx.atomicfu.locks.synchronized(lock, block) -} - internal actual val httpEngine: HttpClientEngine get() = Darwin.create() internal actual val defaultFileSystem: FileSystem? get() = FileSystem.SYSTEM diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/disk/DiskLruCache.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/disk/DiskLruCache.kt index e23dd803..63320551 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/disk/DiskLruCache.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/disk/DiskLruCache.kt @@ -1,18 +1,19 @@ package com.seiko.imageloader.cache.disk import com.seiko.imageloader.cache.disk.DiskLruCache.Editor -import com.seiko.imageloader.util.LockObject import com.seiko.imageloader.util.LruHashMap import com.seiko.imageloader.util.createFile import com.seiko.imageloader.util.deleteContents import com.seiko.imageloader.util.forEachIndices import com.seiko.imageloader.util.getOrPut -import com.seiko.imageloader.util.synchronized import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel +import kotlinx.coroutines.internal.SynchronizedObject +import kotlinx.coroutines.internal.synchronized import kotlinx.coroutines.launch import okio.BufferedSink import okio.Closeable @@ -69,7 +70,7 @@ import okio.buffer * @param valueCount the number of values per cache entry. Must be positive. * @param maxSize the maximum number of bytes this cache should use to store. */ -@OptIn(ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalCoroutinesApi::class, InternalCoroutinesApi::class) internal class DiskLruCache( fileSystem: FileSystem, private val directory: Path, @@ -138,7 +139,7 @@ internal class DiskLruCache( private var mostRecentTrimFailed = false private var mostRecentRebuildFailed = false - private val syncObject = LockObject() + private val syncObject = SynchronizedObject() private val fileSystem = object : ForwardingFileSystem(fileSystem) { override fun sink(file: Path, mustCreate: Boolean): Sink { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/memory/WeakMemoryCache.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/memory/WeakMemoryCache.kt index 979f0365..9996c4f1 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/memory/WeakMemoryCache.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/cache/memory/WeakMemoryCache.kt @@ -1,11 +1,12 @@ package com.seiko.imageloader.cache.memory import androidx.compose.ui.graphics.painter.Painter -import com.seiko.imageloader.util.LockObject import com.seiko.imageloader.util.WeakReference import com.seiko.imageloader.util.firstNotNullOfOrNullIndices import com.seiko.imageloader.util.removeIfIndices -import com.seiko.imageloader.util.synchronized +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.internal.SynchronizedObject +import kotlinx.coroutines.internal.synchronized /** * An in-memory cache that holds weak references to [Painter]s. @@ -30,6 +31,7 @@ internal open class EmptyWeakMemoryCache : WeakMemoryCache { } /** A [WeakMemoryCache] implementation backed by a [LinkedHashMap]. */ +@OptIn(InternalCoroutinesApi::class) internal open class RealWeakMemoryCache( private val valueHashProvider: (V) -> Int, ) : WeakMemoryCache { @@ -37,7 +39,7 @@ internal open class RealWeakMemoryCache( internal val cache = LinkedHashMap>>() private var operationsSinceCleanUp = 0 - private val syncObject = LockObject() + private val syncObject = SynchronizedObject() override val keys: Set get() = synchronized(syncObject) { cache.keys.toSet() } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt index 59f958f7..3ed9160b 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/Platform.kt @@ -13,10 +13,6 @@ expect class WeakReference(referred: T) { fun clear() } -expect class LockObject() - -internal expect inline fun synchronized(lock: LockObject, block: () -> R): R - internal expect suspend fun ByteReadChannel.source(): BufferedSource internal expect val ioDispatcher: CoroutineDispatcher diff --git a/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/LruCache.kt b/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/LruCache.kt index 7919b203..ebfd7922 100644 --- a/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/LruCache.kt +++ b/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/LruCache.kt @@ -1,5 +1,10 @@ package com.seiko.imageloader.util +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.internal.SynchronizedObject +import kotlinx.coroutines.internal.synchronized + +@OptIn(InternalCoroutinesApi::class) actual open class LruCache actual constructor(maxSize: Int) { private var _maxSize = 0 @@ -12,7 +17,7 @@ actual open class LruCache actual constructor(maxSize: Int) { private val map: LinkedHashMap - private val syncObject = LockObject() + private val syncObject = SynchronizedObject() actual fun size() = synchronized(syncObject) { _size } diff --git a/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt b/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt index 2622cab4..3ab03eab 100644 --- a/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt +++ b/image-loader/src/jsMain/kotlin/com/seiko/imageloader/util/Platform.js.kt @@ -28,12 +28,6 @@ actual class WeakReference actual constructor(referred: T) { } } -actual typealias LockObject = Any - -internal actual inline fun synchronized(lock: LockObject, block: () -> R): R { - return kotlinx.atomicfu.locks.synchronized(lock, block) -} - internal actual val ioDispatcher: CoroutineDispatcher get() = Dispatchers.Default internal actual val httpEngine: HttpClientEngine get() = Js.create() diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt index a566ac14..7b138bec 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/util/Platform.jvm.kt @@ -11,12 +11,6 @@ import okio.source actual typealias WeakReference = java.lang.ref.WeakReference -actual typealias LockObject = Any - -internal actual inline fun synchronized(lock: LockObject, block: () -> R): R { - return kotlin.synchronized(lock, block) -} - internal actual suspend fun ByteReadChannel.source(): BufferedSource { return toInputStream().source().buffer() } From babbf9f78061ebe8d78e02ec66ff450f4dfe2e87 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 14:28:50 +0800 Subject: [PATCH 40/99] fix memoryCache build error --- .../kotlin/com/seiko/imageloader/intercept/Interceptors.kt | 2 +- .../singleton/com/seiko/imageloader/LocalImageLoader.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt index e21d48b9..c8ae067a 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt @@ -105,7 +105,7 @@ class InterceptorsBuilder internal constructor() { ) } - fun memoryCache( + fun anyMemoryCache( mapToMemoryValue: (ImageResult) -> T?, mapToImageResult: (T) -> ImageResult?, block: () -> MemoryCache, diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index e8f9fd3f..4ddc44d0 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -54,7 +54,7 @@ fun InterceptorsBuilder.defaultImageResultMemoryCache( }, mapToImageResult: (ImageResult) -> ImageResult? = { it }, ) { - memoryCache( + anyMemoryCache( mapToMemoryValue = mapToMemoryValue, mapToImageResult = mapToImageResult, ) { From 8c6fc6a4c257574b5cab86dd742222021920a19d Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 14:32:12 +0800 Subject: [PATCH 41/99] fix ImageLoader build --- .../src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index bf8090b5..26cb4e3a 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -12,6 +12,8 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.transformLatest From ca39bc44c3838f4b51301fef571470f8a36abc28 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 15:24:54 +0800 Subject: [PATCH 42/99] add Of prefix for results --- .../seiko/imageloader/demo/scene/Common.kt | 4 ++-- .../imageloader/demo/util/ImageLoader.kt | 2 +- .../imageloader/intercept/BlurInterceptor.kt | 4 ++-- .../component/decoder/ImageIODecoder.kt | 2 +- .../fetcher/MokoResourceFetcher.android.kt | 8 +++---- .../fetcher/MokoResourceFetcher.desktop.kt | 6 +++--- .../fetcher/MokoResourceFetcher.ios.kt | 6 +++--- .../fetcher/MokoResourceFetcher.js.kt | 8 +++---- .../fetcher/MokoResourceFetcher.macos.kt | 6 +++--- .../intercept/NinePatchInterceptor.kt | 4 ++-- .../component/decoder/BitmapFactoryDecoder.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/ImageDecoderDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- .../component/fetcher/AssetUriFetcher.kt | 2 +- .../component/fetcher/ContentUriFetcher.kt | 2 +- .../component/fetcher/DrawableFetcher.kt | 4 ++-- .../component/fetcher/ResourceUriFetcher.kt | 8 +++---- .../com/seiko/imageloader/ImageLoader.kt | 2 +- .../imageloader/component/decoder/Decoder.kt | 17 +++++++-------- .../component/fetcher/Base64Fetcher.kt | 2 +- .../component/fetcher/BitmapFetcher.kt | 2 +- .../imageloader/component/fetcher/Fetcher.kt | 17 +++++++-------- .../component/fetcher/KtorUrlFetcher.kt | 2 +- .../intercept/DecodeInterceptor.kt | 8 +++---- .../intercept/DiskCacheInterceptor.kt | 6 +++--- .../imageloader/intercept/FetchInterceptor.kt | 8 +++---- .../imageloader/intercept/Interceptors.kt | 4 ++-- .../seiko/imageloader/model/ImageAction.kt | 21 +++++++------------ .../com/seiko/imageloader/ImageLoaderTest.kt | 10 ++++----- .../screenshot/ChangeImageUrlCommonTest.kt | 2 +- .../screenshot/ComposeScreenShotCommonTest.kt | 6 +++--- .../component/fetcher/ByteBufferFetcher.kt | 2 +- .../component/fetcher/FileFetcher.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/SkiaImageDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- 37 files changed, 90 insertions(+), 101 deletions(-) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index 03eae010..bea02e45 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -106,10 +106,10 @@ fun ImageItem( -> { CircularProgressIndicator() } - is ImageResult.Source -> { + is ImageResult.OfSource -> { Text("image result is source") } - is ImageResult.Error -> { + is ImageResult.OfError -> { Text(current.error.message ?: "Error") } else -> Unit diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt index aa4a12b7..a464b939 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt @@ -66,7 +66,7 @@ object NullDataInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val data = chain.request.data if (data === NullRequestData || data is String && data.isEmpty()) { - return ImageResult.Painter( + return ImageResult.OfPainter( painter = EmptyPainter, ) } diff --git a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt index 586a5587..aa433f8e 100644 --- a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt +++ b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt @@ -9,9 +9,9 @@ class BlurInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.Bitmap) { + if (result is ImageResult.OfBitmap) { val blurEffects = request.blurEffects ?: return result - return ImageResult.Bitmap( + return ImageResult.OfBitmap( bitmap = blur(result.bitmap, blurEffects.radius), ) } diff --git a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt index d6254c28..e709ea08 100644 --- a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt +++ b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt @@ -15,7 +15,7 @@ class ImageIODecoder( val image = runInterruptible { ImageIO.read(source.inputStream()) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = image.toPainter(), ) } diff --git a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt index f5ff9633..caa0fcd1 100644 --- a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt +++ b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt @@ -13,26 +13,26 @@ import okio.buffer import okio.source internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = getInputStream(options.androidContext).source().buffer(), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(Color(getColor(options.androidContext))), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = options.androidContext.resources.openRawResource(rawResId).source().buffer(), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val drawable = requireNotNull(getDrawable(options.androidContext)) - return FetchResult.Image( + return FetchResult.OfImage( image = drawable.toImage(), ) } diff --git a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt index e9309b73..8ec50ec0 100644 --- a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt +++ b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt @@ -16,7 +16,7 @@ internal actual suspend fun AssetResource.toFetchResult(options: Options): Fetch } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter( Color( red = lightColor.red, @@ -31,7 +31,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.Source( + return FetchResult.OfSource( source = stream.source().buffer(), ) } @@ -39,7 +39,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.Source( + return FetchResult.OfSource( source = stream.source().buffer(), ) } diff --git a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt index 82b10621..aea29635 100644 --- a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt +++ b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt @@ -46,7 +46,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch alpha = alpha.value.toFloat(), ) } - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(color), ) } @@ -57,7 +57,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.Source( + return FetchResult.OfSource( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -68,7 +68,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch ?: throw IllegalArgumentException("can't read UIImage of $this") val cgImage: CGImageRef = uiImage.CGImage() ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.Image( + return FetchResult.OfImage( image = cgImage.toSkiaImage(), ) } diff --git a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt index 49bf0409..879d864a 100644 --- a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt +++ b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt @@ -14,25 +14,25 @@ import okio.BufferedSource import org.khronos.webgl.Int8Array internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(originalPath), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(Color(lightColor.argb)), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(fileUrl), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(fileUrl), ) } diff --git a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt index e8fc390e..bd96e573 100644 --- a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt +++ b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt @@ -24,7 +24,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch val nsColor = getNSColor() val deviceColor = nsColor.colorUsingColorSpace(deviceRGBColorSpace) ?: error("can't convert $nsColor to deviceRGBColorSpace") - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter( Color( red = deviceColor.redComponent.toFloat(), @@ -42,7 +42,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.Source( + return FetchResult.OfSource( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -56,7 +56,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch context = null, hints = null, ) ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.Image( + return FetchResult.OfImage( image = cgImage.toSkiaImage(), ) } diff --git a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt index 94c19ea1..cea77289 100644 --- a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt +++ b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt @@ -10,9 +10,9 @@ class NinePatchInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.Bitmap) { + if (result is ImageResult.OfBitmap) { val centerSlice = request.ninePatchData ?: return result - return ImageResult.Painter( + return ImageResult.OfPainter( painter = NinePatchPainter( image = result.bitmap.asImageBitmap(), ninePatchData = centerSlice, diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 4b93ee50..57f82da1 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -78,7 +78,7 @@ class BitmapFactoryDecoder private constructor( // Reverse the EXIF transformations to get the original image. val bitmap = ExifUtils.reverseTransformations(outBitmap, exifData) - return DecodeResult.Bitmap( + return DecodeResult.OfBitmap( bitmap = bitmap, ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index c67ec4eb..4d31ce7e 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -64,7 +64,7 @@ class GifDecoder private constructor( // Set the animated transformation to be applied on each frame. // drawable.setAnimatedTransformation(options.parameters.animatedTransformation()) - DecodeResult.Image( + DecodeResult.OfImage( image = drawable.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 9da950f5..7d73fc47 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -62,7 +62,7 @@ class ImageDecoderDecoder private constructor( imageDecoder?.close() wrapDecodeSource.close() } - DecodeResult.Image( + DecodeResult.OfImage( image = wrapDrawable(drawable).toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index d33b62e7..1a94751e 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -20,7 +20,7 @@ class SvgDecoder private constructor( override suspend fun decode(): DecodeResult { val svg = SVG.getFromInputStream(source.source.inputStream()) - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = SVGPainter(svg, density, options.size), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt index a8a7cc63..bbca5e1b 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt @@ -21,7 +21,7 @@ class AssetUriFetcher private constructor( override suspend fun fetch(): FetchResult { val path = data.pathSegments.drop(1).joinToString("/") - return FetchResult.Source( + return FetchResult.OfSource( source = context.assets.open(path).source().buffer(), extra = extraData { mimeType(MimeTypeMap.getSingleton().getMimeTypeFromUrl(path)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt index d58f2848..07137eaf 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt @@ -46,7 +46,7 @@ class ContentUriFetcher private constructor( checkNotNull(stream) { "Unable to open '$data'." } } - return FetchResult.Source( + return FetchResult.OfSource( source = inputStream.source().buffer(), extra = extraData { mimeType(contentResolver.getType(androidUri)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt index a98ee675..0c352809 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt @@ -10,11 +10,11 @@ class DrawableFetcher private constructor( ) : Fetcher { override suspend fun fetch(): FetchResult { return if (data is BitmapDrawable) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = data.bitmap, ) } else { - FetchResult.Image( + FetchResult.OfImage( image = data.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt index 2386d312..947987f6 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt @@ -63,7 +63,7 @@ class ResourceUriFetcher private constructor( val isVector = drawable.isVector if (isVector) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = DrawableUtils.convertToBitmap( drawable = drawable, config = options.imageConfig.toBitmapConfig(), @@ -72,18 +72,18 @@ class ResourceUriFetcher private constructor( ), ) } else if (drawable is BitmapDrawable) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = drawable.bitmap, ) } else { - FetchResult.Image( + FetchResult.OfImage( image = drawable.toImage(), ) } } else { val typedValue = TypedValue() val inputStream = resources.openRawResource(resId, typedValue) - FetchResult.Source( + FetchResult.OfSource( source = inputStream.source().buffer(), extra = extraData { mimeType(mimeType) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 26cb4e3a..4f0506a8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -67,7 +67,7 @@ private class RealImageLoader( emit(chain.proceed(request)) }.catch { if (it !is CancellationException) { - emit(ImageResult.Error(it)) + emit(ImageResult.OfError(it)) } }.flowOn(requestCoroutineContext) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt index 47880587..350944d1 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt @@ -1,10 +1,13 @@ package com.seiko.imageloader.component.decoder +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.Options -typealias DecodeSource = ImageResult.Source +typealias DecodeSource = ImageResult.OfSource interface Decoder { suspend fun decode(): DecodeResult? @@ -18,15 +21,9 @@ fun Decoder(block: () -> DecodeResult?) = object : Decoder { } sealed interface DecodeResult { - @Poko class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : DecodeResult + @Poko class OfBitmap(val bitmap: Bitmap) : DecodeResult - @Poko class Image( - val image: com.seiko.imageloader.Image, - ) : DecodeResult + @Poko class OfImage(val image: Image) : DecodeResult - @Poko class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : DecodeResult + @Poko class OfPainter(val painter: Painter) : DecodeResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt index 31465f94..402cf6b3 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt @@ -13,7 +13,7 @@ class Base64Fetcher private constructor( return data.split(',').let { val contentType = it.firstOrNull()?.removePrefix("data:")?.removeSuffix(";base64") val content = it.last() - FetchResult.Source( + FetchResult.OfSource( source = Buffer().apply { write(content.decodeBase64Bytes()) }, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt index 30625f7c..198d6caa 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt @@ -7,7 +7,7 @@ class BitmapFetcher private constructor( private val data: Bitmap, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Bitmap( + return FetchResult.OfBitmap( bitmap = data, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt index d6e1c948..955cace8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt @@ -1,5 +1,8 @@ package com.seiko.imageloader.component.fetcher +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.EmptyExtraData import com.seiko.imageloader.model.ExtraData @@ -18,20 +21,14 @@ fun Fetcher(block: suspend () -> FetchResult?) = object : Fetcher { } sealed interface FetchResult { - @Poko class Source( + @Poko class OfSource( val source: BufferedSource, val extra: ExtraData = EmptyExtraData, ) : FetchResult - @Poko class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : FetchResult + @Poko class OfBitmap(val bitmap: Bitmap) : FetchResult - @Poko class Image( - val image: com.seiko.imageloader.Image, - ) : FetchResult + @Poko class OfImage(val image: Image) : FetchResult - @Poko class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : FetchResult + @Poko class OfPainter(val painter: Painter) : FetchResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt index 21d23de7..18af6919 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt @@ -24,7 +24,7 @@ class KtorUrlFetcher private constructor( url(httpUrl) } if (response.status.isSuccess()) { - return FetchResult.Source( + return FetchResult.OfSource( source = response.bodyAsChannel().source(), extra = extraData { mimeType(response.contentType()?.toString()) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt index 00855d19..f4102b55 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt @@ -18,7 +18,7 @@ class DecodeInterceptor : Interceptor { private suspend fun proceed(chain: Interceptor.Chain, request: ImageRequest): ImageResult { val options = chain.options return when (val result = chain.proceed(request)) { - is ImageResult.Source -> { + is ImageResult.OfSource -> { runCatching { decode(chain.components, result, options) }.fold( @@ -69,7 +69,7 @@ class DecodeInterceptor : Interceptor { } private fun DecodeResult.toImageResult() = when (this) { - is DecodeResult.Bitmap -> ImageResult.Bitmap(bitmap = bitmap) - is DecodeResult.Image -> ImageResult.Image(image = image) - is DecodeResult.Painter -> ImageResult.Painter(painter = painter) + is DecodeResult.OfBitmap -> ImageResult.OfBitmap(bitmap = bitmap) + is DecodeResult.OfImage -> ImageResult.OfImage(image = image) + is DecodeResult.OfPainter -> ImageResult.OfPainter(painter = painter) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt index 0107479f..bd5a0010 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt @@ -43,7 +43,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "read disk cache" } - return ImageResult.Source( + return ImageResult.OfSource( source = snapshot.source(), dataSource = DataSource.Disk, ) @@ -53,7 +53,7 @@ class DiskCacheInterceptor( } val result = chain.proceed(request) when (result) { - is ImageResult.Source -> { + is ImageResult.OfSource -> { snapshot = runCatching { writeToDiskCache( options, @@ -73,7 +73,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "write disk cache" } - return ImageResult.Source( + return ImageResult.OfSource( source = snapshot.source(), dataSource = result.dataSource, extra = result.extra, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt index e758674d..4a94c76c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt @@ -41,18 +41,18 @@ class FetchInterceptor : Interceptor { } private fun FetchResult.toImageResult() = when (this) { - is FetchResult.Source -> ImageResult.Source( + is FetchResult.OfSource -> ImageResult.OfSource( source = source, dataSource = DataSource.Engine, extra = extra, ) - is FetchResult.Bitmap -> ImageResult.Bitmap( + is FetchResult.OfBitmap -> ImageResult.OfBitmap( bitmap = bitmap, ) - is FetchResult.Image -> ImageResult.Image( + is FetchResult.OfImage -> ImageResult.OfImage( image = image, ) - is FetchResult.Painter -> ImageResult.Painter( + is FetchResult.OfPainter -> ImageResult.OfPainter( painter = painter, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt index c8ae067a..adeca9b2 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt @@ -92,8 +92,8 @@ class InterceptorsBuilder internal constructor() { } fun memoryCache( - mapToMemoryValue: (ImageResult) -> Bitmap? = { (it as? ImageResult.Bitmap)?.bitmap }, - mapToImageResult: (Bitmap) -> ImageResult? = { ImageResult.Bitmap(it) }, + mapToMemoryValue: (ImageResult) -> Bitmap? = { (it as? ImageResult.OfBitmap)?.bitmap }, + mapToImageResult: (Bitmap) -> ImageResult? = { ImageResult.OfBitmap(it) }, block: () -> MemoryCache, ) { memoryCaches.add( diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt index 2876fdf5..ac9ce9b6 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt @@ -1,6 +1,9 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import okio.BufferedSource @@ -22,7 +25,7 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class Source( + class OfSource( val source: BufferedSource, val dataSource: DataSource, val extra: ExtraData = EmptyExtraData, @@ -30,25 +33,17 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : ImageResult + class OfBitmap(val bitmap: Bitmap) : ImageResult @Immutable @Poko - class Image( - val image: com.seiko.imageloader.Image, - ) : ImageResult + class OfImage(val image: Image) : ImageResult @Immutable @Poko - class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : ImageResult + class OfPainter(val painter: Painter) : ImageResult @Immutable @Poko - class Error( - val error: Throwable, - ) : ImageResult + class OfError(val error: Throwable) : ImageResult } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index 4a702983..a63daaa3 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -33,7 +33,7 @@ class ImageLoaderTest { add( Fetcher.Factory { data, _ -> Fetcher { - FetchResult.Painter( + FetchResult.OfPainter( when (data) { "1" -> resultPainter1 "2" -> resultPainter2 @@ -53,7 +53,7 @@ class ImageLoaderTest { imageLoader.async(request).test { assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) awaitComplete() } } @@ -69,13 +69,13 @@ class ImageLoaderTest { // 1 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) // 2 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter2), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter2), awaitItem()) // 3 - assertEquals(ImageResult.Painter(resultPainter3), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter3), awaitItem()) awaitComplete() } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt index 0de7e4e2..780f6bbd 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt @@ -33,7 +33,7 @@ abstract class ChangeImageUrlCommonTest { 3 -> Color.Gray else -> Color.Red // no display } - ImageResult.Painter(ColorPainter(color)) + ImageResult.OfPainter(ColorPainter(color)) } } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt index 7fb16a8b..7334c3fb 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt @@ -29,7 +29,7 @@ abstract class ComposeScreenShotCommonTest { addInterceptor( Interceptor { chain -> val color = if (url == chain.request.data) Color.Green else Color.Blue - ImageResult.Painter(ColorPainter(color)) + ImageResult.OfPainter(ColorPainter(color)) }, ) } @@ -58,7 +58,7 @@ abstract class ComposeScreenShotCommonTest { useDefaultInterceptors = false addInterceptor { delay(100) - ImageResult.Painter(ColorPainter(Color.Green)) + ImageResult.OfPainter(ColorPainter(Color.Green)) } } } @@ -81,7 +81,7 @@ abstract class ComposeScreenShotCommonTest { interceptor { useDefaultInterceptors = false addInterceptor { - ImageResult.Error(RuntimeException("error")) + ImageResult.OfError(RuntimeException("error")) } } } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt index 7570cbcd..a0255f68 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt @@ -14,7 +14,7 @@ class ByteBufferFetcher private constructor( // Reset the position so we can read the byte buffer again. data.position(0) } - return FetchResult.Source( + return FetchResult.OfSource( source = source, ) } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt index d2b4e789..3e2afc9c 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt @@ -12,7 +12,7 @@ class FileFetcher private constructor( private val data: File, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Source( + return FetchResult.OfSource( source = data.source().buffer(), extra = extraData { mimeType(getMimeTypeFromExtension(data.extension)) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 3f2d3f52..00549ccb 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -16,7 +16,7 @@ class GifDecoder private constructor( val codec = source.use { Codec.makeFromData(Data.makeFromBytes(it.readByteArray())) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = GifPainter( codec = codec, repeatCount = options.repeatCount, diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index 45b77996..a74012d3 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -24,7 +24,7 @@ class SkiaImageDecoder private constructor( val image = source.use { Image.makeFromEncoded(it.readByteArray()) } - DecodeResult.Bitmap( + DecodeResult.OfBitmap( bitmap = image.toBitmap(), ) } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index c05b50c6..7124e316 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -20,7 +20,7 @@ class SvgDecoder private constructor( val data = source.use { Data.makeFromBytes(it.readByteArray()) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = SVGPainter(SVGDOM(data), density, options.size), ) } From 51c546a46069be1a3eb6414212e3e33f9a4f84fb Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 15:30:14 +0800 Subject: [PATCH 43/99] add Of prefix for results --- .../seiko/imageloader/demo/scene/Common.kt | 4 ++-- .../imageloader/demo/util/ImageLoader.kt | 2 +- .../imageloader/intercept/BlurInterceptor.kt | 4 ++-- .../component/decoder/ImageIODecoder.kt | 2 +- .../fetcher/MokoResourceFetcher.android.kt | 8 +++---- .../fetcher/MokoResourceFetcher.desktop.kt | 6 +++--- .../fetcher/MokoResourceFetcher.ios.kt | 6 +++--- .../fetcher/MokoResourceFetcher.js.kt | 8 +++---- .../fetcher/MokoResourceFetcher.macos.kt | 6 +++--- .../intercept/NinePatchInterceptor.kt | 4 ++-- .../component/decoder/BitmapFactoryDecoder.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/ImageDecoderDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- .../component/fetcher/AssetUriFetcher.kt | 2 +- .../component/fetcher/ContentUriFetcher.kt | 2 +- .../component/fetcher/DrawableFetcher.kt | 4 ++-- .../component/fetcher/ResourceUriFetcher.kt | 8 +++---- .../com/seiko/imageloader/ImageLoader.kt | 2 +- .../kotlin/com/seiko/imageloader/Remember.kt | 10 ++++----- .../imageloader/component/decoder/Decoder.kt | 17 +++++++-------- .../component/fetcher/Base64Fetcher.kt | 2 +- .../component/fetcher/BitmapFetcher.kt | 2 +- .../imageloader/component/fetcher/Fetcher.kt | 17 +++++++-------- .../component/fetcher/KtorUrlFetcher.kt | 2 +- .../intercept/DecodeInterceptor.kt | 8 +++---- .../intercept/DiskCacheInterceptor.kt | 6 +++--- .../imageloader/intercept/FetchInterceptor.kt | 8 +++---- .../imageloader/intercept/Interceptors.kt | 4 ++-- .../seiko/imageloader/model/ImageAction.kt | 21 +++++++------------ .../com/seiko/imageloader/LocalImageLoader.kt | 10 ++++----- .../com/seiko/imageloader/ImageLoaderTest.kt | 10 ++++----- .../screenshot/ChangeImageUrlCommonTest.kt | 2 +- .../screenshot/ComposeScreenShotCommonTest.kt | 6 +++--- .../component/fetcher/ByteBufferFetcher.kt | 2 +- .../component/fetcher/FileFetcher.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/SkiaImageDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- 39 files changed, 100 insertions(+), 111 deletions(-) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index 03eae010..bea02e45 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -106,10 +106,10 @@ fun ImageItem( -> { CircularProgressIndicator() } - is ImageResult.Source -> { + is ImageResult.OfSource -> { Text("image result is source") } - is ImageResult.Error -> { + is ImageResult.OfError -> { Text(current.error.message ?: "Error") } else -> Unit diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt index aa4a12b7..a464b939 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt @@ -66,7 +66,7 @@ object NullDataInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val data = chain.request.data if (data === NullRequestData || data is String && data.isEmpty()) { - return ImageResult.Painter( + return ImageResult.OfPainter( painter = EmptyPainter, ) } diff --git a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt index 586a5587..aa433f8e 100644 --- a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt +++ b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt @@ -9,9 +9,9 @@ class BlurInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.Bitmap) { + if (result is ImageResult.OfBitmap) { val blurEffects = request.blurEffects ?: return result - return ImageResult.Bitmap( + return ImageResult.OfBitmap( bitmap = blur(result.bitmap, blurEffects.radius), ) } diff --git a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt index d6254c28..e709ea08 100644 --- a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt +++ b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt @@ -15,7 +15,7 @@ class ImageIODecoder( val image = runInterruptible { ImageIO.read(source.inputStream()) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = image.toPainter(), ) } diff --git a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt index f5ff9633..caa0fcd1 100644 --- a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt +++ b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt @@ -13,26 +13,26 @@ import okio.buffer import okio.source internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = getInputStream(options.androidContext).source().buffer(), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(Color(getColor(options.androidContext))), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = options.androidContext.resources.openRawResource(rawResId).source().buffer(), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val drawable = requireNotNull(getDrawable(options.androidContext)) - return FetchResult.Image( + return FetchResult.OfImage( image = drawable.toImage(), ) } diff --git a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt index e9309b73..8ec50ec0 100644 --- a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt +++ b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt @@ -16,7 +16,7 @@ internal actual suspend fun AssetResource.toFetchResult(options: Options): Fetch } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter( Color( red = lightColor.red, @@ -31,7 +31,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.Source( + return FetchResult.OfSource( source = stream.source().buffer(), ) } @@ -39,7 +39,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.Source( + return FetchResult.OfSource( source = stream.source().buffer(), ) } diff --git a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt index 82b10621..aea29635 100644 --- a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt +++ b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt @@ -46,7 +46,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch alpha = alpha.value.toFloat(), ) } - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(color), ) } @@ -57,7 +57,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.Source( + return FetchResult.OfSource( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -68,7 +68,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch ?: throw IllegalArgumentException("can't read UIImage of $this") val cgImage: CGImageRef = uiImage.CGImage() ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.Image( + return FetchResult.OfImage( image = cgImage.toSkiaImage(), ) } diff --git a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt index 49bf0409..879d864a 100644 --- a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt +++ b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt @@ -14,25 +14,25 @@ import okio.BufferedSource import org.khronos.webgl.Int8Array internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(originalPath), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(Color(lightColor.argb)), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(fileUrl), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(fileUrl), ) } diff --git a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt index e8fc390e..bd96e573 100644 --- a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt +++ b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt @@ -24,7 +24,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch val nsColor = getNSColor() val deviceColor = nsColor.colorUsingColorSpace(deviceRGBColorSpace) ?: error("can't convert $nsColor to deviceRGBColorSpace") - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter( Color( red = deviceColor.redComponent.toFloat(), @@ -42,7 +42,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.Source( + return FetchResult.OfSource( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -56,7 +56,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch context = null, hints = null, ) ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.Image( + return FetchResult.OfImage( image = cgImage.toSkiaImage(), ) } diff --git a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt index 94c19ea1..cea77289 100644 --- a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt +++ b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt @@ -10,9 +10,9 @@ class NinePatchInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.Bitmap) { + if (result is ImageResult.OfBitmap) { val centerSlice = request.ninePatchData ?: return result - return ImageResult.Painter( + return ImageResult.OfPainter( painter = NinePatchPainter( image = result.bitmap.asImageBitmap(), ninePatchData = centerSlice, diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 3a3b0f3f..2e2f0174 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -78,7 +78,7 @@ class BitmapFactoryDecoder private constructor( // Reverse the EXIF transformations to get the original image. val bitmap = ExifUtils.reverseTransformations(outBitmap, exifData) - return DecodeResult.Bitmap( + return DecodeResult.OfBitmap( bitmap = bitmap, ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index c67ec4eb..4d31ce7e 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -64,7 +64,7 @@ class GifDecoder private constructor( // Set the animated transformation to be applied on each frame. // drawable.setAnimatedTransformation(options.parameters.animatedTransformation()) - DecodeResult.Image( + DecodeResult.OfImage( image = drawable.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 9da950f5..7d73fc47 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -62,7 +62,7 @@ class ImageDecoderDecoder private constructor( imageDecoder?.close() wrapDecodeSource.close() } - DecodeResult.Image( + DecodeResult.OfImage( image = wrapDrawable(drawable).toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 70361082..a2a54697 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -23,7 +23,7 @@ class SvgDecoder private constructor( val requestSize = options.sizeResolver.run { density.size() } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = SVGPainter(svg, density, requestSize), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt index a8a7cc63..bbca5e1b 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt @@ -21,7 +21,7 @@ class AssetUriFetcher private constructor( override suspend fun fetch(): FetchResult { val path = data.pathSegments.drop(1).joinToString("/") - return FetchResult.Source( + return FetchResult.OfSource( source = context.assets.open(path).source().buffer(), extra = extraData { mimeType(MimeTypeMap.getSingleton().getMimeTypeFromUrl(path)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt index d58f2848..07137eaf 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt @@ -46,7 +46,7 @@ class ContentUriFetcher private constructor( checkNotNull(stream) { "Unable to open '$data'." } } - return FetchResult.Source( + return FetchResult.OfSource( source = inputStream.source().buffer(), extra = extraData { mimeType(contentResolver.getType(androidUri)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt index a98ee675..0c352809 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt @@ -10,11 +10,11 @@ class DrawableFetcher private constructor( ) : Fetcher { override suspend fun fetch(): FetchResult { return if (data is BitmapDrawable) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = data.bitmap, ) } else { - FetchResult.Image( + FetchResult.OfImage( image = data.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt index 2386d312..947987f6 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt @@ -63,7 +63,7 @@ class ResourceUriFetcher private constructor( val isVector = drawable.isVector if (isVector) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = DrawableUtils.convertToBitmap( drawable = drawable, config = options.imageConfig.toBitmapConfig(), @@ -72,18 +72,18 @@ class ResourceUriFetcher private constructor( ), ) } else if (drawable is BitmapDrawable) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = drawable.bitmap, ) } else { - FetchResult.Image( + FetchResult.OfImage( image = drawable.toImage(), ) } } else { val typedValue = TypedValue() val inputStream = resources.openRawResource(resId, typedValue) - FetchResult.Source( + FetchResult.OfSource( source = inputStream.source().buffer(), extra = extraData { mimeType(mimeType) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 2e4ca4b8..b1c5fc20 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -61,7 +61,7 @@ private class RealImageLoader( emit(chain.proceed(request)) }.catch { if (it !is CancellationException) { - emit(ImageResult.Error(it)) + emit(ImageResult.OfError(it)) } }.flowOn(requestCoroutineContext) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt index 795760b7..279af95a 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt @@ -73,17 +73,17 @@ fun rememberImageResultPainter( errorPainter: (@Composable () -> Painter)? = null, ): Painter { return when (result) { - is ImageResult.Painter -> remember(result) { + is ImageResult.OfPainter -> remember(result) { result.painter } - is ImageResult.Bitmap -> remember(result, filterQuality) { + is ImageResult.OfBitmap -> remember(result, filterQuality) { result.bitmap.toPainter(filterQuality) } - is ImageResult.Image -> remember(result) { + is ImageResult.OfImage -> remember(result) { result.image.toPainter() } - is ImageResult.Error, - is ImageResult.Source, + is ImageResult.OfError, + is ImageResult.OfSource, -> errorPainter?.invoke() ?: EmptyPainter }.also { painter -> if (painter is AnimationPainter) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt index 47880587..350944d1 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt @@ -1,10 +1,13 @@ package com.seiko.imageloader.component.decoder +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.Options -typealias DecodeSource = ImageResult.Source +typealias DecodeSource = ImageResult.OfSource interface Decoder { suspend fun decode(): DecodeResult? @@ -18,15 +21,9 @@ fun Decoder(block: () -> DecodeResult?) = object : Decoder { } sealed interface DecodeResult { - @Poko class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : DecodeResult + @Poko class OfBitmap(val bitmap: Bitmap) : DecodeResult - @Poko class Image( - val image: com.seiko.imageloader.Image, - ) : DecodeResult + @Poko class OfImage(val image: Image) : DecodeResult - @Poko class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : DecodeResult + @Poko class OfPainter(val painter: Painter) : DecodeResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt index 31465f94..402cf6b3 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt @@ -13,7 +13,7 @@ class Base64Fetcher private constructor( return data.split(',').let { val contentType = it.firstOrNull()?.removePrefix("data:")?.removeSuffix(";base64") val content = it.last() - FetchResult.Source( + FetchResult.OfSource( source = Buffer().apply { write(content.decodeBase64Bytes()) }, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt index 30625f7c..198d6caa 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt @@ -7,7 +7,7 @@ class BitmapFetcher private constructor( private val data: Bitmap, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Bitmap( + return FetchResult.OfBitmap( bitmap = data, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt index d6e1c948..955cace8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt @@ -1,5 +1,8 @@ package com.seiko.imageloader.component.fetcher +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.EmptyExtraData import com.seiko.imageloader.model.ExtraData @@ -18,20 +21,14 @@ fun Fetcher(block: suspend () -> FetchResult?) = object : Fetcher { } sealed interface FetchResult { - @Poko class Source( + @Poko class OfSource( val source: BufferedSource, val extra: ExtraData = EmptyExtraData, ) : FetchResult - @Poko class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : FetchResult + @Poko class OfBitmap(val bitmap: Bitmap) : FetchResult - @Poko class Image( - val image: com.seiko.imageloader.Image, - ) : FetchResult + @Poko class OfImage(val image: Image) : FetchResult - @Poko class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : FetchResult + @Poko class OfPainter(val painter: Painter) : FetchResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt index 21d23de7..18af6919 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt @@ -24,7 +24,7 @@ class KtorUrlFetcher private constructor( url(httpUrl) } if (response.status.isSuccess()) { - return FetchResult.Source( + return FetchResult.OfSource( source = response.bodyAsChannel().source(), extra = extraData { mimeType(response.contentType()?.toString()) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt index 00855d19..f4102b55 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt @@ -18,7 +18,7 @@ class DecodeInterceptor : Interceptor { private suspend fun proceed(chain: Interceptor.Chain, request: ImageRequest): ImageResult { val options = chain.options return when (val result = chain.proceed(request)) { - is ImageResult.Source -> { + is ImageResult.OfSource -> { runCatching { decode(chain.components, result, options) }.fold( @@ -69,7 +69,7 @@ class DecodeInterceptor : Interceptor { } private fun DecodeResult.toImageResult() = when (this) { - is DecodeResult.Bitmap -> ImageResult.Bitmap(bitmap = bitmap) - is DecodeResult.Image -> ImageResult.Image(image = image) - is DecodeResult.Painter -> ImageResult.Painter(painter = painter) + is DecodeResult.OfBitmap -> ImageResult.OfBitmap(bitmap = bitmap) + is DecodeResult.OfImage -> ImageResult.OfImage(image = image) + is DecodeResult.OfPainter -> ImageResult.OfPainter(painter = painter) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt index 0107479f..bd5a0010 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt @@ -43,7 +43,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "read disk cache" } - return ImageResult.Source( + return ImageResult.OfSource( source = snapshot.source(), dataSource = DataSource.Disk, ) @@ -53,7 +53,7 @@ class DiskCacheInterceptor( } val result = chain.proceed(request) when (result) { - is ImageResult.Source -> { + is ImageResult.OfSource -> { snapshot = runCatching { writeToDiskCache( options, @@ -73,7 +73,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "write disk cache" } - return ImageResult.Source( + return ImageResult.OfSource( source = snapshot.source(), dataSource = result.dataSource, extra = result.extra, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt index e758674d..4a94c76c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt @@ -41,18 +41,18 @@ class FetchInterceptor : Interceptor { } private fun FetchResult.toImageResult() = when (this) { - is FetchResult.Source -> ImageResult.Source( + is FetchResult.OfSource -> ImageResult.OfSource( source = source, dataSource = DataSource.Engine, extra = extra, ) - is FetchResult.Bitmap -> ImageResult.Bitmap( + is FetchResult.OfBitmap -> ImageResult.OfBitmap( bitmap = bitmap, ) - is FetchResult.Image -> ImageResult.Image( + is FetchResult.OfImage -> ImageResult.OfImage( image = image, ) - is FetchResult.Painter -> ImageResult.Painter( + is FetchResult.OfPainter -> ImageResult.OfPainter( painter = painter, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt index cc582e8c..1dc4b98c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt @@ -93,14 +93,14 @@ class InterceptorsBuilder internal constructor() { fun memoryCache( mapToMemoryValue: (ImageResult) -> Bitmap? = { - if (it is ImageResult.Bitmap) { + if (it is ImageResult.OfBitmap) { it.bitmap } else { null } }, mapToImageResult: (Bitmap) -> ImageResult? = { - ImageResult.Bitmap(it) + ImageResult.OfBitmap(it) }, block: () -> MemoryCache, ) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt index 2876fdf5..ac9ce9b6 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt @@ -1,6 +1,9 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import okio.BufferedSource @@ -22,7 +25,7 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class Source( + class OfSource( val source: BufferedSource, val dataSource: DataSource, val extra: ExtraData = EmptyExtraData, @@ -30,25 +33,17 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : ImageResult + class OfBitmap(val bitmap: Bitmap) : ImageResult @Immutable @Poko - class Image( - val image: com.seiko.imageloader.Image, - ) : ImageResult + class OfImage(val image: Image) : ImageResult @Immutable @Poko - class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : ImageResult + class OfPainter(val painter: Painter) : ImageResult @Immutable @Poko - class Error( - val error: Throwable, - ) : ImageResult + class OfError(val error: Throwable) : ImageResult } diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 001834e6..39d446ab 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -42,12 +42,12 @@ fun InterceptorsBuilder.defaultImageResultMemoryCache( valueSizeProvider: (ImageResult) -> Int = { 1 }, mapToMemoryValue: (ImageResult) -> ImageResult? = { when (it) { - is ImageResult.Image, - is ImageResult.Painter, + is ImageResult.OfImage, + is ImageResult.OfPainter, -> it - is ImageResult.Bitmap -> if (includeBitmap) it else null - is ImageResult.Source, - is ImageResult.Error, + is ImageResult.OfBitmap -> if (includeBitmap) it else null + is ImageResult.OfSource, + is ImageResult.OfError, -> null } }, diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index 4a702983..a63daaa3 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -33,7 +33,7 @@ class ImageLoaderTest { add( Fetcher.Factory { data, _ -> Fetcher { - FetchResult.Painter( + FetchResult.OfPainter( when (data) { "1" -> resultPainter1 "2" -> resultPainter2 @@ -53,7 +53,7 @@ class ImageLoaderTest { imageLoader.async(request).test { assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) awaitComplete() } } @@ -69,13 +69,13 @@ class ImageLoaderTest { // 1 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) // 2 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter2), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter2), awaitItem()) // 3 - assertEquals(ImageResult.Painter(resultPainter3), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter3), awaitItem()) awaitComplete() } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt index 0de7e4e2..780f6bbd 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt @@ -33,7 +33,7 @@ abstract class ChangeImageUrlCommonTest { 3 -> Color.Gray else -> Color.Red // no display } - ImageResult.Painter(ColorPainter(color)) + ImageResult.OfPainter(ColorPainter(color)) } } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt index 7fb16a8b..7334c3fb 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt @@ -29,7 +29,7 @@ abstract class ComposeScreenShotCommonTest { addInterceptor( Interceptor { chain -> val color = if (url == chain.request.data) Color.Green else Color.Blue - ImageResult.Painter(ColorPainter(color)) + ImageResult.OfPainter(ColorPainter(color)) }, ) } @@ -58,7 +58,7 @@ abstract class ComposeScreenShotCommonTest { useDefaultInterceptors = false addInterceptor { delay(100) - ImageResult.Painter(ColorPainter(Color.Green)) + ImageResult.OfPainter(ColorPainter(Color.Green)) } } } @@ -81,7 +81,7 @@ abstract class ComposeScreenShotCommonTest { interceptor { useDefaultInterceptors = false addInterceptor { - ImageResult.Error(RuntimeException("error")) + ImageResult.OfError(RuntimeException("error")) } } } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt index 7570cbcd..a0255f68 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt @@ -14,7 +14,7 @@ class ByteBufferFetcher private constructor( // Reset the position so we can read the byte buffer again. data.position(0) } - return FetchResult.Source( + return FetchResult.OfSource( source = source, ) } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt index d2b4e789..3e2afc9c 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt @@ -12,7 +12,7 @@ class FileFetcher private constructor( private val data: File, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Source( + return FetchResult.OfSource( source = data.source().buffer(), extra = extraData { mimeType(getMimeTypeFromExtension(data.extension)) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 3f2d3f52..00549ccb 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -16,7 +16,7 @@ class GifDecoder private constructor( val codec = source.use { Codec.makeFromData(Data.makeFromBytes(it.readByteArray())) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = GifPainter( codec = codec, repeatCount = options.repeatCount, diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index 06414aed..0447666d 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -24,7 +24,7 @@ class SkiaImageDecoder private constructor( val image = source.use { Image.makeFromEncoded(it.readByteArray()) } - DecodeResult.Bitmap( + DecodeResult.OfBitmap( bitmap = image.toBitmap(), ) } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index f83e6482..94c66b9d 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -23,7 +23,7 @@ class SvgDecoder private constructor( val requestSize = options.sizeResolver.run { density.size() } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = SVGPainter(SVGDOM(data), density, requestSize), ) } From 0a6e9e4753c441b687c6f77379b544424e190adf Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 15:40:02 +0800 Subject: [PATCH 44/99] Revert "add Of prefix for results" This reverts commit 51c546a46069be1a3eb6414212e3e33f9a4f84fb. --- .../seiko/imageloader/demo/scene/Common.kt | 4 ++-- .../imageloader/demo/util/ImageLoader.kt | 2 +- .../imageloader/intercept/BlurInterceptor.kt | 4 ++-- .../component/decoder/ImageIODecoder.kt | 2 +- .../fetcher/MokoResourceFetcher.android.kt | 8 +++---- .../fetcher/MokoResourceFetcher.desktop.kt | 6 +++--- .../fetcher/MokoResourceFetcher.ios.kt | 6 +++--- .../fetcher/MokoResourceFetcher.js.kt | 8 +++---- .../fetcher/MokoResourceFetcher.macos.kt | 6 +++--- .../intercept/NinePatchInterceptor.kt | 4 ++-- .../component/decoder/BitmapFactoryDecoder.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/ImageDecoderDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- .../component/fetcher/AssetUriFetcher.kt | 2 +- .../component/fetcher/ContentUriFetcher.kt | 2 +- .../component/fetcher/DrawableFetcher.kt | 4 ++-- .../component/fetcher/ResourceUriFetcher.kt | 8 +++---- .../com/seiko/imageloader/ImageLoader.kt | 2 +- .../kotlin/com/seiko/imageloader/Remember.kt | 10 ++++----- .../imageloader/component/decoder/Decoder.kt | 17 ++++++++------- .../component/fetcher/Base64Fetcher.kt | 2 +- .../component/fetcher/BitmapFetcher.kt | 2 +- .../imageloader/component/fetcher/Fetcher.kt | 17 ++++++++------- .../component/fetcher/KtorUrlFetcher.kt | 2 +- .../intercept/DecodeInterceptor.kt | 8 +++---- .../intercept/DiskCacheInterceptor.kt | 6 +++--- .../imageloader/intercept/FetchInterceptor.kt | 8 +++---- .../imageloader/intercept/Interceptors.kt | 4 ++-- .../seiko/imageloader/model/ImageAction.kt | 21 ++++++++++++------- .../com/seiko/imageloader/LocalImageLoader.kt | 10 ++++----- .../com/seiko/imageloader/ImageLoaderTest.kt | 10 ++++----- .../screenshot/ChangeImageUrlCommonTest.kt | 2 +- .../screenshot/ComposeScreenShotCommonTest.kt | 6 +++--- .../component/fetcher/ByteBufferFetcher.kt | 2 +- .../component/fetcher/FileFetcher.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/SkiaImageDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- 39 files changed, 111 insertions(+), 100 deletions(-) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index bea02e45..03eae010 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -106,10 +106,10 @@ fun ImageItem( -> { CircularProgressIndicator() } - is ImageResult.OfSource -> { + is ImageResult.Source -> { Text("image result is source") } - is ImageResult.OfError -> { + is ImageResult.Error -> { Text(current.error.message ?: "Error") } else -> Unit diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt index a464b939..aa4a12b7 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt @@ -66,7 +66,7 @@ object NullDataInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val data = chain.request.data if (data === NullRequestData || data is String && data.isEmpty()) { - return ImageResult.OfPainter( + return ImageResult.Painter( painter = EmptyPainter, ) } diff --git a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt index aa433f8e..586a5587 100644 --- a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt +++ b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt @@ -9,9 +9,9 @@ class BlurInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.OfBitmap) { + if (result is ImageResult.Bitmap) { val blurEffects = request.blurEffects ?: return result - return ImageResult.OfBitmap( + return ImageResult.Bitmap( bitmap = blur(result.bitmap, blurEffects.radius), ) } diff --git a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt index e709ea08..d6254c28 100644 --- a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt +++ b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt @@ -15,7 +15,7 @@ class ImageIODecoder( val image = runInterruptible { ImageIO.read(source.inputStream()) } - return DecodeResult.OfPainter( + return DecodeResult.Painter( painter = image.toPainter(), ) } diff --git a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt index caa0fcd1..f5ff9633 100644 --- a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt +++ b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt @@ -13,26 +13,26 @@ import okio.buffer import okio.source internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfSource( + return FetchResult.Source( source = getInputStream(options.androidContext).source().buffer(), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfPainter( + return FetchResult.Painter( painter = ColorPainter(Color(getColor(options.androidContext))), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfSource( + return FetchResult.Source( source = options.androidContext.resources.openRawResource(rawResId).source().buffer(), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val drawable = requireNotNull(getDrawable(options.androidContext)) - return FetchResult.OfImage( + return FetchResult.Image( image = drawable.toImage(), ) } diff --git a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt index 8ec50ec0..e9309b73 100644 --- a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt +++ b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt @@ -16,7 +16,7 @@ internal actual suspend fun AssetResource.toFetchResult(options: Options): Fetch } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfPainter( + return FetchResult.Painter( painter = ColorPainter( Color( red = lightColor.red, @@ -31,7 +31,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.OfSource( + return FetchResult.Source( source = stream.source().buffer(), ) } @@ -39,7 +39,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.OfSource( + return FetchResult.Source( source = stream.source().buffer(), ) } diff --git a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt index aea29635..82b10621 100644 --- a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt +++ b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt @@ -46,7 +46,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch alpha = alpha.value.toFloat(), ) } - return FetchResult.OfPainter( + return FetchResult.Painter( painter = ColorPainter(color), ) } @@ -57,7 +57,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.OfSource( + return FetchResult.Source( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -68,7 +68,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch ?: throw IllegalArgumentException("can't read UIImage of $this") val cgImage: CGImageRef = uiImage.CGImage() ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.OfImage( + return FetchResult.Image( image = cgImage.toSkiaImage(), ) } diff --git a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt index 879d864a..49bf0409 100644 --- a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt +++ b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt @@ -14,25 +14,25 @@ import okio.BufferedSource import org.khronos.webgl.Int8Array internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfSource( + return FetchResult.Source( source = fetchToSource(originalPath), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfPainter( + return FetchResult.Painter( painter = ColorPainter(Color(lightColor.argb)), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfSource( + return FetchResult.Source( source = fetchToSource(fileUrl), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.OfSource( + return FetchResult.Source( source = fetchToSource(fileUrl), ) } diff --git a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt index bd96e573..e8fc390e 100644 --- a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt +++ b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt @@ -24,7 +24,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch val nsColor = getNSColor() val deviceColor = nsColor.colorUsingColorSpace(deviceRGBColorSpace) ?: error("can't convert $nsColor to deviceRGBColorSpace") - return FetchResult.OfPainter( + return FetchResult.Painter( painter = ColorPainter( Color( red = deviceColor.redComponent.toFloat(), @@ -42,7 +42,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.OfSource( + return FetchResult.Source( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -56,7 +56,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch context = null, hints = null, ) ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.OfImage( + return FetchResult.Image( image = cgImage.toSkiaImage(), ) } diff --git a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt index cea77289..94c19ea1 100644 --- a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt +++ b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt @@ -10,9 +10,9 @@ class NinePatchInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.OfBitmap) { + if (result is ImageResult.Bitmap) { val centerSlice = request.ninePatchData ?: return result - return ImageResult.OfPainter( + return ImageResult.Painter( painter = NinePatchPainter( image = result.bitmap.asImageBitmap(), ninePatchData = centerSlice, diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 2e2f0174..3a3b0f3f 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -78,7 +78,7 @@ class BitmapFactoryDecoder private constructor( // Reverse the EXIF transformations to get the original image. val bitmap = ExifUtils.reverseTransformations(outBitmap, exifData) - return DecodeResult.OfBitmap( + return DecodeResult.Bitmap( bitmap = bitmap, ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 4d31ce7e..c67ec4eb 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -64,7 +64,7 @@ class GifDecoder private constructor( // Set the animated transformation to be applied on each frame. // drawable.setAnimatedTransformation(options.parameters.animatedTransformation()) - DecodeResult.OfImage( + DecodeResult.Image( image = drawable.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 7d73fc47..9da950f5 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -62,7 +62,7 @@ class ImageDecoderDecoder private constructor( imageDecoder?.close() wrapDecodeSource.close() } - DecodeResult.OfImage( + DecodeResult.Image( image = wrapDrawable(drawable).toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index a2a54697..70361082 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -23,7 +23,7 @@ class SvgDecoder private constructor( val requestSize = options.sizeResolver.run { density.size() } - return DecodeResult.OfPainter( + return DecodeResult.Painter( painter = SVGPainter(svg, density, requestSize), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt index bbca5e1b..a8a7cc63 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt @@ -21,7 +21,7 @@ class AssetUriFetcher private constructor( override suspend fun fetch(): FetchResult { val path = data.pathSegments.drop(1).joinToString("/") - return FetchResult.OfSource( + return FetchResult.Source( source = context.assets.open(path).source().buffer(), extra = extraData { mimeType(MimeTypeMap.getSingleton().getMimeTypeFromUrl(path)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt index 07137eaf..d58f2848 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt @@ -46,7 +46,7 @@ class ContentUriFetcher private constructor( checkNotNull(stream) { "Unable to open '$data'." } } - return FetchResult.OfSource( + return FetchResult.Source( source = inputStream.source().buffer(), extra = extraData { mimeType(contentResolver.getType(androidUri)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt index 0c352809..a98ee675 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt @@ -10,11 +10,11 @@ class DrawableFetcher private constructor( ) : Fetcher { override suspend fun fetch(): FetchResult { return if (data is BitmapDrawable) { - FetchResult.OfBitmap( + FetchResult.Bitmap( bitmap = data.bitmap, ) } else { - FetchResult.OfImage( + FetchResult.Image( image = data.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt index 947987f6..2386d312 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt @@ -63,7 +63,7 @@ class ResourceUriFetcher private constructor( val isVector = drawable.isVector if (isVector) { - FetchResult.OfBitmap( + FetchResult.Bitmap( bitmap = DrawableUtils.convertToBitmap( drawable = drawable, config = options.imageConfig.toBitmapConfig(), @@ -72,18 +72,18 @@ class ResourceUriFetcher private constructor( ), ) } else if (drawable is BitmapDrawable) { - FetchResult.OfBitmap( + FetchResult.Bitmap( bitmap = drawable.bitmap, ) } else { - FetchResult.OfImage( + FetchResult.Image( image = drawable.toImage(), ) } } else { val typedValue = TypedValue() val inputStream = resources.openRawResource(resId, typedValue) - FetchResult.OfSource( + FetchResult.Source( source = inputStream.source().buffer(), extra = extraData { mimeType(mimeType) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index b1c5fc20..2e4ca4b8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -61,7 +61,7 @@ private class RealImageLoader( emit(chain.proceed(request)) }.catch { if (it !is CancellationException) { - emit(ImageResult.OfError(it)) + emit(ImageResult.Error(it)) } }.flowOn(requestCoroutineContext) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt index 279af95a..795760b7 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt @@ -73,17 +73,17 @@ fun rememberImageResultPainter( errorPainter: (@Composable () -> Painter)? = null, ): Painter { return when (result) { - is ImageResult.OfPainter -> remember(result) { + is ImageResult.Painter -> remember(result) { result.painter } - is ImageResult.OfBitmap -> remember(result, filterQuality) { + is ImageResult.Bitmap -> remember(result, filterQuality) { result.bitmap.toPainter(filterQuality) } - is ImageResult.OfImage -> remember(result) { + is ImageResult.Image -> remember(result) { result.image.toPainter() } - is ImageResult.OfError, - is ImageResult.OfSource, + is ImageResult.Error, + is ImageResult.Source, -> errorPainter?.invoke() ?: EmptyPainter }.also { painter -> if (painter is AnimationPainter) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt index 350944d1..47880587 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt @@ -1,13 +1,10 @@ package com.seiko.imageloader.component.decoder -import androidx.compose.ui.graphics.painter.Painter -import com.seiko.imageloader.Bitmap -import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.Options -typealias DecodeSource = ImageResult.OfSource +typealias DecodeSource = ImageResult.Source interface Decoder { suspend fun decode(): DecodeResult? @@ -21,9 +18,15 @@ fun Decoder(block: () -> DecodeResult?) = object : Decoder { } sealed interface DecodeResult { - @Poko class OfBitmap(val bitmap: Bitmap) : DecodeResult + @Poko class Bitmap( + val bitmap: com.seiko.imageloader.Bitmap, + ) : DecodeResult - @Poko class OfImage(val image: Image) : DecodeResult + @Poko class Image( + val image: com.seiko.imageloader.Image, + ) : DecodeResult - @Poko class OfPainter(val painter: Painter) : DecodeResult + @Poko class Painter( + val painter: androidx.compose.ui.graphics.painter.Painter, + ) : DecodeResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt index 402cf6b3..31465f94 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt @@ -13,7 +13,7 @@ class Base64Fetcher private constructor( return data.split(',').let { val contentType = it.firstOrNull()?.removePrefix("data:")?.removeSuffix(";base64") val content = it.last() - FetchResult.OfSource( + FetchResult.Source( source = Buffer().apply { write(content.decodeBase64Bytes()) }, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt index 198d6caa..30625f7c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt @@ -7,7 +7,7 @@ class BitmapFetcher private constructor( private val data: Bitmap, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.OfBitmap( + return FetchResult.Bitmap( bitmap = data, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt index 955cace8..d6e1c948 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt @@ -1,8 +1,5 @@ package com.seiko.imageloader.component.fetcher -import androidx.compose.ui.graphics.painter.Painter -import com.seiko.imageloader.Bitmap -import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.EmptyExtraData import com.seiko.imageloader.model.ExtraData @@ -21,14 +18,20 @@ fun Fetcher(block: suspend () -> FetchResult?) = object : Fetcher { } sealed interface FetchResult { - @Poko class OfSource( + @Poko class Source( val source: BufferedSource, val extra: ExtraData = EmptyExtraData, ) : FetchResult - @Poko class OfBitmap(val bitmap: Bitmap) : FetchResult + @Poko class Bitmap( + val bitmap: com.seiko.imageloader.Bitmap, + ) : FetchResult - @Poko class OfImage(val image: Image) : FetchResult + @Poko class Image( + val image: com.seiko.imageloader.Image, + ) : FetchResult - @Poko class OfPainter(val painter: Painter) : FetchResult + @Poko class Painter( + val painter: androidx.compose.ui.graphics.painter.Painter, + ) : FetchResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt index 18af6919..21d23de7 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt @@ -24,7 +24,7 @@ class KtorUrlFetcher private constructor( url(httpUrl) } if (response.status.isSuccess()) { - return FetchResult.OfSource( + return FetchResult.Source( source = response.bodyAsChannel().source(), extra = extraData { mimeType(response.contentType()?.toString()) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt index f4102b55..00855d19 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt @@ -18,7 +18,7 @@ class DecodeInterceptor : Interceptor { private suspend fun proceed(chain: Interceptor.Chain, request: ImageRequest): ImageResult { val options = chain.options return when (val result = chain.proceed(request)) { - is ImageResult.OfSource -> { + is ImageResult.Source -> { runCatching { decode(chain.components, result, options) }.fold( @@ -69,7 +69,7 @@ class DecodeInterceptor : Interceptor { } private fun DecodeResult.toImageResult() = when (this) { - is DecodeResult.OfBitmap -> ImageResult.OfBitmap(bitmap = bitmap) - is DecodeResult.OfImage -> ImageResult.OfImage(image = image) - is DecodeResult.OfPainter -> ImageResult.OfPainter(painter = painter) + is DecodeResult.Bitmap -> ImageResult.Bitmap(bitmap = bitmap) + is DecodeResult.Image -> ImageResult.Image(image = image) + is DecodeResult.Painter -> ImageResult.Painter(painter = painter) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt index bd5a0010..0107479f 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt @@ -43,7 +43,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "read disk cache" } - return ImageResult.OfSource( + return ImageResult.Source( source = snapshot.source(), dataSource = DataSource.Disk, ) @@ -53,7 +53,7 @@ class DiskCacheInterceptor( } val result = chain.proceed(request) when (result) { - is ImageResult.OfSource -> { + is ImageResult.Source -> { snapshot = runCatching { writeToDiskCache( options, @@ -73,7 +73,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "write disk cache" } - return ImageResult.OfSource( + return ImageResult.Source( source = snapshot.source(), dataSource = result.dataSource, extra = result.extra, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt index 4a94c76c..e758674d 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt @@ -41,18 +41,18 @@ class FetchInterceptor : Interceptor { } private fun FetchResult.toImageResult() = when (this) { - is FetchResult.OfSource -> ImageResult.OfSource( + is FetchResult.Source -> ImageResult.Source( source = source, dataSource = DataSource.Engine, extra = extra, ) - is FetchResult.OfBitmap -> ImageResult.OfBitmap( + is FetchResult.Bitmap -> ImageResult.Bitmap( bitmap = bitmap, ) - is FetchResult.OfImage -> ImageResult.OfImage( + is FetchResult.Image -> ImageResult.Image( image = image, ) - is FetchResult.OfPainter -> ImageResult.OfPainter( + is FetchResult.Painter -> ImageResult.Painter( painter = painter, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt index 1dc4b98c..cc582e8c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt @@ -93,14 +93,14 @@ class InterceptorsBuilder internal constructor() { fun memoryCache( mapToMemoryValue: (ImageResult) -> Bitmap? = { - if (it is ImageResult.OfBitmap) { + if (it is ImageResult.Bitmap) { it.bitmap } else { null } }, mapToImageResult: (Bitmap) -> ImageResult? = { - ImageResult.OfBitmap(it) + ImageResult.Bitmap(it) }, block: () -> MemoryCache, ) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt index ac9ce9b6..2876fdf5 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt @@ -1,9 +1,6 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Immutable -import androidx.compose.ui.graphics.painter.Painter -import com.seiko.imageloader.Bitmap -import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import okio.BufferedSource @@ -25,7 +22,7 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class OfSource( + class Source( val source: BufferedSource, val dataSource: DataSource, val extra: ExtraData = EmptyExtraData, @@ -33,17 +30,25 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class OfBitmap(val bitmap: Bitmap) : ImageResult + class Bitmap( + val bitmap: com.seiko.imageloader.Bitmap, + ) : ImageResult @Immutable @Poko - class OfImage(val image: Image) : ImageResult + class Image( + val image: com.seiko.imageloader.Image, + ) : ImageResult @Immutable @Poko - class OfPainter(val painter: Painter) : ImageResult + class Painter( + val painter: androidx.compose.ui.graphics.painter.Painter, + ) : ImageResult @Immutable @Poko - class OfError(val error: Throwable) : ImageResult + class Error( + val error: Throwable, + ) : ImageResult } diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 39d446ab..001834e6 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -42,12 +42,12 @@ fun InterceptorsBuilder.defaultImageResultMemoryCache( valueSizeProvider: (ImageResult) -> Int = { 1 }, mapToMemoryValue: (ImageResult) -> ImageResult? = { when (it) { - is ImageResult.OfImage, - is ImageResult.OfPainter, + is ImageResult.Image, + is ImageResult.Painter, -> it - is ImageResult.OfBitmap -> if (includeBitmap) it else null - is ImageResult.OfSource, - is ImageResult.OfError, + is ImageResult.Bitmap -> if (includeBitmap) it else null + is ImageResult.Source, + is ImageResult.Error, -> null } }, diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index a63daaa3..4a702983 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -33,7 +33,7 @@ class ImageLoaderTest { add( Fetcher.Factory { data, _ -> Fetcher { - FetchResult.OfPainter( + FetchResult.Painter( when (data) { "1" -> resultPainter1 "2" -> resultPainter2 @@ -53,7 +53,7 @@ class ImageLoaderTest { imageLoader.async(request).test { assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) + assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) awaitComplete() } } @@ -69,13 +69,13 @@ class ImageLoaderTest { // 1 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) + assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) // 2 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.OfPainter(resultPainter2), awaitItem()) + assertEquals(ImageResult.Painter(resultPainter2), awaitItem()) // 3 - assertEquals(ImageResult.OfPainter(resultPainter3), awaitItem()) + assertEquals(ImageResult.Painter(resultPainter3), awaitItem()) awaitComplete() } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt index 780f6bbd..0de7e4e2 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt @@ -33,7 +33,7 @@ abstract class ChangeImageUrlCommonTest { 3 -> Color.Gray else -> Color.Red // no display } - ImageResult.OfPainter(ColorPainter(color)) + ImageResult.Painter(ColorPainter(color)) } } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt index 7334c3fb..7fb16a8b 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt @@ -29,7 +29,7 @@ abstract class ComposeScreenShotCommonTest { addInterceptor( Interceptor { chain -> val color = if (url == chain.request.data) Color.Green else Color.Blue - ImageResult.OfPainter(ColorPainter(color)) + ImageResult.Painter(ColorPainter(color)) }, ) } @@ -58,7 +58,7 @@ abstract class ComposeScreenShotCommonTest { useDefaultInterceptors = false addInterceptor { delay(100) - ImageResult.OfPainter(ColorPainter(Color.Green)) + ImageResult.Painter(ColorPainter(Color.Green)) } } } @@ -81,7 +81,7 @@ abstract class ComposeScreenShotCommonTest { interceptor { useDefaultInterceptors = false addInterceptor { - ImageResult.OfError(RuntimeException("error")) + ImageResult.Error(RuntimeException("error")) } } } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt index a0255f68..7570cbcd 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt @@ -14,7 +14,7 @@ class ByteBufferFetcher private constructor( // Reset the position so we can read the byte buffer again. data.position(0) } - return FetchResult.OfSource( + return FetchResult.Source( source = source, ) } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt index 3e2afc9c..d2b4e789 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt @@ -12,7 +12,7 @@ class FileFetcher private constructor( private val data: File, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.OfSource( + return FetchResult.Source( source = data.source().buffer(), extra = extraData { mimeType(getMimeTypeFromExtension(data.extension)) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 00549ccb..3f2d3f52 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -16,7 +16,7 @@ class GifDecoder private constructor( val codec = source.use { Codec.makeFromData(Data.makeFromBytes(it.readByteArray())) } - return DecodeResult.OfPainter( + return DecodeResult.Painter( painter = GifPainter( codec = codec, repeatCount = options.repeatCount, diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index 0447666d..06414aed 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -24,7 +24,7 @@ class SkiaImageDecoder private constructor( val image = source.use { Image.makeFromEncoded(it.readByteArray()) } - DecodeResult.OfBitmap( + DecodeResult.Bitmap( bitmap = image.toBitmap(), ) } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 94c66b9d..f83e6482 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -23,7 +23,7 @@ class SvgDecoder private constructor( val requestSize = options.sizeResolver.run { density.size() } - return DecodeResult.OfPainter( + return DecodeResult.Painter( painter = SVGPainter(SVGDOM(data), density, requestSize), ) } From 57ebb3694f50f14237fb3fc593273fdde7d71438 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 15:30:14 +0800 Subject: [PATCH 45/99] add Of prefix for results (cherry picked from commit 51c546a46069be1a3eb6414212e3e33f9a4f84fb) --- .../seiko/imageloader/demo/scene/Common.kt | 4 ++-- .../imageloader/demo/util/ImageLoader.kt | 2 +- .../imageloader/intercept/BlurInterceptor.kt | 4 ++-- .../component/decoder/ImageIODecoder.kt | 2 +- .../fetcher/MokoResourceFetcher.android.kt | 8 +++---- .../fetcher/MokoResourceFetcher.desktop.kt | 6 +++--- .../fetcher/MokoResourceFetcher.ios.kt | 6 +++--- .../fetcher/MokoResourceFetcher.js.kt | 8 +++---- .../fetcher/MokoResourceFetcher.macos.kt | 6 +++--- .../intercept/NinePatchInterceptor.kt | 4 ++-- .../component/decoder/BitmapFactoryDecoder.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/ImageDecoderDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- .../component/fetcher/AssetUriFetcher.kt | 2 +- .../component/fetcher/ContentUriFetcher.kt | 2 +- .../component/fetcher/DrawableFetcher.kt | 4 ++-- .../component/fetcher/ResourceUriFetcher.kt | 8 +++---- .../com/seiko/imageloader/ImageLoader.kt | 2 +- .../kotlin/com/seiko/imageloader/Remember.kt | 10 ++++----- .../imageloader/component/decoder/Decoder.kt | 17 +++++++-------- .../component/fetcher/Base64Fetcher.kt | 2 +- .../component/fetcher/BitmapFetcher.kt | 2 +- .../imageloader/component/fetcher/Fetcher.kt | 17 +++++++-------- .../component/fetcher/KtorUrlFetcher.kt | 2 +- .../intercept/DecodeInterceptor.kt | 8 +++---- .../intercept/DiskCacheInterceptor.kt | 6 +++--- .../imageloader/intercept/FetchInterceptor.kt | 8 +++---- .../imageloader/intercept/Interceptors.kt | 4 ++-- .../seiko/imageloader/model/ImageAction.kt | 21 +++++++------------ .../com/seiko/imageloader/LocalImageLoader.kt | 10 ++++----- .../com/seiko/imageloader/ImageLoaderTest.kt | 10 ++++----- .../screenshot/ChangeImageUrlCommonTest.kt | 2 +- .../screenshot/ComposeScreenShotCommonTest.kt | 6 +++--- .../component/fetcher/ByteBufferFetcher.kt | 2 +- .../component/fetcher/FileFetcher.kt | 2 +- .../component/decoder/GifDecoder.kt | 2 +- .../component/decoder/SkiaImageDecoder.kt | 2 +- .../component/decoder/SvgDecoder.kt | 2 +- 39 files changed, 100 insertions(+), 111 deletions(-) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index 03eae010..bea02e45 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -106,10 +106,10 @@ fun ImageItem( -> { CircularProgressIndicator() } - is ImageResult.Source -> { + is ImageResult.OfSource -> { Text("image result is source") } - is ImageResult.Error -> { + is ImageResult.OfError -> { Text(current.error.message ?: "Error") } else -> Unit diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt index aa4a12b7..a464b939 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/util/ImageLoader.kt @@ -66,7 +66,7 @@ object NullDataInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val data = chain.request.data if (data === NullRequestData || data is String && data.isEmpty()) { - return ImageResult.Painter( + return ImageResult.OfPainter( painter = EmptyPainter, ) } diff --git a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt index 586a5587..aa433f8e 100644 --- a/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt +++ b/extension/blur/src/commonMain/kotlin/com/seiko/imageloader/intercept/BlurInterceptor.kt @@ -9,9 +9,9 @@ class BlurInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.Bitmap) { + if (result is ImageResult.OfBitmap) { val blurEffects = request.blurEffects ?: return result - return ImageResult.Bitmap( + return ImageResult.OfBitmap( bitmap = blur(result.bitmap, blurEffects.radius), ) } diff --git a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt index d6254c28..e709ea08 100644 --- a/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt +++ b/extension/imageio/src/jvmMain/kotlin/com/seiko/imageloader/component/decoder/ImageIODecoder.kt @@ -15,7 +15,7 @@ class ImageIODecoder( val image = runInterruptible { ImageIO.read(source.inputStream()) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = image.toPainter(), ) } diff --git a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt index f5ff9633..caa0fcd1 100644 --- a/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt +++ b/extension/moko-resources/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.android.kt @@ -13,26 +13,26 @@ import okio.buffer import okio.source internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = getInputStream(options.androidContext).source().buffer(), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(Color(getColor(options.androidContext))), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = options.androidContext.resources.openRawResource(rawResId).source().buffer(), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val drawable = requireNotNull(getDrawable(options.androidContext)) - return FetchResult.Image( + return FetchResult.OfImage( image = drawable.toImage(), ) } diff --git a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt index e9309b73..8ec50ec0 100644 --- a/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt +++ b/extension/moko-resources/src/desktopMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.desktop.kt @@ -16,7 +16,7 @@ internal actual suspend fun AssetResource.toFetchResult(options: Options): Fetch } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter( Color( red = lightColor.red, @@ -31,7 +31,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.Source( + return FetchResult.OfSource( source = stream.source().buffer(), ) } @@ -39,7 +39,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { val stream = resourcesClassLoader.getResourceAsStream(filePath) ?: throw FileNotFoundException("Couldn't open resource as stream at: $filePath") - return FetchResult.Source( + return FetchResult.OfSource( source = stream.source().buffer(), ) } diff --git a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt index 82b10621..aea29635 100644 --- a/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt +++ b/extension/moko-resources/src/iosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.ios.kt @@ -46,7 +46,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch alpha = alpha.value.toFloat(), ) } - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(color), ) } @@ -57,7 +57,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.Source( + return FetchResult.OfSource( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -68,7 +68,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch ?: throw IllegalArgumentException("can't read UIImage of $this") val cgImage: CGImageRef = uiImage.CGImage() ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.Image( + return FetchResult.OfImage( image = cgImage.toSkiaImage(), ) } diff --git a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt index 49bf0409..879d864a 100644 --- a/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt +++ b/extension/moko-resources/src/jsMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.js.kt @@ -14,25 +14,25 @@ import okio.BufferedSource import org.khronos.webgl.Int8Array internal actual suspend fun AssetResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(originalPath), ) } internal actual suspend fun ColorResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter(Color(lightColor.argb)), ) } internal actual suspend fun FileResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(fileUrl), ) } internal actual suspend fun ImageResource.toFetchResult(options: Options): FetchResult? { - return FetchResult.Source( + return FetchResult.OfSource( source = fetchToSource(fileUrl), ) } diff --git a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt index e8fc390e..bd96e573 100644 --- a/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt +++ b/extension/moko-resources/src/macosMain/kotlin/com/seiko/imageloader/component/fetcher/MokoResourceFetcher.macos.kt @@ -24,7 +24,7 @@ internal actual suspend fun ColorResource.toFetchResult(options: Options): Fetch val nsColor = getNSColor() val deviceColor = nsColor.colorUsingColorSpace(deviceRGBColorSpace) ?: error("can't convert $nsColor to deviceRGBColorSpace") - return FetchResult.Painter( + return FetchResult.OfPainter( painter = ColorPainter( Color( red = deviceColor.redComponent.toFloat(), @@ -42,7 +42,7 @@ internal actual suspend fun FileResource.toFetchResult(options: Options): FetchR ofType = extension, inDirectory = "files", )!!.toPath() - return FetchResult.Source( + return FetchResult.OfSource( source = FileSystem.SYSTEM.source(path).buffer(), ) } @@ -56,7 +56,7 @@ internal actual suspend fun ImageResource.toFetchResult(options: Options): Fetch context = null, hints = null, ) ?: throw IllegalArgumentException("can't read CGImage of $this") - return FetchResult.Image( + return FetchResult.OfImage( image = cgImage.toSkiaImage(), ) } diff --git a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt index 94c19ea1..cea77289 100644 --- a/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt +++ b/extension/nine-patch/src/commonMain/kotlin/com/seiko/imageloader/intercept/NinePatchInterceptor.kt @@ -10,9 +10,9 @@ class NinePatchInterceptor : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val request = chain.request val result = chain.proceed(request) - if (result is ImageResult.Bitmap) { + if (result is ImageResult.OfBitmap) { val centerSlice = request.ninePatchData ?: return result - return ImageResult.Painter( + return ImageResult.OfPainter( painter = NinePatchPainter( image = result.bitmap.asImageBitmap(), ninePatchData = centerSlice, diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 3a3b0f3f..2e2f0174 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -78,7 +78,7 @@ class BitmapFactoryDecoder private constructor( // Reverse the EXIF transformations to get the original image. val bitmap = ExifUtils.reverseTransformations(outBitmap, exifData) - return DecodeResult.Bitmap( + return DecodeResult.OfBitmap( bitmap = bitmap, ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index c67ec4eb..4d31ce7e 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -64,7 +64,7 @@ class GifDecoder private constructor( // Set the animated transformation to be applied on each frame. // drawable.setAnimatedTransformation(options.parameters.animatedTransformation()) - DecodeResult.Image( + DecodeResult.OfImage( image = drawable.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 9da950f5..7d73fc47 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -62,7 +62,7 @@ class ImageDecoderDecoder private constructor( imageDecoder?.close() wrapDecodeSource.close() } - DecodeResult.Image( + DecodeResult.OfImage( image = wrapDrawable(drawable).toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 70361082..a2a54697 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -23,7 +23,7 @@ class SvgDecoder private constructor( val requestSize = options.sizeResolver.run { density.size() } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = SVGPainter(svg, density, requestSize), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt index a8a7cc63..bbca5e1b 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/AssetUriFetcher.kt @@ -21,7 +21,7 @@ class AssetUriFetcher private constructor( override suspend fun fetch(): FetchResult { val path = data.pathSegments.drop(1).joinToString("/") - return FetchResult.Source( + return FetchResult.OfSource( source = context.assets.open(path).source().buffer(), extra = extraData { mimeType(MimeTypeMap.getSingleton().getMimeTypeFromUrl(path)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt index d58f2848..07137eaf 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ContentUriFetcher.kt @@ -46,7 +46,7 @@ class ContentUriFetcher private constructor( checkNotNull(stream) { "Unable to open '$data'." } } - return FetchResult.Source( + return FetchResult.OfSource( source = inputStream.source().buffer(), extra = extraData { mimeType(contentResolver.getType(androidUri)) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt index a98ee675..0c352809 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/DrawableFetcher.kt @@ -10,11 +10,11 @@ class DrawableFetcher private constructor( ) : Fetcher { override suspend fun fetch(): FetchResult { return if (data is BitmapDrawable) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = data.bitmap, ) } else { - FetchResult.Image( + FetchResult.OfImage( image = data.toImage(), ) } diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt index 2386d312..947987f6 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt @@ -63,7 +63,7 @@ class ResourceUriFetcher private constructor( val isVector = drawable.isVector if (isVector) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = DrawableUtils.convertToBitmap( drawable = drawable, config = options.imageConfig.toBitmapConfig(), @@ -72,18 +72,18 @@ class ResourceUriFetcher private constructor( ), ) } else if (drawable is BitmapDrawable) { - FetchResult.Bitmap( + FetchResult.OfBitmap( bitmap = drawable.bitmap, ) } else { - FetchResult.Image( + FetchResult.OfImage( image = drawable.toImage(), ) } } else { val typedValue = TypedValue() val inputStream = resources.openRawResource(resId, typedValue) - FetchResult.Source( + FetchResult.OfSource( source = inputStream.source().buffer(), extra = extraData { mimeType(mimeType) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 2e4ca4b8..b1c5fc20 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -61,7 +61,7 @@ private class RealImageLoader( emit(chain.proceed(request)) }.catch { if (it !is CancellationException) { - emit(ImageResult.Error(it)) + emit(ImageResult.OfError(it)) } }.flowOn(requestCoroutineContext) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt index 795760b7..279af95a 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt @@ -73,17 +73,17 @@ fun rememberImageResultPainter( errorPainter: (@Composable () -> Painter)? = null, ): Painter { return when (result) { - is ImageResult.Painter -> remember(result) { + is ImageResult.OfPainter -> remember(result) { result.painter } - is ImageResult.Bitmap -> remember(result, filterQuality) { + is ImageResult.OfBitmap -> remember(result, filterQuality) { result.bitmap.toPainter(filterQuality) } - is ImageResult.Image -> remember(result) { + is ImageResult.OfImage -> remember(result) { result.image.toPainter() } - is ImageResult.Error, - is ImageResult.Source, + is ImageResult.OfError, + is ImageResult.OfSource, -> errorPainter?.invoke() ?: EmptyPainter }.also { painter -> if (painter is AnimationPainter) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt index 47880587..350944d1 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/decoder/Decoder.kt @@ -1,10 +1,13 @@ package com.seiko.imageloader.component.decoder +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.Options -typealias DecodeSource = ImageResult.Source +typealias DecodeSource = ImageResult.OfSource interface Decoder { suspend fun decode(): DecodeResult? @@ -18,15 +21,9 @@ fun Decoder(block: () -> DecodeResult?) = object : Decoder { } sealed interface DecodeResult { - @Poko class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : DecodeResult + @Poko class OfBitmap(val bitmap: Bitmap) : DecodeResult - @Poko class Image( - val image: com.seiko.imageloader.Image, - ) : DecodeResult + @Poko class OfImage(val image: Image) : DecodeResult - @Poko class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : DecodeResult + @Poko class OfPainter(val painter: Painter) : DecodeResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt index 31465f94..402cf6b3 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Base64Fetcher.kt @@ -13,7 +13,7 @@ class Base64Fetcher private constructor( return data.split(',').let { val contentType = it.firstOrNull()?.removePrefix("data:")?.removeSuffix(";base64") val content = it.last() - FetchResult.Source( + FetchResult.OfSource( source = Buffer().apply { write(content.decodeBase64Bytes()) }, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt index 30625f7c..198d6caa 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/BitmapFetcher.kt @@ -7,7 +7,7 @@ class BitmapFetcher private constructor( private val data: Bitmap, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Bitmap( + return FetchResult.OfBitmap( bitmap = data, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt index d6e1c948..955cace8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/Fetcher.kt @@ -1,5 +1,8 @@ package com.seiko.imageloader.component.fetcher +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import com.seiko.imageloader.model.EmptyExtraData import com.seiko.imageloader.model.ExtraData @@ -18,20 +21,14 @@ fun Fetcher(block: suspend () -> FetchResult?) = object : Fetcher { } sealed interface FetchResult { - @Poko class Source( + @Poko class OfSource( val source: BufferedSource, val extra: ExtraData = EmptyExtraData, ) : FetchResult - @Poko class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : FetchResult + @Poko class OfBitmap(val bitmap: Bitmap) : FetchResult - @Poko class Image( - val image: com.seiko.imageloader.Image, - ) : FetchResult + @Poko class OfImage(val image: Image) : FetchResult - @Poko class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : FetchResult + @Poko class OfPainter(val painter: Painter) : FetchResult } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt index 21d23de7..18af6919 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/fetcher/KtorUrlFetcher.kt @@ -24,7 +24,7 @@ class KtorUrlFetcher private constructor( url(httpUrl) } if (response.status.isSuccess()) { - return FetchResult.Source( + return FetchResult.OfSource( source = response.bodyAsChannel().source(), extra = extraData { mimeType(response.contentType()?.toString()) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt index 00855d19..f4102b55 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DecodeInterceptor.kt @@ -18,7 +18,7 @@ class DecodeInterceptor : Interceptor { private suspend fun proceed(chain: Interceptor.Chain, request: ImageRequest): ImageResult { val options = chain.options return when (val result = chain.proceed(request)) { - is ImageResult.Source -> { + is ImageResult.OfSource -> { runCatching { decode(chain.components, result, options) }.fold( @@ -69,7 +69,7 @@ class DecodeInterceptor : Interceptor { } private fun DecodeResult.toImageResult() = when (this) { - is DecodeResult.Bitmap -> ImageResult.Bitmap(bitmap = bitmap) - is DecodeResult.Image -> ImageResult.Image(image = image) - is DecodeResult.Painter -> ImageResult.Painter(painter = painter) + is DecodeResult.OfBitmap -> ImageResult.OfBitmap(bitmap = bitmap) + is DecodeResult.OfImage -> ImageResult.OfImage(image = image) + is DecodeResult.OfPainter -> ImageResult.OfPainter(painter = painter) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt index 0107479f..bd5a0010 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/DiskCacheInterceptor.kt @@ -43,7 +43,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "read disk cache" } - return ImageResult.Source( + return ImageResult.OfSource( source = snapshot.source(), dataSource = DataSource.Disk, ) @@ -53,7 +53,7 @@ class DiskCacheInterceptor( } val result = chain.proceed(request) when (result) { - is ImageResult.Source -> { + is ImageResult.OfSource -> { snapshot = runCatching { writeToDiskCache( options, @@ -73,7 +73,7 @@ class DiskCacheInterceptor( tag = "DiskCacheInterceptor", data = request.data, ) { "write disk cache" } - return ImageResult.Source( + return ImageResult.OfSource( source = snapshot.source(), dataSource = result.dataSource, extra = result.extra, diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt index e758674d..4a94c76c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/FetchInterceptor.kt @@ -41,18 +41,18 @@ class FetchInterceptor : Interceptor { } private fun FetchResult.toImageResult() = when (this) { - is FetchResult.Source -> ImageResult.Source( + is FetchResult.OfSource -> ImageResult.OfSource( source = source, dataSource = DataSource.Engine, extra = extra, ) - is FetchResult.Bitmap -> ImageResult.Bitmap( + is FetchResult.OfBitmap -> ImageResult.OfBitmap( bitmap = bitmap, ) - is FetchResult.Image -> ImageResult.Image( + is FetchResult.OfImage -> ImageResult.OfImage( image = image, ) - is FetchResult.Painter -> ImageResult.Painter( + is FetchResult.OfPainter -> ImageResult.OfPainter( painter = painter, ) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt index cc582e8c..1dc4b98c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/intercept/Interceptors.kt @@ -93,14 +93,14 @@ class InterceptorsBuilder internal constructor() { fun memoryCache( mapToMemoryValue: (ImageResult) -> Bitmap? = { - if (it is ImageResult.Bitmap) { + if (it is ImageResult.OfBitmap) { it.bitmap } else { null } }, mapToImageResult: (Bitmap) -> ImageResult? = { - ImageResult.Bitmap(it) + ImageResult.OfBitmap(it) }, block: () -> MemoryCache, ) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt index 2876fdf5..ac9ce9b6 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageAction.kt @@ -1,6 +1,9 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Bitmap +import com.seiko.imageloader.Image import com.seiko.imageloader.Poko import okio.BufferedSource @@ -22,7 +25,7 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class Source( + class OfSource( val source: BufferedSource, val dataSource: DataSource, val extra: ExtraData = EmptyExtraData, @@ -30,25 +33,17 @@ sealed interface ImageResult : ImageAction { @Immutable @Poko - class Bitmap( - val bitmap: com.seiko.imageloader.Bitmap, - ) : ImageResult + class OfBitmap(val bitmap: Bitmap) : ImageResult @Immutable @Poko - class Image( - val image: com.seiko.imageloader.Image, - ) : ImageResult + class OfImage(val image: Image) : ImageResult @Immutable @Poko - class Painter( - val painter: androidx.compose.ui.graphics.painter.Painter, - ) : ImageResult + class OfPainter(val painter: Painter) : ImageResult @Immutable @Poko - class Error( - val error: Throwable, - ) : ImageResult + class OfError(val error: Throwable) : ImageResult } diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 001834e6..39d446ab 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -42,12 +42,12 @@ fun InterceptorsBuilder.defaultImageResultMemoryCache( valueSizeProvider: (ImageResult) -> Int = { 1 }, mapToMemoryValue: (ImageResult) -> ImageResult? = { when (it) { - is ImageResult.Image, - is ImageResult.Painter, + is ImageResult.OfImage, + is ImageResult.OfPainter, -> it - is ImageResult.Bitmap -> if (includeBitmap) it else null - is ImageResult.Source, - is ImageResult.Error, + is ImageResult.OfBitmap -> if (includeBitmap) it else null + is ImageResult.OfSource, + is ImageResult.OfError, -> null } }, diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index 4a702983..a63daaa3 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -33,7 +33,7 @@ class ImageLoaderTest { add( Fetcher.Factory { data, _ -> Fetcher { - FetchResult.Painter( + FetchResult.OfPainter( when (data) { "1" -> resultPainter1 "2" -> resultPainter2 @@ -53,7 +53,7 @@ class ImageLoaderTest { imageLoader.async(request).test { assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) awaitComplete() } } @@ -69,13 +69,13 @@ class ImageLoaderTest { // 1 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter1), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter1), awaitItem()) // 2 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) - assertEquals(ImageResult.Painter(resultPainter2), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter2), awaitItem()) // 3 - assertEquals(ImageResult.Painter(resultPainter3), awaitItem()) + assertEquals(ImageResult.OfPainter(resultPainter3), awaitItem()) awaitComplete() } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt index 0de7e4e2..780f6bbd 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlCommonTest.kt @@ -33,7 +33,7 @@ abstract class ChangeImageUrlCommonTest { 3 -> Color.Gray else -> Color.Red // no display } - ImageResult.Painter(ColorPainter(color)) + ImageResult.OfPainter(ColorPainter(color)) } } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt index 7fb16a8b..7334c3fb 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotCommonTest.kt @@ -29,7 +29,7 @@ abstract class ComposeScreenShotCommonTest { addInterceptor( Interceptor { chain -> val color = if (url == chain.request.data) Color.Green else Color.Blue - ImageResult.Painter(ColorPainter(color)) + ImageResult.OfPainter(ColorPainter(color)) }, ) } @@ -58,7 +58,7 @@ abstract class ComposeScreenShotCommonTest { useDefaultInterceptors = false addInterceptor { delay(100) - ImageResult.Painter(ColorPainter(Color.Green)) + ImageResult.OfPainter(ColorPainter(Color.Green)) } } } @@ -81,7 +81,7 @@ abstract class ComposeScreenShotCommonTest { interceptor { useDefaultInterceptors = false addInterceptor { - ImageResult.Error(RuntimeException("error")) + ImageResult.OfError(RuntimeException("error")) } } } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt index 7570cbcd..a0255f68 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/ByteBufferFetcher.kt @@ -14,7 +14,7 @@ class ByteBufferFetcher private constructor( // Reset the position so we can read the byte buffer again. data.position(0) } - return FetchResult.Source( + return FetchResult.OfSource( source = source, ) } diff --git a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt index d2b4e789..3e2afc9c 100644 --- a/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt +++ b/image-loader/src/jvmMain/kotlin/com/seiko/imageloader/component/fetcher/FileFetcher.kt @@ -12,7 +12,7 @@ class FileFetcher private constructor( private val data: File, ) : Fetcher { override suspend fun fetch(): FetchResult { - return FetchResult.Source( + return FetchResult.OfSource( source = data.source().buffer(), extra = extraData { mimeType(getMimeTypeFromExtension(data.extension)) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 3f2d3f52..00549ccb 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -16,7 +16,7 @@ class GifDecoder private constructor( val codec = source.use { Codec.makeFromData(Data.makeFromBytes(it.readByteArray())) } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = GifPainter( codec = codec, repeatCount = options.repeatCount, diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index 06414aed..0447666d 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -24,7 +24,7 @@ class SkiaImageDecoder private constructor( val image = source.use { Image.makeFromEncoded(it.readByteArray()) } - DecodeResult.Bitmap( + DecodeResult.OfBitmap( bitmap = image.toBitmap(), ) } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index f83e6482..94c66b9d 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -23,7 +23,7 @@ class SvgDecoder private constructor( val requestSize = options.sizeResolver.run { density.size() } - return DecodeResult.Painter( + return DecodeResult.OfPainter( painter = SVGPainter(SVGDOM(data), density, requestSize), ) } From 7dd1473fb6ba6fd15784deef620acc3fd163c3cf Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 25 Oct 2023 15:24:54 +0800 Subject: [PATCH 46/99] rename ImageConfig to BitmapConfig --- .../component/decoder/BitmapFactoryDecoder.kt | 2 +- .../imageloader/component/decoder/GifDecoder.kt | 2 +- .../component/decoder/ImageDecoderDecoder.kt | 2 +- .../component/fetcher/ResourceUriFetcher.kt | 2 +- .../kotlin/com/seiko/imageloader/util/Bitmap.kt | 12 ++++++------ .../kotlin/com/seiko/imageloader/Bitmap.kt | 12 ++++++++++++ .../imageloader/component/keyer/KtorUrlKeyer.kt | 5 +++-- .../com/seiko/imageloader/option/Options.kt | 16 +++++----------- .../seiko/imageloader/model/ImageRequestTest.kt | 5 +++-- 9 files changed, 33 insertions(+), 25 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 3a3b0f3f..9a05b866 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -85,7 +85,7 @@ class BitmapFactoryDecoder private constructor( /** Compute and set [BitmapFactory.Options.inPreferredConfig]. */ private fun BitmapFactory.Options.configureConfig(exifData: ExifData) { - var config = options.imageConfig.toBitmapConfig() + var config = options.bitmapConfig.toBitmapConfig() // Disable hardware bitmaps if we need to perform EXIF transformations. if (exifData.isFlipped || exifData.isRotated) { diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index c67ec4eb..d603ae59 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -40,7 +40,7 @@ class GifDecoder private constructor( val movie: Movie? = bufferedSource.use { Movie.decodeStream(it.inputStream()) } check(movie != null && movie.width() > 0 && movie.height() > 0) { "Failed to decode GIF." } - val config = options.imageConfig.toBitmapConfig() + val config = options.bitmapConfig.toBitmapConfig() val movieConfig = when { // movie.isOpaque && options.allowRgb565 -> Bitmap.Config.RGB_565 config.isHardware -> Bitmap.Config.ARGB_8888 diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 9da950f5..6394944e 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -101,7 +101,7 @@ class ImageDecoderDecoder private constructor( } private fun ImageDecoder.configureImageDecoderProperties() { - val config = options.imageConfig.toBitmapConfig() + val config = options.bitmapConfig.toBitmapConfig() allocator = if (config.isHardware) { ImageDecoder.ALLOCATOR_HARDWARE } else { diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt index 2386d312..8410c0a1 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt @@ -66,7 +66,7 @@ class ResourceUriFetcher private constructor( FetchResult.Bitmap( bitmap = DrawableUtils.convertToBitmap( drawable = drawable, - config = options.imageConfig.toBitmapConfig(), + config = options.bitmapConfig.toBitmapConfig(), scale = options.scale, allowInexactSize = options.allowInexactSize, ), diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt index 2cd383d2..7f8e09ad 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt @@ -3,7 +3,7 @@ package com.seiko.imageloader.util import android.graphics.Bitmap import android.os.Build import android.util.Log -import com.seiko.imageloader.option.Options +import com.seiko.imageloader.BitmapConfig internal val Bitmap.safeConfig: Bitmap.Config get() = config @@ -11,16 +11,16 @@ internal val Bitmap.safeConfig: Bitmap.Config internal val Bitmap.Config.isHardware: Boolean get() = Build.VERSION.SDK_INT >= 26 && this == Bitmap.Config.HARDWARE -internal fun Options.ImageConfig.toBitmapConfig(): Bitmap.Config = when (this) { - Options.ImageConfig.ALPHA_8 -> Bitmap.Config.ALPHA_8 - Options.ImageConfig.ARGB_8888 -> Bitmap.Config.ARGB_8888 - Options.ImageConfig.RGBA_F16 -> if (Build.VERSION.SDK_INT >= 26) { +internal fun BitmapConfig.toBitmapConfig(): Bitmap.Config = when (this) { + BitmapConfig.ALPHA_8 -> Bitmap.Config.ALPHA_8 + BitmapConfig.ARGB_8888 -> Bitmap.Config.ARGB_8888 + BitmapConfig.RGBA_F16 -> if (Build.VERSION.SDK_INT >= 26) { Bitmap.Config.RGBA_F16 } else { Log.w("ImageConfig", "ImageConfig.RGBA_F16 not support in android less than API 26") Bitmap.Config.ARGB_8888 } - Options.ImageConfig.HARDWARE -> if (Build.VERSION.SDK_INT >= 26) { + BitmapConfig.HARDWARE -> if (Build.VERSION.SDK_INT >= 26) { Bitmap.Config.HARDWARE } else { Log.w("ImageConfig", "ImageConfig.HARDWARE not support in android less than API 26") diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Bitmap.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Bitmap.kt index 6ed2d167..930c0b54 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Bitmap.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Bitmap.kt @@ -12,6 +12,18 @@ internal expect val Bitmap.size: Int internal expect val Bitmap.identityHashCode: Int +enum class BitmapConfig { + ALPHA_8, + ARGB_8888, + RGBA_F16, + HARDWARE, + ; + + companion object { + val Default = ARGB_8888 + } +} + expect fun Bitmap.asImageBitmap(): ImageBitmap fun Bitmap.toPainter(filterQuality: FilterQuality = DefaultFilterQuality): Painter { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/keyer/KtorUrlKeyer.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/keyer/KtorUrlKeyer.kt index 5f68ac02..5ec24718 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/keyer/KtorUrlKeyer.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/component/keyer/KtorUrlKeyer.kt @@ -1,5 +1,6 @@ package com.seiko.imageloader.component.keyer +import com.seiko.imageloader.BitmapConfig import com.seiko.imageloader.option.Options import com.seiko.imageloader.option.Scale import com.seiko.imageloader.util.DEFAULT_MAX_IMAGE_SIZE @@ -23,8 +24,8 @@ class KtorUrlKeyer : Keyer { if (!options.premultipliedAlpha) { append("-premultipliedAlpha") } - if (options.imageConfig != Options.ImageConfig.ARGB_8888) { - append("-imageConfig=${options.imageConfig}") + if (options.bitmapConfig != BitmapConfig.Default) { + append("-imageConfig=${options.bitmapConfig}") } if (options.scale != Scale.FILL) { append("-scale=fit") diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt index b48361a7..3281b9eb 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/Options.kt @@ -1,5 +1,6 @@ package com.seiko.imageloader.option +import com.seiko.imageloader.BitmapConfig import com.seiko.imageloader.Poko import com.seiko.imageloader.cache.CachePolicy import com.seiko.imageloader.model.EmptyExtraData @@ -13,7 +14,7 @@ import com.seiko.imageloader.util.DEFAULT_MAX_IMAGE_SIZE val allowInexactSize: Boolean, val premultipliedAlpha: Boolean, val retryIfDiskDecodeError: Boolean, - val imageConfig: ImageConfig, + val bitmapConfig: BitmapConfig, val scale: Scale, val sizeResolver: SizeResolver, val memoryCachePolicy: CachePolicy, @@ -27,13 +28,6 @@ import com.seiko.imageloader.util.DEFAULT_MAX_IMAGE_SIZE @Deprecated("", ReplaceWith("Options(options) {}")) fun newBuilder(block: OptionsBuilder.() -> Unit) = Options(this, block) - enum class ImageConfig { - ALPHA_8, - ARGB_8888, - RGBA_F16, - HARDWARE, - } - companion object { internal const val REPEAT_INFINITE = -1 } @@ -44,7 +38,7 @@ class OptionsBuilder internal constructor() { var allowInexactSize: Boolean = false var premultipliedAlpha: Boolean = true var retryIfDiskDecodeError: Boolean = true - var imageConfig: Options.ImageConfig = Options.ImageConfig.ARGB_8888 + var bitmapConfig: BitmapConfig = BitmapConfig.Default var scale: Scale = Scale.FILL var sizeResolver: SizeResolver = SizeResolver.Unspecified var memoryCachePolicy: CachePolicy = CachePolicy.ENABLED @@ -67,7 +61,7 @@ class OptionsBuilder internal constructor() { allowInexactSize = options.allowInexactSize premultipliedAlpha = options.premultipliedAlpha retryIfDiskDecodeError = options.retryIfDiskDecodeError - imageConfig = options.imageConfig + bitmapConfig = options.bitmapConfig scale = options.scale sizeResolver = options.sizeResolver memoryCachePolicy = options.memoryCachePolicy @@ -95,7 +89,7 @@ class OptionsBuilder internal constructor() { allowInexactSize = allowInexactSize, premultipliedAlpha = premultipliedAlpha, retryIfDiskDecodeError = retryIfDiskDecodeError, - imageConfig = imageConfig, + bitmapConfig = bitmapConfig, scale = scale, sizeResolver = sizeResolver, memoryCachePolicy = memoryCachePolicy, diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt index 3630ca49..dd81d1f1 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt @@ -2,6 +2,7 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Composable import androidx.compose.ui.geometry.Size +import com.seiko.imageloader.BitmapConfig import com.seiko.imageloader.EmptyPainter import com.seiko.imageloader.cache.CachePolicy import com.seiko.imageloader.component.decoder.Decoder @@ -37,7 +38,7 @@ class ImageRequestTest { allowInexactSize = true premultipliedAlpha = false retryIfDiskDecodeError = false - imageConfig = Options.ImageConfig.ALPHA_8 + bitmapConfig = BitmapConfig.ALPHA_8 scale = Scale.FIT sizeResolver = onePxSizeResolver memoryCachePolicy = CachePolicy.DISABLED @@ -55,7 +56,7 @@ class ImageRequestTest { assertTrue(options.allowInexactSize) assertFalse(options.premultipliedAlpha) assertFalse(options.retryIfDiskDecodeError) - assertEquals(options.imageConfig, Options.ImageConfig.ALPHA_8) + assertEquals(options.bitmapConfig, BitmapConfig.ALPHA_8) assertEquals(options.scale, Scale.FIT) assertEquals(options.sizeResolver, onePxSizeResolver) assertEquals(options.memoryCachePolicy, CachePolicy.DISABLED) From 528aa9462eacb2aea0c0c0f8cecdd3ed3e7e5d6b Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 26 Oct 2023 15:56:14 +0800 Subject: [PATCH 47/99] roborazzi to 1.7.0-rc-1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 25c619c2..4a5c5efa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ androidx-test-junit = "1.1.5" androidx-test-espresso = "3.5.1" androidx-test-uiautomator = "2.2.0" profileinstaller = "1.3.1" -roborazzi = "1.6.0" +roborazzi = "1.7.0-rc-1" robolectric = "4.10.3" poko = "0.15.0" turbine = "1.0.0" From 1f1a853cf89baf4d9ac553e18a30d728e9f3a60a Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 26 Oct 2023 15:56:36 +0800 Subject: [PATCH 48/99] set desktop test fun name --- .../com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt | 2 +- .../seiko/imageloader/screenshot/ComposeScreenShotTest.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt index 76be3329..bfde4824 100644 --- a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt +++ b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt @@ -25,7 +25,7 @@ class ChangeImageUrlTest : ChangeImageUrlCommonTest() { @OptIn(ExperimentalTestApi::class) @Test - fun test_image_change() = runDesktopComposeUiTest(width = 80, height = 80) { + fun desktop_test_image_change() = runDesktopComposeUiTest(width = 80, height = 80) { setContent { TestUI() } diff --git a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt index 33fb7854..59ba1e64 100644 --- a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt +++ b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ComposeScreenShotTest.kt @@ -23,17 +23,17 @@ class ComposeScreenShotTest : ComposeScreenShotCommonTest() { } @Test - fun test_load_image() = runMyDesktopComposeUiTest(width = 100 + 8 + 100) { + fun desktop_test_load_image() = runMyDesktopComposeUiTest(width = 100 + 8 + 100) { TestLoadImageUI() } @Test - fun test_placeholder_painter() = runMyDesktopComposeUiTest { + fun desktop_test_placeholder_painter() = runMyDesktopComposeUiTest { TestPlaceholderPainterUI() } @Test - fun test_error_painter() = runMyDesktopComposeUiTest { + fun desktop_test_error_painter() = runMyDesktopComposeUiTest { TestErrorPainterUI() } From f080963e83121cdc4836cca1f4155ef8333dd1cb Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 26 Oct 2023 16:16:00 +0800 Subject: [PATCH 49/99] roborazzi to 1.8.0-alpha-3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4a5c5efa..d758bec5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ androidx-test-junit = "1.1.5" androidx-test-espresso = "3.5.1" androidx-test-uiautomator = "2.2.0" profileinstaller = "1.3.1" -roborazzi = "1.7.0-rc-1" +roborazzi = "1.8.0-alpha-3" robolectric = "4.10.3" poko = "0.15.0" turbine = "1.0.0" From 9cd7e6327c09baded98c3ab4b2be744f296ea5a8 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 26 Oct 2023 19:57:41 +0800 Subject: [PATCH 50/99] OptIn ExperimentalRoborazziApi --- .../com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt index bfde4824..8b7958be 100644 --- a/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt +++ b/image-loader/src/desktopTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt @@ -23,7 +23,7 @@ class ChangeImageUrlTest : ChangeImageUrlCommonTest() { ) } - @OptIn(ExperimentalTestApi::class) + @OptIn(ExperimentalTestApi::class, ExperimentalRoborazziApi::class) @Test fun desktop_test_image_change() = runDesktopComposeUiTest(width = 80, height = 80) { setContent { From ccfa3842c7d00b3a4a9bb380de14bd7cdf69cb95 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 26 Oct 2023 19:58:02 +0800 Subject: [PATCH 51/99] update android capture image --- .../screenshot/ChangeImageUrlTest.kt | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt b/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt index be3a331d..0fe05652 100644 --- a/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt +++ b/image-loader/src/androidUnitTest/kotlin/com/seiko/imageloader/screenshot/ChangeImageUrlTest.kt @@ -6,12 +6,7 @@ import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.github.takahirom.roborazzi.ExperimentalRoborazziApi -import com.github.takahirom.roborazzi.InternalRoborazziApi -import com.github.takahirom.roborazzi.RoborazziContext -import com.github.takahirom.roborazzi.RoborazziOptions -import com.github.takahirom.roborazzi.captureRoboImage -import org.junit.Before +import com.github.takahirom.roborazzi.RoborazziRule import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -26,31 +21,23 @@ class ChangeImageUrlTest : ChangeImageUrlCommonTest() { @get:Rule val composeTestRule = createAndroidComposeRule() - @OptIn(ExperimentalRoborazziApi::class, InternalRoborazziApi::class) - @Before - fun initRoborazziConfig() { - RoborazziContext.setRuleOverrideOutputDirectory( - outputDirectory = "build/outputs/roborazzi/android", - ) - } + @get:Rule + val roborazziRule = RoborazziRule( + composeRule = composeTestRule, + captureRoot = composeTestRule.onRoot(), + options = RoborazziRule.Options( + captureType = RoborazziRule.CaptureType.AllImage(), + outputDirectoryPath = "build/outputs/roborazzi/android", + ), + ) @Test fun test_image_change() = with(composeTestRule) { setContent { TestUI() } - val roborazziOptions = RoborazziOptions( - captureType = RoborazziOptions.CaptureType.Screenshot(), - compareOptions = RoborazziOptions.CompareOptions(changeThreshold = 0F), - ) - onRoot().captureRoboImage( - roborazziOptions = roborazziOptions, - ) (0..2).forEach { _ -> onNodeWithTag(BUTTON_TAG).performClick() - onRoot().captureRoboImage( - roborazziOptions = roborazziOptions, - ) } } } From a0b3dddfd03c13614c87c0b0a9c40819a63c6689 Mon Sep 17 00:00:00 2001 From: seiko Date: Fri, 27 Oct 2023 11:18:43 +0800 Subject: [PATCH 52/99] run screenshot only if image-loader dir change --- .github/workflows/CompareScreenshot.yml | 2 ++ .github/workflows/StoreScreenshot.yml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/CompareScreenshot.yml b/.github/workflows/CompareScreenshot.yml index 67658d8f..4c460cdf 100644 --- a/.github/workflows/CompareScreenshot.yml +++ b/.github/workflows/CompareScreenshot.yml @@ -5,6 +5,8 @@ on: branches: - master pull_request: + paths: + - 'image-loader/**' permissions: { } diff --git a/.github/workflows/StoreScreenshot.yml b/.github/workflows/StoreScreenshot.yml index 50e3dd42..a1c08a46 100644 --- a/.github/workflows/StoreScreenshot.yml +++ b/.github/workflows/StoreScreenshot.yml @@ -5,6 +5,10 @@ on: branches: - master pull_request: + paths: + - 'image-loader/**' + +run-name: "StoreScreenshot by ${{ github.actor }}" permissions: { } From 8945ac294b938723812c2487964d52ef3a3d9b22 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Oct 2023 03:19:34 +0000 Subject: [PATCH 53/99] Update roborazzi to v1.8.0-alpha-4 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d758bec5..1253627d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ androidx-test-junit = "1.1.5" androidx-test-espresso = "3.5.1" androidx-test-uiautomator = "2.2.0" profileinstaller = "1.3.1" -roborazzi = "1.8.0-alpha-3" +roborazzi = "1.8.0-alpha-4" robolectric = "4.10.3" poko = "0.15.0" turbine = "1.0.0" From ea4427574ff13b4fddfb1ad82c050e3c1f6c5a20 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:36:26 +0000 Subject: [PATCH 54/99] Update dependency org.robolectric:robolectric to v4.11 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1253627d..775cebca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,7 @@ androidx-test-espresso = "3.5.1" androidx-test-uiautomator = "2.2.0" profileinstaller = "1.3.1" roborazzi = "1.8.0-alpha-4" -robolectric = "4.10.3" +robolectric = "4.11" poko = "0.15.0" turbine = "1.0.0" From 8ad7ac456cacfa63e84672efeac41a788fb21b19 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 30 Oct 2023 11:30:13 +0800 Subject: [PATCH 55/99] rename BitmapConfig.toBitmapConfig to toAndroidConfig --- .../imageloader/component/decoder/BitmapFactoryDecoder.kt | 4 ++-- .../com/seiko/imageloader/component/decoder/GifDecoder.kt | 4 ++-- .../imageloader/component/decoder/ImageDecoderDecoder.kt | 4 ++-- .../seiko/imageloader/component/fetcher/ResourceUriFetcher.kt | 4 ++-- .../androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index efd377ba..683a4d61 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -14,7 +14,7 @@ import com.seiko.imageloader.util.calculateInSampleSize import com.seiko.imageloader.util.computeSizeMultiplier import com.seiko.imageloader.util.isRotated import com.seiko.imageloader.util.isSwapped -import com.seiko.imageloader.util.toBitmapConfig +import com.seiko.imageloader.util.toAndroidConfig import com.seiko.imageloader.util.toSoftware import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.sync.Semaphore @@ -85,7 +85,7 @@ class BitmapFactoryDecoder private constructor( /** Compute and set [BitmapFactory.Options.inPreferredConfig]. */ private fun BitmapFactory.Options.configureConfig(exifData: ExifData) { - var config = options.bitmapConfig.toBitmapConfig() + var config = options.bitmapConfig.toAndroidConfig() // Disable hardware bitmaps if we need to perform EXIF transformations. if (exifData.isFlipped || exifData.isRotated) { diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt index 7839618e..27354775 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/GifDecoder.kt @@ -10,7 +10,7 @@ import com.seiko.imageloader.util.FrameDelayRewritingSource import com.seiko.imageloader.util.MovieDrawable import com.seiko.imageloader.util.isGif import com.seiko.imageloader.util.isHardware -import com.seiko.imageloader.util.toBitmapConfig +import com.seiko.imageloader.util.toAndroidConfig import kotlinx.coroutines.runInterruptible import okio.BufferedSource import okio.buffer @@ -40,7 +40,7 @@ class GifDecoder private constructor( val movie: Movie? = bufferedSource.use { Movie.decodeStream(it.inputStream()) } check(movie != null && movie.width() > 0 && movie.height() > 0) { "Failed to decode GIF." } - val config = options.bitmapConfig.toBitmapConfig() + val config = options.bitmapConfig.toAndroidConfig() val movieConfig = when { // movie.isOpaque && options.allowRgb565 -> Bitmap.Config.RGB_565 config.isHardware -> Bitmap.Config.ARGB_8888 diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt index 7c0d426b..4bc6c91d 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/ImageDecoderDecoder.kt @@ -21,7 +21,7 @@ import com.seiko.imageloader.util.isAnimatedHeif import com.seiko.imageloader.util.isAnimatedWebP import com.seiko.imageloader.util.isGif import com.seiko.imageloader.util.isHardware -import com.seiko.imageloader.util.toBitmapConfig +import com.seiko.imageloader.util.toAndroidConfig import kotlinx.coroutines.runInterruptible import okio.BufferedSource import okio.FileSystem @@ -101,7 +101,7 @@ class ImageDecoderDecoder private constructor( } private fun ImageDecoder.configureImageDecoderProperties() { - val config = options.bitmapConfig.toBitmapConfig() + val config = options.bitmapConfig.toAndroidConfig() allocator = if (config.isHardware) { ImageDecoder.ALLOCATOR_HARDWARE } else { diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt index 945f077e..34f9bd5c 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/fetcher/ResourceUriFetcher.kt @@ -26,7 +26,7 @@ import com.seiko.imageloader.option.androidContext import com.seiko.imageloader.toImage import com.seiko.imageloader.util.DrawableUtils import com.seiko.imageloader.util.getMimeTypeFromUrl -import com.seiko.imageloader.util.toBitmapConfig +import com.seiko.imageloader.util.toAndroidConfig import okio.buffer import okio.source import org.xmlpull.v1.XmlPullParser @@ -66,7 +66,7 @@ class ResourceUriFetcher private constructor( FetchResult.OfBitmap( bitmap = DrawableUtils.convertToBitmap( drawable = drawable, - config = options.bitmapConfig.toBitmapConfig(), + config = options.bitmapConfig.toAndroidConfig(), scale = options.scale, allowInexactSize = options.allowInexactSize, ), diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt index 7f8e09ad..ef0bc2fb 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/util/Bitmap.kt @@ -11,7 +11,7 @@ internal val Bitmap.safeConfig: Bitmap.Config internal val Bitmap.Config.isHardware: Boolean get() = Build.VERSION.SDK_INT >= 26 && this == Bitmap.Config.HARDWARE -internal fun BitmapConfig.toBitmapConfig(): Bitmap.Config = when (this) { +internal fun BitmapConfig.toAndroidConfig(): Bitmap.Config = when (this) { BitmapConfig.ALPHA_8 -> Bitmap.Config.ALPHA_8 BitmapConfig.ARGB_8888 -> Bitmap.Config.ARGB_8888 BitmapConfig.RGBA_F16 -> if (Build.VERSION.SDK_INT >= 26) { From dfaf9edf46651a9f413bd600fa46eb427a1a3351 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 30 Oct 2023 15:49:10 +0800 Subject: [PATCH 56/99] add create prefix for ImageLoader.Default --- .../main/java/com/seiko/imageloader/demo/MainActivity.kt | 4 ++-- .../commonMain/kotlin/com/seiko/imageloader/demo/Main.kt | 4 ++-- .../singleton/com/seiko/imageloader/ImageLoaderFactory.kt | 2 +- .../com/seiko/imageloader/LocalImageLoader.android.kt | 3 +-- .../com/seiko/imageloader/LocalImageLoader.apple.kt | 7 ++++--- .../singleton/com/seiko/imageloader/LocalImageLoader.kt | 5 +++-- .../com/seiko/imageloader/LocalImageLoader.desktop.kt | 2 +- .../singleton/com/seiko/imageloader/LocalImageLoader.js.kt | 2 +- 8 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/android/src/main/java/com/seiko/imageloader/demo/MainActivity.kt b/app/android/src/main/java/com/seiko/imageloader/demo/MainActivity.kt index 0a9bf110..a30ec844 100644 --- a/app/android/src/main/java/com/seiko/imageloader/demo/MainActivity.kt +++ b/app/android/src/main/java/com/seiko/imageloader/demo/MainActivity.kt @@ -5,9 +5,9 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember -import com.seiko.imageloader.DefaultAndroid import com.seiko.imageloader.ImageLoader import com.seiko.imageloader.LocalImageLoader +import com.seiko.imageloader.createDefaultAndroid import com.seiko.imageloader.demo.util.commonConfig class MainActivity : ComponentActivity() { @@ -24,7 +24,7 @@ class MainActivity : ComponentActivity() { private fun generateImageLoader(): ImageLoader { return ImageLoader { - takeFrom(ImageLoader.DefaultAndroid(applicationContext)) + takeFrom(ImageLoader.createDefaultAndroid(applicationContext)) commonConfig() } // return ImageLoader { diff --git a/app/ios-combine/src/commonMain/kotlin/com/seiko/imageloader/demo/Main.kt b/app/ios-combine/src/commonMain/kotlin/com/seiko/imageloader/demo/Main.kt index dcf4ff98..b34c8cf7 100644 --- a/app/ios-combine/src/commonMain/kotlin/com/seiko/imageloader/demo/Main.kt +++ b/app/ios-combine/src/commonMain/kotlin/com/seiko/imageloader/demo/Main.kt @@ -3,9 +3,9 @@ package com.seiko.imageloader.demo import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.window.ComposeUIViewController -import com.seiko.imageloader.DefaultIOS import com.seiko.imageloader.ImageLoader import com.seiko.imageloader.LocalImageLoader +import com.seiko.imageloader.createDefaultIOS import com.seiko.imageloader.demo.util.commonConfig import platform.UIKit.UIViewController @@ -20,7 +20,7 @@ fun MainViewController(): UIViewController = ComposeUIViewController { private fun generateImageLoader(): ImageLoader { return ImageLoader { - takeFrom(ImageLoader.DefaultIOS) + takeFrom(ImageLoader.createDefaultIOS()) commonConfig() } // return ImageLoader { diff --git a/image-loader/src/androidMain/singleton/com/seiko/imageloader/ImageLoaderFactory.kt b/image-loader/src/androidMain/singleton/com/seiko/imageloader/ImageLoaderFactory.kt index 8ee4501c..9e925390 100644 --- a/image-loader/src/androidMain/singleton/com/seiko/imageloader/ImageLoaderFactory.kt +++ b/image-loader/src/androidMain/singleton/com/seiko/imageloader/ImageLoaderFactory.kt @@ -22,5 +22,5 @@ val Context.imageLoader: ImageLoader private fun Context.newImageLoader(): ImageLoader { currentImageLoader?.let { return it } return (applicationContext as? ImageLoaderFactory)?.newImageLoader() - ?: ImageLoader.DefaultAndroid(this) + ?: ImageLoader.createDefaultAndroid(this) } diff --git a/image-loader/src/androidMain/singleton/com/seiko/imageloader/LocalImageLoader.android.kt b/image-loader/src/androidMain/singleton/com/seiko/imageloader/LocalImageLoader.android.kt index e31f8a62..8d011593 100644 --- a/image-loader/src/androidMain/singleton/com/seiko/imageloader/LocalImageLoader.android.kt +++ b/image-loader/src/androidMain/singleton/com/seiko/imageloader/LocalImageLoader.android.kt @@ -29,8 +29,7 @@ actual fun createImageLoaderProvidableCompositionLocal() = ImageLoaderProvidable delegate = staticCompositionLocalOf { null }, ) -@Suppress("FunctionName") -fun ImageLoader.Companion.DefaultAndroid(context: Context): ImageLoader { +fun ImageLoader.Companion.createDefaultAndroid(context: Context): ImageLoader { return ImageLoader { options { androidContext(context.applicationContext) diff --git a/image-loader/src/appleMain/singleton/com/seiko/imageloader/LocalImageLoader.apple.kt b/image-loader/src/appleMain/singleton/com/seiko/imageloader/LocalImageLoader.apple.kt index c32b70df..a550da4c 100644 --- a/image-loader/src/appleMain/singleton/com/seiko/imageloader/LocalImageLoader.apple.kt +++ b/image-loader/src/appleMain/singleton/com/seiko/imageloader/LocalImageLoader.apple.kt @@ -9,12 +9,12 @@ import platform.Foundation.NSUserDomainMask actual fun createImageLoaderProvidableCompositionLocal() = ImageLoaderProvidableCompositionLocal( delegate = staticCompositionLocalOf { - ImageLoader.DefaultIOS + ImageLoader.createDefaultIOS() }, ) -val ImageLoader.Companion.DefaultIOS: ImageLoader - get() = ImageLoader { +fun ImageLoader.Companion.createDefaultIOS(): ImageLoader { + return ImageLoader { components { setupDefaultComponents() } @@ -29,6 +29,7 @@ val ImageLoader.Companion.DefaultIOS: ImageLoader } } } +} private fun getCacheDir(): String { return NSSearchPathForDirectoriesInDomains( diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 39d446ab..0110f578 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -21,8 +21,8 @@ expect class ImageLoaderProvidableCompositionLocal { expect fun createImageLoaderProvidableCompositionLocal(): ImageLoaderProvidableCompositionLocal -val ImageLoader.Companion.Default: ImageLoader - get() = ImageLoader { +fun ImageLoader.Companion.createDefault(): ImageLoader { + return ImageLoader { components { setupDefaultComponents() } @@ -33,6 +33,7 @@ val ImageLoader.Companion.Default: ImageLoader } } } +} // cache 100 image result, without bitmap fun InterceptorsBuilder.defaultImageResultMemoryCache( diff --git a/image-loader/src/desktopMain/singleton/com/seiko/imageloader/LocalImageLoader.desktop.kt b/image-loader/src/desktopMain/singleton/com/seiko/imageloader/LocalImageLoader.desktop.kt index 1f1635ce..20942199 100644 --- a/image-loader/src/desktopMain/singleton/com/seiko/imageloader/LocalImageLoader.desktop.kt +++ b/image-loader/src/desktopMain/singleton/com/seiko/imageloader/LocalImageLoader.desktop.kt @@ -5,6 +5,6 @@ import androidx.compose.runtime.staticCompositionLocalOf actual fun createImageLoaderProvidableCompositionLocal() = ImageLoaderProvidableCompositionLocal( delegate = staticCompositionLocalOf { // no disk cache in desktop - ImageLoader.Default + ImageLoader.createDefault() }, ) diff --git a/image-loader/src/jsMain/singleton/com/seiko/imageloader/LocalImageLoader.js.kt b/image-loader/src/jsMain/singleton/com/seiko/imageloader/LocalImageLoader.js.kt index 51414222..53f4d3b6 100644 --- a/image-loader/src/jsMain/singleton/com/seiko/imageloader/LocalImageLoader.js.kt +++ b/image-loader/src/jsMain/singleton/com/seiko/imageloader/LocalImageLoader.js.kt @@ -5,6 +5,6 @@ import androidx.compose.runtime.staticCompositionLocalOf actual fun createImageLoaderProvidableCompositionLocal() = ImageLoaderProvidableCompositionLocal( delegate = staticCompositionLocalOf { // no disk cache in js - ImageLoader.Default + ImageLoader.createDefault() }, ) From cd12082c002a7e98b7ba2279273a14b24e29f116 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 30 Oct 2023 20:31:31 +0800 Subject: [PATCH 57/99] update source set --- app/common/build.gradle.kts | 13 ++++++------- app/macos/build.gradle.kts | 9 +-------- app/web/build.gradle.kts | 7 +++---- extension/blur/build.gradle.kts | 3 +-- image-loader/build.gradle.kts | 33 ++++++++++++++++----------------- 5 files changed, 27 insertions(+), 38 deletions(-) diff --git a/app/common/build.gradle.kts b/app/common/build.gradle.kts index 5f86fd30..7a4ca1e8 100644 --- a/app/common/build.gradle.kts +++ b/app/common/build.gradle.kts @@ -7,9 +7,8 @@ plugins { } kotlin { - @Suppress("UNUSED_VARIABLE") sourceSets { - val commonMain by getting { + commonMain { dependencies { api(compose.runtime) api(compose.foundation) @@ -27,24 +26,24 @@ kotlin { implementation(libs.kermit) } } - val androidMain by getting { + androidMain { // https://github.com/icerockdev/moko-resources/issues/531 - dependsOn(commonMain) + dependsOn(commonMain.get()) dependencies { implementation(libs.ktor.client.cio) } } - val desktopMain by getting { + desktopMain { dependencies { implementation(libs.ktor.client.cio) } } - val appleMain by getting { + appleMain { dependencies { implementation(libs.ktor.client.darwin) } } - val jsMain by getting { + jsMain { dependencies { implementation(libs.ktor.client.js) } diff --git a/app/macos/build.gradle.kts b/app/macos/build.gradle.kts index 12078f61..926b8c7b 100644 --- a/app/macos/build.gradle.kts +++ b/app/macos/build.gradle.kts @@ -30,19 +30,12 @@ kotlin { } } } - @Suppress("UNUSED_VARIABLE") sourceSets { - val macosMain by creating { + commonMain { dependencies { implementation(projects.app.common) } } - val macosX64Main by getting { - dependsOn(macosMain) - } - val macosArm64Main by getting { - dependsOn(macosMain) - } } } diff --git a/app/web/build.gradle.kts b/app/web/build.gradle.kts index 2279788f..0f48a320 100644 --- a/app/web/build.gradle.kts +++ b/app/web/build.gradle.kts @@ -9,9 +9,8 @@ kotlin { browser() binaries.executable() } - @Suppress("UNUSED_VARIABLE") sourceSets { - val commonMain by getting { + commonMain { dependencies { implementation(projects.app.common) implementation(compose.runtime) @@ -19,9 +18,9 @@ kotlin { implementation(libs.moko.resources) } } - val jsMain by getting { + getByName("jsMain") { // https://github.com/icerockdev/moko-resources/issues/531 - dependsOn(commonMain) + dependsOn(commonMain.get()) } } } diff --git a/extension/blur/build.gradle.kts b/extension/blur/build.gradle.kts index 93b64e36..fcd92450 100644 --- a/extension/blur/build.gradle.kts +++ b/extension/blur/build.gradle.kts @@ -12,8 +12,7 @@ kotlin { implementation(projects.imageLoader) } } - @Suppress("UNUSED_VARIABLE") - val androidMain by getting { + androidMain { dependencies { implementation("com.github.android:renderscript-intrinsics-replacement-toolkit:9a70eae6f1") } diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 96d2ab20..647c0c47 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -12,9 +12,8 @@ plugins { } kotlin { - @Suppress("UNUSED_VARIABLE") sourceSets { - val commonMain by getting { + commonMain { dependencies { api(compose.ui) api(libs.kotlinx.coroutines.core) @@ -23,7 +22,7 @@ kotlin { api(libs.uri.kmp) } } - val commonTest by getting { + commonTest { dependencies { implementation(kotlin("test")) implementation(libs.bundles.test.common) @@ -31,12 +30,12 @@ kotlin { implementation(compose.ui) } } - val jvmMain by getting { + jvmMain { dependencies { implementation(libs.ktor.client.okhttp) } } - val androidMain by getting { + androidMain { dependencies { implementation(libs.kotlinx.coroutines.android) implementation(libs.androidx.core.ktx) @@ -45,18 +44,18 @@ kotlin { implementation(libs.androidsvg) } } - val androidUnitTest by getting { + androidUnitTest { dependencies { implementation(compose.desktop.uiTestJUnit4) implementation(libs.bundles.test.android) } } - val desktopMain by getting { + desktopMain { dependencies { implementation(libs.kotlinx.coroutines.swing) } } - val desktopTest by getting { + desktopTest { languageSettings { enableLanguageFeature(LanguageFeature.ContextReceivers.name) } @@ -69,29 +68,29 @@ kotlin { } } } - val appleMain by getting { + appleMain { dependencies { implementation(libs.ktor.client.darwin) } } - val jsMain by getting { + jsMain { dependencies { implementation(libs.ktor.client.js) } } val noJsMain by creating { - dependsOn(commonMain) - jvmMain.dependsOn(this) - appleMain.dependsOn(this) + dependsOn(commonMain.get()) + jvmMain.get().dependsOn(this) + appleMain.get().dependsOn(this) dependencies { implementation(libs.androidx.collection) } } val noAndroidMain by creating { - dependsOn(commonMain) - desktopMain.dependsOn(this) - appleMain.dependsOn(this) - jsMain.dependsOn(this) + dependsOn(commonMain.get()) + desktopMain.get().dependsOn(this) + appleMain.get().dependsOn(this) + jsMain.get().dependsOn(this) } } sourceSets.all { From f3589992729df2c34af9421033e1c4496e423de3 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 30 Oct 2023 20:31:57 +0800 Subject: [PATCH 58/99] optIn ExperimentalNativeApi --- image-loader/build.gradle.kts | 5 +++++ .../kotlin/com/seiko/imageloader/util/Platform.apple.kt | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 647c0c47..787420bf 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -13,6 +13,11 @@ plugins { kotlin { sourceSets { + all { + languageSettings { + optIn("kotlin.experimental.ExperimentalNativeApi") + } + } commonMain { dependencies { api(compose.ui) diff --git a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt index 7c5af2a6..51ff888d 100644 --- a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt +++ b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt @@ -3,9 +3,7 @@ package com.seiko.imageloader.util import io.ktor.client.engine.HttpClientEngine import io.ktor.client.engine.darwin.Darwin import okio.FileSystem -import kotlin.experimental.ExperimentalNativeApi -@OptIn(ExperimentalNativeApi::class) actual typealias WeakReference = kotlin.native.ref.WeakReference internal actual val httpEngine: HttpClientEngine get() = Darwin.create() From 4e4ca0d8c3fdb24added2dca4f97a19441db740b Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 30 Oct 2023 20:32:17 +0800 Subject: [PATCH 59/99] set app.benchmark minSdk to 23 --- app/android/benchmark/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/android/benchmark/build.gradle.kts b/app/android/benchmark/build.gradle.kts index 1aa7bc09..cdd23fc4 100644 --- a/app/android/benchmark/build.gradle.kts +++ b/app/android/benchmark/build.gradle.kts @@ -9,6 +9,7 @@ plugins { android { namespace = "com.seiko.imageloader.demo.benchmark" defaultConfig { + minSdk = 23 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" // TODO temporary until AGP 8.2, which no longer requires this. From 26ed2a159ae949a46c52c34034cf6fd76db690a6 Mon Sep 17 00:00:00 2001 From: seiko Date: Mon, 30 Oct 2023 20:34:29 +0800 Subject: [PATCH 60/99] update screenshot ci paths --- .github/workflows/CompareScreenshot.yml | 2 +- .github/workflows/StoreScreenshot.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CompareScreenshot.yml b/.github/workflows/CompareScreenshot.yml index 4c460cdf..52e0949b 100644 --- a/.github/workflows/CompareScreenshot.yml +++ b/.github/workflows/CompareScreenshot.yml @@ -6,7 +6,7 @@ on: - master pull_request: paths: - - 'image-loader/**' + - 'image-loader/src/**' permissions: { } diff --git a/.github/workflows/StoreScreenshot.yml b/.github/workflows/StoreScreenshot.yml index a1c08a46..88ca8f15 100644 --- a/.github/workflows/StoreScreenshot.yml +++ b/.github/workflows/StoreScreenshot.yml @@ -6,7 +6,7 @@ on: - master pull_request: paths: - - 'image-loader/**' + - 'image-loader/src/**' run-name: "StoreScreenshot by ${{ github.actor }}" From d5359cff08c0e5019ce9da1550221d56c77b8b42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:31:26 +0000 Subject: [PATCH 61/99] Update dependency org.jetbrains.compose to v1.5.10 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 775cebca..c8495412 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agp = "8.1.2" -compose-multiplatform = "1.5.3" +compose-multiplatform = "1.5.10" kotlin = "1.9.10" kotlinx-coroutines = "1.7.3" kotlinx-serialization = "1.6.0" From 389e7d29efe6f43239de39e87d0f9028962a08a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:01:22 +0000 Subject: [PATCH 62/99] Update dependency org.robolectric:robolectric to v4.11.1 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 775cebca..79b33b4e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,7 @@ androidx-test-espresso = "3.5.1" androidx-test-uiautomator = "2.2.0" profileinstaller = "1.3.1" roborazzi = "1.8.0-alpha-4" -robolectric = "4.11" +robolectric = "4.11.1" poko = "0.15.0" turbine = "1.0.0" From 9303134b845b16a90675d709775e9e8369d62f3c Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 12:11:51 +0800 Subject: [PATCH 63/99] ignore unspecified size --- .../imageloader/component/decoder/BitmapFactoryDecoder.kt | 3 ++- .../seiko/imageloader/component/decoder/SkiaImageDecoder.kt | 3 ++- .../com/seiko/imageloader/component/decoder/SvgDecoder.kt | 5 +---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 43117e56..1e182e41 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.os.Build.VERSION.SDK_INT +import androidx.compose.ui.geometry.isSpecified import com.seiko.imageloader.option.Options import com.seiko.imageloader.option.androidContext import com.seiko.imageloader.util.DEFAULT_MAX_PARALLELISM @@ -118,7 +119,7 @@ class BitmapFactoryDecoder private constructor( // EXIF transformations (but before sampling). val srcWidth = if (exifData.isSwapped) outHeight else outWidth val srcHeight = if (exifData.isSwapped) outWidth else outHeight - val (dstWidth, dstHeight) = if (!options.size.isEmpty()) { + val (dstWidth, dstHeight) = if (options.size.isSpecified && !options.size.isEmpty()) { options.size.run { width.toInt() to height.toInt() } } else { calculateDstSize(srcWidth, srcHeight, options.maxImageSize) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index a74012d3..a2a8a43f 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -1,5 +1,6 @@ package com.seiko.imageloader.component.decoder +import androidx.compose.ui.geometry.isSpecified import com.seiko.imageloader.option.Options import com.seiko.imageloader.util.DEFAULT_MAX_PARALLELISM import com.seiko.imageloader.util.calculateDstSize @@ -32,7 +33,7 @@ class SkiaImageDecoder private constructor( // TODO wait to fix high probability crash on ios private fun Image.toBitmap(): Bitmap { val bitmap = Bitmap() - val (dstWidth, dstHeight) = if (!options.size.isEmpty()) { + val (dstWidth, dstHeight) = if (options.size.isSpecified && !options.size.isEmpty()) { options.size.run { width.toInt() to height.toInt() } } else { calculateDstSize(width, height, options.maxImageSize) diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index 94c66b9d..7124e316 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -20,11 +20,8 @@ class SvgDecoder private constructor( val data = source.use { Data.makeFromBytes(it.readByteArray()) } - val requestSize = options.sizeResolver.run { - density.size() - } return DecodeResult.OfPainter( - painter = SVGPainter(SVGDOM(data), density, requestSize), + painter = SVGPainter(SVGDOM(data), density, options.size), ) } From a931291c1e568fbc6d30390c02369897b4910063 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 12:12:41 +0800 Subject: [PATCH 64/99] fix android SvgDecoder size --- .../com/seiko/imageloader/component/decoder/SvgDecoder.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt index a2a54697..1a94751e 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/SvgDecoder.kt @@ -20,11 +20,8 @@ class SvgDecoder private constructor( override suspend fun decode(): DecodeResult { val svg = SVG.getFromInputStream(source.source.inputStream()) - val requestSize = options.sizeResolver.run { - density.size() - } return DecodeResult.OfPainter( - painter = SVGPainter(svg, density, requestSize), + painter = SVGPainter(svg, density, options.size), ) } From e8810fc88baa53596819fa2ff539162eef6ba700 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 12:40:03 +0800 Subject: [PATCH 65/99] prefect SizeResolver compare --- .../seiko/imageloader/option/SizeResolver.kt | 22 ++++++++++--- .../imageloader/option/SizeResolverTest.kt | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 image-loader/src/commonTest/kotlin/com/seiko/imageloader/option/SizeResolverTest.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt index adc0db66..24440456 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/option/SizeResolver.kt @@ -7,10 +7,14 @@ interface SizeResolver { suspend fun size(): Size companion object { - val Unspecified = SizeResolver(Size.Unspecified) + val Unspecified: SizeResolver = RealSizeResolver(Size.Unspecified) } } +fun SizeResolver(block: suspend () -> Size) = object : SizeResolver { + override suspend fun size(): Size = block() +} + class AsyncSizeResolver : SizeResolver { private val sizeObserver = CompletableDeferred() @@ -24,10 +28,18 @@ class AsyncSizeResolver : SizeResolver { } } -fun SizeResolver(block: suspend () -> Size) = object : SizeResolver { - override suspend fun size(): Size = block() -} +fun SizeResolver(size: Size): SizeResolver = RealSizeResolver(size) -fun SizeResolver(size: Size): SizeResolver = object : SizeResolver { +private class RealSizeResolver(private val size: Size) : SizeResolver { override suspend fun size(): Size = size + + override fun equals(other: Any?): Boolean { + return other is RealSizeResolver && size == other.size + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + size.hashCode() + return result + } } diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/option/SizeResolverTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/option/SizeResolverTest.kt new file mode 100644 index 00000000..020a96db --- /dev/null +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/option/SizeResolverTest.kt @@ -0,0 +1,31 @@ +package com.seiko.imageloader.option + +import androidx.compose.ui.geometry.Size +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class SizeResolverTest { + + @Test + fun compare_test() { + assertEquals( + SizeResolver(Size(10f, 10f)), + SizeResolver(Size(10.0f, 10.0f)), + ) + assertEquals( + SizeResolver(Size.Unspecified), + SizeResolver.Unspecified, + ) + } + + @Test + fun async_size_test() = runTest { + val sizeResolver = AsyncSizeResolver() + launch { + sizeResolver.setSize(Size(10f, 10f)) + } + assertEquals(Size(10f, 10f), sizeResolver.size()) + } +} From 24f446b87c15b71c54ff2baac3d27336d277c57a Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 12:43:53 +0800 Subject: [PATCH 66/99] prefect ImageRequest compare --- .../seiko/imageloader/model/ImageRequest.kt | 2 ++ .../imageloader/model/ImageRequestTest.kt | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index c88a12d0..ec75f3b6 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -3,6 +3,7 @@ package com.seiko.imageloader.model import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.painter.Painter +import com.seiko.imageloader.Poko import com.seiko.imageloader.component.ComponentRegistry import com.seiko.imageloader.component.ComponentRegistryBuilder import com.seiko.imageloader.intercept.Interceptor @@ -11,6 +12,7 @@ import com.seiko.imageloader.option.Scale import com.seiko.imageloader.option.SizeResolver @Immutable +@Poko class ImageRequest internal constructor( val data: Any, val extra: ExtraData, diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt index 93822839..80a952ec 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt @@ -14,6 +14,7 @@ import com.seiko.imageloader.option.takeFrom import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNotEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -97,4 +98,22 @@ class ImageRequestTest { assertEquals(request.components.fetcherFactories.first(), fetcherFactory) assertEquals(request.components.decoderFactories.first(), decoderFactory) } + + @Test + fun image_request_compare_test() { + val request1 = ImageRequest { + data("aa") + skipEvent = true + } + assertNotEquals(request1, ImageRequest("aa")) + assertEquals(request1, ImageRequest("aa") { skipEvent = true }) + val request2 = ImageRequest { + data("aa") + extra { + put("a", "b") + } + } + assertNotEquals(request2, ImageRequest("aa")) + assertEquals(request2, ImageRequest("aa") { extra { put("a", "b") } }) + } } From ddc408fce72ed286b0b8a2fc3d55272112358b06 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 13:59:18 +0800 Subject: [PATCH 67/99] fix skia GifPainter repeatCount --- .../kotlin/com/seiko/imageloader/Remember.kt | 4 ++-- .../seiko/imageloader/util/AnimationPainter.kt | 2 ++ .../com/seiko/imageloader/util/GifPainter.kt | 18 ++++++++++++------ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt index 279af95a..81b7c1d3 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt @@ -86,9 +86,9 @@ fun rememberImageResultPainter( is ImageResult.OfSource, -> errorPainter?.invoke() ?: EmptyPainter }.also { painter -> - if (painter is AnimationPainter) { + if (painter is AnimationPainter && painter.isPlay()) { LaunchedEffect(painter) { - while (painter.isPlay()) { + while (painter.nextPlay()) { withFrameMillis { frameTimeMillis -> painter.update(frameTimeMillis) } diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/AnimationPainter.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/AnimationPainter.kt index 4a96623f..24bb3de1 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/AnimationPainter.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/AnimationPainter.kt @@ -4,5 +4,7 @@ interface AnimationPainter { fun isPlay(): Boolean + fun nextPlay(): Boolean + fun update(frameTimeMillis: Long) } diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/util/GifPainter.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/util/GifPainter.kt index 6a5aedbf..4d0117fd 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/util/GifPainter.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/util/GifPainter.kt @@ -21,7 +21,7 @@ internal class GifPainter( private val durations = codec.framesInfo.map { it.duration } private val totalDuration = durations.sum() - private var startTime = -1L + private var startTimeMillis = -1L private var frame by mutableStateOf(0) private var loopIteration = -1 @@ -52,14 +52,20 @@ internal class GifPainter( } override fun isPlay(): Boolean { - return totalDuration > 0 && (repeatCount == Options.REPEAT_INFINITE || loopIteration++ < repeatCount) + return totalDuration > 0 && (repeatCount == Options.REPEAT_INFINITE || repeatCount > 0) + } + + override fun nextPlay(): Boolean { + return totalDuration > 0 && (repeatCount == Options.REPEAT_INFINITE || loopIteration < repeatCount) } override fun update(frameTimeMillis: Long) { - if (startTime == -1L) { - startTime = frameTimeMillis + if (startTimeMillis == -1L) { + startTimeMillis = frameTimeMillis } - frame = frameOf(time = (frameTimeMillis - startTime) % totalDuration) + val playTimeMillis = frameTimeMillis - startTimeMillis + frame = frameOf(time = playTimeMillis % totalDuration) + loopIteration = (playTimeMillis / totalDuration).toInt() } // WARNING: it is not optimal @@ -87,7 +93,7 @@ internal class GifPainter( } private fun clear() { - startTime = -1 + startTimeMillis = -1 frame = 0 loopIteration = -1 bitmapCache?.close() From ef266110166c5a01992f56b9462156d989383d83 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 15:38:31 +0800 Subject: [PATCH 68/99] fix calculateDstSize --- .../kotlin/com/seiko/imageloader/util/CalculateSIze.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/CalculateSIze.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/CalculateSIze.kt index da7ea968..962ba7f5 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/CalculateSIze.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/util/CalculateSIze.kt @@ -19,7 +19,7 @@ internal fun calculateDstSize( dstHeight = ((maxImageSize.toFloat() / srcWidth.toFloat()) * dstHeight).toInt() dstWidth = maxImageSize } else { - dstWidth = ((maxImageSize.toFloat() / srcWidth.toFloat()) * dstWidth).toInt() + dstWidth = ((maxImageSize.toFloat() / srcHeight.toFloat()) * dstWidth).toInt() dstHeight = maxImageSize } } From 8a5996e45b8f59557a3b6b9e9c2d3afe220ddc0f Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 15:51:03 +0800 Subject: [PATCH 69/99] update calc of bitmap dstSize --- .../component/decoder/BitmapFactoryDecoder.kt | 10 +++++++--- .../component/decoder/SkiaImageDecoder.kt | 19 +++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt index 1e182e41..f482fea6 100644 --- a/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt +++ b/image-loader/src/androidMain/kotlin/com/seiko/imageloader/component/decoder/BitmapFactoryDecoder.kt @@ -119,11 +119,15 @@ class BitmapFactoryDecoder private constructor( // EXIF transformations (but before sampling). val srcWidth = if (exifData.isSwapped) outHeight else outWidth val srcHeight = if (exifData.isSwapped) outWidth else outHeight - val (dstWidth, dstHeight) = if (options.size.isSpecified && !options.size.isEmpty()) { - options.size.run { width.toInt() to height.toInt() } + + val maxImageSize = if (options.size.isSpecified && !options.size.isEmpty()) { + minOf(options.size.width, options.size.height).toInt() + .coerceAtMost(options.maxImageSize) } else { - calculateDstSize(srcWidth, srcHeight, options.maxImageSize) + options.maxImageSize } + val (dstWidth, dstHeight) = calculateDstSize(srcWidth, srcHeight, maxImageSize) + // Calculate the image's sample size. inSampleSize = calculateInSampleSize( srcWidth = srcWidth, diff --git a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt index a2a8a43f..6f314828 100644 --- a/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt +++ b/image-loader/src/skiaMain/kotlin/com/seiko/imageloader/component/decoder/SkiaImageDecoder.kt @@ -12,7 +12,6 @@ import org.jetbrains.skia.Bitmap import org.jetbrains.skia.Canvas import org.jetbrains.skia.Image import org.jetbrains.skia.Rect -import org.jetbrains.skia.SamplingMode import org.jetbrains.skia.impl.use class SkiaImageDecoder private constructor( @@ -33,20 +32,24 @@ class SkiaImageDecoder private constructor( // TODO wait to fix high probability crash on ios private fun Image.toBitmap(): Bitmap { val bitmap = Bitmap() - val (dstWidth, dstHeight) = if (options.size.isSpecified && !options.size.isEmpty()) { - options.size.run { width.toInt() to height.toInt() } + + val srcWidth = width + val srcHeight = height + + val maxImageSize = if (options.size.isSpecified && !options.size.isEmpty()) { + minOf(options.size.width, options.size.height).toInt() + .coerceAtMost(options.maxImageSize) } else { - calculateDstSize(width, height, options.maxImageSize) + options.maxImageSize } + val (dstWidth, dstHeight) = calculateDstSize(srcWidth, srcHeight, maxImageSize) + bitmap.allocN32Pixels(dstWidth, dstHeight) Canvas(bitmap).use { canvas -> canvas.drawImageRect( this, - Rect.makeWH(width.toFloat(), height.toFloat()), + Rect.makeWH(srcWidth.toFloat(), srcHeight.toFloat()), Rect.makeWH(dstWidth.toFloat(), dstHeight.toFloat()), - SamplingMode.DEFAULT, - null, - true, ) } bitmap.setImmutable() From 3ff5faa50253682e844d6d13283c1e684d0dd9b9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:05:48 +0000 Subject: [PATCH 70/99] Update kotlin to v1.9.20 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0edbb677..e1216a3a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agp = "8.1.2" compose-multiplatform = "1.5.10" -kotlin = "1.9.10" +kotlin = "1.9.20" kotlinx-coroutines = "1.7.3" kotlinx-serialization = "1.6.0" androidx-core-ktx = "1.12.0" From 7e084a53daed93dba4853f32a7fb5efda2bcebe9 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 17:45:18 +0800 Subject: [PATCH 71/99] fix ImageRequest no primary constructor on js target --- .../seiko/imageloader/model/ImageRequest.kt | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index ec75f3b6..4eabc477 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -12,7 +12,6 @@ import com.seiko.imageloader.option.Scale import com.seiko.imageloader.option.SizeResolver @Immutable -@Poko class ImageRequest internal constructor( val data: Any, val extra: ExtraData, @@ -26,6 +25,32 @@ class ImageRequest internal constructor( ) { @Deprecated("", ReplaceWith("ImageRequest(request) {}")) fun newBuilder(block: ImageRequestBuilder.() -> Unit) = ImageRequest(this, block) + + override fun equals(other: Any?): Boolean { + return other is ImageRequest && + data == other.data && + extra == other.extra && + sizeResolver == other.sizeResolver && + placeholderPainter == other.placeholderPainter && + errorPainter == other.errorPainter && + skipEvent == other.skipEvent && + optionsBuilders == other.optionsBuilders && + components == other.components && + interceptors == other.interceptors + } + + override fun hashCode(): Int { + var result = data.hashCode() + result = 31 * result + extra.hashCode() + result = 31 * result + sizeResolver.hashCode() + result = 31 * result + placeholderPainter.hashCode() + result = 31 * result + errorPainter.hashCode() + result = 31 * result + skipEvent.hashCode() + result = 31 * result + optionsBuilders.hashCode() + result = 31 * result + components.hashCode() + result = 31 * result + interceptors.hashCode() + return result + } } class ImageRequestBuilder internal constructor() { From d2e966444922e0c404dc518e9f3e57c811d7be73 Mon Sep 17 00:00:00 2001 From: seiko Date: Wed, 1 Nov 2023 17:46:11 +0800 Subject: [PATCH 72/99] add @Composable AutoSizeImage --- .../com/seiko/imageloader/AutoSizeImage.kt | 499 ++++++++++++++++++ .../kotlin/com/seiko/imageloader/Modifiers.kt | 69 --- .../com/seiko/imageloader/LocalImageLoader.kt | 4 +- 3 files changed, 502 insertions(+), 70 deletions(-) create mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt delete mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt new file mode 100644 index 00000000..36a53dbb --- /dev/null +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt @@ -0,0 +1,499 @@ +package com.seiko.imageloader + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.RememberObserver +import androidx.compose.runtime.withFrameMillis +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.isSpecified +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.DefaultAlpha +import androidx.compose.ui.graphics.drawscope.ContentDrawScope +import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.withSave +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.layout.times +import androidx.compose.ui.node.CompositionLocalConsumerModifierNode +import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.LayoutModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.node.currentValueOf +import androidx.compose.ui.node.invalidateDraw +import androidx.compose.ui.node.invalidateMeasurement +import androidx.compose.ui.platform.InspectorInfo +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.constrainHeight +import androidx.compose.ui.unit.constrainWidth +import androidx.compose.ui.unit.toOffset +import com.seiko.imageloader.model.ImageEvent +import com.seiko.imageloader.model.ImageRequest +import com.seiko.imageloader.model.ImageResult +import com.seiko.imageloader.option.AsyncSizeResolver +import com.seiko.imageloader.option.SizeResolver +import com.seiko.imageloader.option.toScale +import com.seiko.imageloader.util.AnimationPainter +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlin.math.roundToInt + +@Composable +fun AutoSizeImage( + request: ImageRequest, + contentDescription: String?, + modifier: Modifier = Modifier, + alignment: Alignment = Alignment.Center, + contentScale: ContentScale = ContentScale.Fit, + alpha: Float = DefaultAlpha, + colorFilter: ColorFilter? = null, + imageLoader: ImageLoader? = null, + placeholderPainter: (@Composable () -> Painter)? = request.placeholderPainter, + errorPainter: (@Composable () -> Painter)? = request.errorPainter, +) { + // same with @Composable Image(painter) + val semantics = if (contentDescription != null) { + Modifier.semantics { + this.contentDescription = contentDescription + this.role = Role.Image + } + } else { + Modifier + } + Layout( + modifier.then(semantics).clipToBounds().autoSizeNode( + request = request, + alignment = alignment, + contentScale = contentScale, + alpha = alpha, + colorFilter = colorFilter, + imageLoader = imageLoader, + placeholderPainter = placeholderPainter?.invoke(), + errorPainter = errorPainter?.invoke(), + ), + ) { _, constraints -> + layout(constraints.minWidth, constraints.minHeight) {} + } +} + +private fun Modifier.autoSizeNode( + request: ImageRequest, + alignment: Alignment, + contentScale: ContentScale, + alpha: Float, + colorFilter: ColorFilter?, + imageLoader: ImageLoader?, + placeholderPainter: Painter?, + errorPainter: Painter?, +): Modifier = this then AutoSizeImageNodeElement( + request = request, + alignment = alignment, + contentScale = contentScale, + alpha = alpha, + colorFilter = colorFilter, + imageLoader = imageLoader, + placeholderPainter = placeholderPainter, + errorPainter = errorPainter, +) + +private data class AutoSizeImageNodeElement( + private val request: ImageRequest, + private val alignment: Alignment, + private val contentScale: ContentScale, + private val alpha: Float, + private val colorFilter: ColorFilter?, + private val imageLoader: ImageLoader?, + private val placeholderPainter: Painter?, + private val errorPainter: Painter?, +) : ModifierNodeElement() { + override fun create(): AutoSizeImageNode { + return AutoSizeImageNode( + request = request, + alignment = alignment, + contentScale = contentScale, + alpha = alpha, + colorFilter = colorFilter, + imageLoader = imageLoader, + placeholderPainter = placeholderPainter, + errorPainter = errorPainter, + ) + } + + override fun update(node: AutoSizeImageNode) { + node.update( + request = request, + alignment = alignment, + contentScale = contentScale, + alpha = alpha, + colorFilter = colorFilter, + imageLoader = imageLoader, + placeholderPainter = placeholderPainter, + errorPainter = errorPainter, + ) + } + + override fun InspectorInfo.inspectableProperties() { + name = "autoSizeImage" + properties["request"] = request + properties["alignment"] = alignment + properties["contentScale"] = contentScale + properties["alpha"] = alpha + properties["colorFilter"] = colorFilter + properties["imageLoader"] = imageLoader ?: "Default" + properties["placeholderPainter"] = placeholderPainter + properties["errorPainter"] = errorPainter + } +} + +private class AutoSizeImageNode( + request: ImageRequest, + private var alignment: Alignment, + private var contentScale: ContentScale, + private var alpha: Float, + private var colorFilter: ColorFilter?, + private var imageLoader: ImageLoader?, + private var placeholderPainter: Painter?, + private var errorPainter: Painter?, +) : Modifier.Node(), LayoutModifierNode, DrawModifierNode, CompositionLocalConsumerModifierNode { + + private var request: ImageRequest = modifyRequest(request) + + private var currentImageJob: Job? = null + private var currentPlayerJob: Job? = null + + private var cachedSize: Size = Size.Unspecified + + private var drawPainter: Painter? = null + private var drawPainterPositionAndSize: CachedPositionAndSize? = null + + private var hasFixedSize: Boolean = false + private var isReset: Boolean = false + + override val shouldAutoInvalidate: Boolean + get() = false + + override fun onAttach() { + super.onAttach() + isReset = false + launchImage() + } + + override fun onDetach() { + super.onDetach() + clear() + } + + override fun onReset() { + super.onReset() + isReset = true + } + + private fun clear() { + // if this node is reset from pool, not need to reset size + if (!isReset) { + hasFixedSize = false + cachedSize = Size.Unspecified + } + updatePainter(null) + } + + fun update( + request: ImageRequest, + alignment: Alignment, + contentScale: ContentScale, + alpha: Float, + colorFilter: ColorFilter?, + imageLoader: ImageLoader?, + placeholderPainter: Painter?, + errorPainter: Painter?, + ) { + val finalRequest = modifyRequest(request) + val isRequestChange = this.request != finalRequest + + this.request = finalRequest + this.alignment = alignment + this.contentScale = contentScale + this.alpha = alpha + this.colorFilter = colorFilter + this.imageLoader = imageLoader + this.placeholderPainter = placeholderPainter + this.errorPainter = errorPainter + + if (isAttached && isRequestChange) { + launchImage() + } + } + + private fun modifyRequest(request: ImageRequest): ImageRequest { + return if (request.sizeResolver == SizeResolver.Unspecified) { + ImageRequest(request) { + if (cachedSize.isSpecified && !cachedSize.isEmpty()) { + size(SizeResolver(cachedSize)) + } else { + size(AsyncSizeResolver()) + } + scale(contentScale.toScale()) + } + } else { + request + } + } + + private fun launchImage() { + val imageLoader = imageLoader ?: currentValueOf(LocalImageLoader) + currentImageJob?.cancel() + currentImageJob = coroutineScope.launch { + imageLoader.async(request).collect { action -> + when (action) { + is ImageEvent -> placeholderPainter + is ImageResult.OfPainter -> action.painter + is ImageResult.OfBitmap -> action.bitmap.toPainter() + is ImageResult.OfImage -> action.image.toPainter() + is ImageResult.OfError -> errorPainter + is ImageResult.OfSource -> errorPainter + }?.let { painter -> + updatePainter(painter) + } + } + } + } + + private fun updatePainter(painter: Painter?) { + (drawPainter as? RememberObserver)?.onAbandoned() + currentPlayerJob?.cancel() + currentPlayerJob = null + + drawPainter = painter + + if (isAttached) { + (painter as? RememberObserver)?.onRemembered() + checkPainterPlay() + } + + drawPainterPositionAndSize = null + + if (hasFixedSize) { + invalidateDraw() + } else { + invalidateMeasurement() + } + } + + private fun checkPainterPlay() { + val painter = drawPainter ?: return + if (painter is AnimationPainter && painter.isPlay()) { + currentPlayerJob?.cancel() + currentPlayerJob = coroutineScope.launch { + while (painter.nextPlay()) { + withFrameMillis { frameTimeMillis -> + painter.update(frameTimeMillis) + } + } + } + } + } + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints, + ): MeasureResult { + drawPainterPositionAndSize = null + hasFixedSize = constraints.hasFixedSize() + cachedSize = constraints.inferredSize() + + val sizeResolver = request.sizeResolver + if (sizeResolver is AsyncSizeResolver) { + sizeResolver.setSize(cachedSize) + } + + val placeable = measurable.measure( + modifyConstraints(constraints, drawPainter, contentScale), + ) + return layout(placeable.width, placeable.height) { + placeable.placeRelative(0, 0) + } + } + + override fun ContentDrawScope.draw() { + drawPainter?.let { painter -> + drawContext.canvas.withSave { + val positionAndSize = drawPainterPositionAndSize + ?: calcPositionAndSize(painter).also { + drawPainterPositionAndSize = it + } + val dx = positionAndSize.position.x + val dy = positionAndSize.position.y + val scaledSize = positionAndSize.size + translate(dx, dy) { + with(painter) { + draw(scaledSize, alpha, colorFilter) + } + } + } + } + + // Maintain the same pattern as Modifier.drawBehind to allow chaining of DrawModifiers + drawContent() + } + + private fun ContentDrawScope.calcPositionAndSize(painter: Painter): CachedPositionAndSize { + val intrinsicSize = painter.intrinsicSize + val srcWidth = if (intrinsicSize.hasSpecifiedAndFiniteWidth()) { + intrinsicSize.width + } else { + size.width + } + + val srcHeight = if (intrinsicSize.hasSpecifiedAndFiniteHeight()) { + intrinsicSize.height + } else { + size.height + } + val srcSize = Size(srcWidth, srcHeight) + + // Compute the offset to translate the content based on the given alignment + // and size to draw based on the ContentScale parameter + val scaledSize = if (size.width != 0f && size.height != 0f) { + srcSize * contentScale.computeScaleFactor(srcSize, size) + } else { + Size.Zero + } + + val alignedPosition = alignment.align( + IntSize(scaledSize.width.roundToInt(), scaledSize.height.roundToInt()), + IntSize(size.width.roundToInt(), size.height.roundToInt()), + layoutDirection, + ).toOffset() + return CachedPositionAndSize( + alignedPosition, + scaledSize, + ) + } + + private data class CachedPositionAndSize( + val position: Offset, + val size: Size, + ) + + override fun equals(other: Any?): Boolean { + return (other is AutoSizeImageNode) && + request == other.request && + alignment == other.alignment && + contentScale == other.contentScale && + alpha == other.alpha && + colorFilter == other.colorFilter && + imageLoader == other.imageLoader + } + + override fun hashCode(): Int { + var result = request.hashCode() + result = 31 * result + alignment.hashCode() + result = 31 * result + contentScale.hashCode() + result = 31 * result + alpha.hashCode() + result = 31 * result + colorFilter.hashCode() + result = 31 * result + imageLoader.hashCode() + result = 31 * result + placeholderPainter.hashCode() + result = 31 * result + errorPainter.hashCode() + return result + } + + override fun toString(): String { + return "AutoSizeImageModifier(" + + "painter=$drawPainter, " + + "alignment=$alignment, " + + "contentScale=$contentScale, " + + "alpha=$alpha, " + + "colorFilter=$colorFilter, " + + "imageLoader=$imageLoader, " + + "placeholderPainter=$placeholderPainter, " + + "errorPainter=$errorPainter)" + } +} + +private fun modifyConstraints( + constraints: Constraints, + painter: Painter?, + contentScale: ContentScale, +): Constraints { + if (constraints.hasFixedSize()) { + return constraints.copy( + minWidth = constraints.maxWidth, + minHeight = constraints.maxHeight, + ) + } + + val intrinsicSize = painter?.intrinsicSize ?: return constraints + val intrinsicWidth = if (intrinsicSize.hasSpecifiedAndFiniteWidth()) { + intrinsicSize.width.roundToInt() + } else { + constraints.minWidth + } + + val intrinsicHeight = if (intrinsicSize.hasSpecifiedAndFiniteHeight()) { + intrinsicSize.height.roundToInt() + } else { + constraints.minHeight + } + + // Scale the width and height appropriately based on the given constraints + // and ContentScale + val constrainedWidth = constraints.constrainWidth(intrinsicWidth) + val constrainedHeight = constraints.constrainHeight(intrinsicHeight) + val scaledSize = calculateScaledSize( + Size(constrainedWidth.toFloat(), constrainedHeight.toFloat()), + painter, + contentScale, + ) + + // For both width and height constraints, consume the minimum of the scaled width + // and the maximum constraint as some scale types can scale larger than the maximum + // available size (ex ContentScale.Crop) + // In this case the larger of the 2 dimensions is used and the aspect ratio is + // maintained. Even if the size of the composable is smaller, the painter will + // draw its content clipped + val minWidth = constraints.constrainWidth(scaledSize.width.roundToInt()) + val minHeight = constraints.constrainHeight(scaledSize.height.roundToInt()) + return constraints.copy(minWidth = minWidth, minHeight = minHeight) +} + +private fun calculateScaledSize(dstSize: Size, painter: Painter, contentScale: ContentScale): Size { + val srcWidth = if (!painter.intrinsicSize.hasSpecifiedAndFiniteWidth()) { + dstSize.width + } else { + painter.intrinsicSize.width + } + + val srcHeight = if (!painter.intrinsicSize.hasSpecifiedAndFiniteHeight()) { + dstSize.height + } else { + painter.intrinsicSize.height + } + + val srcSize = Size(srcWidth, srcHeight) + return if (dstSize.width != 0f && dstSize.height != 0f) { + srcSize * contentScale.computeScaleFactor(srcSize, dstSize) + } else { + Size.Zero + } +} + +private fun Constraints.hasFixedSize() = hasFixedWidth && hasFixedHeight + +internal fun Constraints.inferredSize(): Size { + if (!hasBoundedWidth || !hasBoundedHeight) return Size.Unspecified + return Size(maxWidth.toFloat(), maxHeight.toFloat()) +} + +private fun Size.hasSpecifiedAndFiniteWidth() = this != Size.Unspecified && width.isFinite() +private fun Size.hasSpecifiedAndFiniteHeight() = this != Size.Unspecified && height.isFinite() diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt deleted file mode 100644 index f521deab..00000000 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Modifiers.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.seiko.imageloader - -import androidx.compose.runtime.State -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.layout.Measurable -import androidx.compose.ui.layout.MeasureResult -import androidx.compose.ui.layout.MeasureScope -import androidx.compose.ui.node.LayoutModifierNode -import androidx.compose.ui.node.ModifierNodeElement -import androidx.compose.ui.unit.Constraints -import com.seiko.imageloader.model.ImageRequest -import com.seiko.imageloader.option.AsyncSizeResolver - -fun Modifier.imageNode( - requestState: State, -): Modifier = this.then(ImageNodeElement(requestState)) - -private class ImageNodeElement( - private val requestState: State, -) : ModifierNodeElement() { - override fun create(): ImageNode { - return ImageNode(requestState) - } - - override fun equals(other: Any?): Boolean { - val otherModifier = other as? ImageNodeElement ?: return false - return requestState == otherModifier.requestState - } - - override fun hashCode(): Int { - return requestState.hashCode() - } - - override fun update(node: ImageNode) { - node.requestState = requestState - } -} - -private class ImageNode( - var requestState: State, -) : Modifier.Node(), LayoutModifierNode { - - val request: ImageRequest by requestState - - override fun MeasureScope.measure( - measurable: Measurable, - constraints: Constraints, - ): MeasureResult { - val sizeResolver = request.sizeResolver - if (sizeResolver is AsyncSizeResolver) { - val inferredSize = constraints.inferredSize() - sizeResolver.setSize(inferredSize) - } - - val placeable = measurable.measure(constraints) - return layout(placeable.width, placeable.height) { - placeable.placeRelative(0, 0) - } - } -} - -private fun Constraints.hasFixedSize() = hasFixedWidth && hasFixedHeight - -internal fun Constraints.inferredSize(): Size { - if (!hasBoundedWidth || !hasBoundedHeight) return Size.Unspecified - return Size(maxWidth.toFloat(), maxHeight.toFloat()) -} diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 2140c7d5..8a32d43c 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -3,12 +3,14 @@ package com.seiko.imageloader import androidx.compose.runtime.Composable import androidx.compose.runtime.ProvidedValue import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.staticCompositionLocalOf import com.seiko.imageloader.cache.memory.MemoryCache import com.seiko.imageloader.component.setupDefaultComponents import com.seiko.imageloader.intercept.InterceptorsBuilder import com.seiko.imageloader.model.ImageResult -val LocalImageLoader = createImageLoaderProvidableCompositionLocal() +// TODO need to update +val LocalImageLoader = staticCompositionLocalOf { error("please provide ImageLoader first.") } // maybe it's no longer needed here expect class ImageLoaderProvidableCompositionLocal { From cb4161554335cf9aea3f16d336a8228ddfd69d18 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 2 Nov 2023 09:57:04 +0800 Subject: [PATCH 73/99] fix ImageActionTest --- .../imageloader/model/ImageActionTest.kt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt index 3cacba1c..f34ac3ff 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageActionTest.kt @@ -89,11 +89,11 @@ class ImageActionTest { private fun when_image_result_test(action: ImageAction) { when (action) { is ImageEvent -> LoadingUI() - is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Error -> ErrorUI(action.error) - is ImageResult.Source -> ErrorUI(action.error) + is ImageResult.OfImage -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfBitmap -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfPainter -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfError -> ErrorUI(action.error) + is ImageResult.OfSource -> ErrorUI(action.error) } } @@ -101,9 +101,9 @@ class ImageActionTest { private fun when_image_result_success_no_result_failure_test(action: ImageAction) { when (action) { is ImageAction.Loading -> LoadingUI() - is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfImage -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfBitmap -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfPainter -> SuccessUI(rememberImageSuccessPainter(action)) is ImageAction.Failure -> ErrorUI(action.error) } } @@ -116,11 +116,11 @@ class ImageActionTest { is ImageEvent.StartWithDisk, is ImageEvent.StartWithFetch, -> LoadingUI() - is ImageResult.Image -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Bitmap -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Painter -> SuccessUI(rememberImageSuccessPainter(action)) - is ImageResult.Error -> ErrorUI(action.error) - is ImageResult.Source -> ErrorUI(action.error) + is ImageResult.OfImage -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfBitmap -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfPainter -> SuccessUI(rememberImageSuccessPainter(action)) + is ImageResult.OfError -> ErrorUI(action.error) + is ImageResult.OfSource -> ErrorUI(action.error) } } From d737986ec4dfd54e336b9d1755b508f011df9189 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 2 Nov 2023 10:03:45 +0800 Subject: [PATCH 74/99] remove apple httpEngine --- .../kotlin/com/seiko/imageloader/util/Platform.apple.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt index 51ff888d..49431509 100644 --- a/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt +++ b/image-loader/src/appleMain/kotlin/com/seiko/imageloader/util/Platform.apple.kt @@ -1,11 +1,7 @@ package com.seiko.imageloader.util -import io.ktor.client.engine.HttpClientEngine -import io.ktor.client.engine.darwin.Darwin import okio.FileSystem actual typealias WeakReference = kotlin.native.ref.WeakReference -internal actual val httpEngine: HttpClientEngine get() = Darwin.create() - internal actual val defaultFileSystem: FileSystem? get() = FileSystem.SYSTEM From 10322ddc67f5e466db5bf2472d98cdf6c478380f Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 2 Nov 2023 10:45:57 +0800 Subject: [PATCH 75/99] apply spotless --- .../src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 655661fc..9ef1c67e 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -11,8 +11,6 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.transformLatest From c97c70d70a174258a530becf4920bf6ea8976ec8 Mon Sep 17 00:00:00 2001 From: seiko Date: Thu, 2 Nov 2023 14:37:13 +0800 Subject: [PATCH 76/99] replace with applyHierarchyTemplate --- .../src/main/kotlin/KotlinMultiplatformConventionPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt index 1e005fc0..a76e99e5 100644 --- a/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt @@ -24,7 +24,7 @@ class KotlinMultiplatformConventionPlugin : Plugin { nodejs() } @OptIn(ExperimentalKotlinGradlePluginApi::class) - targetHierarchy.custom { + applyHierarchyTemplate { common { group("jvm") { withAndroidTarget() From 539b779843f6508cb39668949448c25eec08a983 Mon Sep 17 00:00:00 2001 From: seiko Date: Fri, 3 Nov 2023 11:55:05 +0800 Subject: [PATCH 77/99] remove ImageRequest placeholderPainter & errorPainter --- .../com/seiko/imageloader/AutoSizeImage.kt | 4 ++-- .../com/seiko/imageloader/RememberExt.kt | 4 ++-- .../seiko/imageloader/model/ImageRequest.kt | 22 ------------------- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt index 36a53dbb..b17bb9ff 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt @@ -59,8 +59,8 @@ fun AutoSizeImage( alpha: Float = DefaultAlpha, colorFilter: ColorFilter? = null, imageLoader: ImageLoader? = null, - placeholderPainter: (@Composable () -> Painter)? = request.placeholderPainter, - errorPainter: (@Composable () -> Painter)? = request.errorPainter, + placeholderPainter: (@Composable () -> Painter)? = null, + errorPainter: (@Composable () -> Painter)? = null, ) { // same with @Composable Image(painter) val semantics = if (contentDescription != null) { diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt index 66015ecf..fd8edf2f 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt @@ -69,8 +69,8 @@ fun rememberImagePainter( request: ImageRequest, imageLoader: ImageLoader = LocalImageLoader.current, filterQuality: FilterQuality = DrawScope.DefaultFilterQuality, - placeholderPainter: (@Composable () -> Painter)? = request.placeholderPainter, - errorPainter: (@Composable () -> Painter)? = request.errorPainter, + placeholderPainter: (@Composable () -> Painter)? = null, + errorPainter: (@Composable () -> Painter)? = null, ): Painter { val action by rememberImageAction(request, imageLoader) return rememberImageActionPainter( diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index 67ef2b55..eca4ce24 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -1,8 +1,6 @@ package com.seiko.imageloader.model -import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable -import androidx.compose.ui.graphics.painter.Painter import com.seiko.imageloader.component.ComponentRegistry import com.seiko.imageloader.component.ComponentRegistryBuilder import com.seiko.imageloader.intercept.Interceptor @@ -15,8 +13,6 @@ class ImageRequest internal constructor( val data: Any, val extra: ExtraData, val sizeResolver: SizeResolver, - val placeholderPainter: (@Composable () -> Painter)?, - val errorPainter: (@Composable () -> Painter)?, val skipEvent: Boolean, internal val optionsBuilders: List Unit>, internal val components: ComponentRegistry?, @@ -28,8 +24,6 @@ class ImageRequest internal constructor( data == other.data && extra == other.extra && sizeResolver == other.sizeResolver && - placeholderPainter == other.placeholderPainter && - errorPainter == other.errorPainter && skipEvent == other.skipEvent && optionsBuilders == other.optionsBuilders && components == other.components && @@ -40,8 +34,6 @@ class ImageRequest internal constructor( var result = data.hashCode() result = 31 * result + extra.hashCode() result = 31 * result + sizeResolver.hashCode() - result = 31 * result + placeholderPainter.hashCode() - result = 31 * result + errorPainter.hashCode() result = 31 * result + skipEvent.hashCode() result = 31 * result + optionsBuilders.hashCode() result = 31 * result + components.hashCode() @@ -56,8 +48,6 @@ class ImageRequestBuilder internal constructor() { private var sizeResolver: SizeResolver = SizeResolver.Unspecified private val optionsBuilders: MutableList Unit> = mutableListOf() private var extraData: ExtraData? = null - private var placeholderPainter: (@Composable () -> Painter)? = null - private var errorPainter: (@Composable () -> Painter)? = null private var componentBuilder: ComponentRegistryBuilder? = null private var interceptors: MutableList? = null var skipEvent: Boolean = false @@ -72,8 +62,6 @@ class ImageRequestBuilder internal constructor() { } optionsBuilders.addAll(request.optionsBuilders) extraData = request.extra - placeholderPainter = request.placeholderPainter - errorPainter = request.errorPainter componentBuilder = request.components?.let { ComponentRegistryBuilder(it) } interceptors = request.interceptors?.toMutableList() skipEvent = request.skipEvent @@ -113,21 +101,11 @@ class ImageRequestBuilder internal constructor() { ?: extraData(builder) } - fun placeholderPainter(loader: @Composable () -> Painter) { - placeholderPainter = loader - } - - fun errorPainter(loader: @Composable () -> Painter) { - errorPainter = loader - } - internal fun build() = ImageRequest( data = data ?: NullRequestData, sizeResolver = sizeResolver, optionsBuilders = optionsBuilders, extra = extraData ?: EmptyExtraData, - placeholderPainter = placeholderPainter, - errorPainter = errorPainter, skipEvent = skipEvent, components = componentBuilder?.build(), interceptors = interceptors, From 6b797845feda59b5c391136f8f6c4babbc293822 Mon Sep 17 00:00:00 2001 From: seiko Date: Fri, 3 Nov 2023 15:47:20 +0800 Subject: [PATCH 78/99] fix ImageRequestTest --- .../kotlin/com/seiko/imageloader/model/ImageRequestTest.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt index 80a952ec..ed43af2d 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt @@ -64,8 +64,6 @@ class ImageRequestTest { @Test fun image_request_other_params_test() { - val placeholderPainterFactory = @Composable { EmptyPainter } - val errorPainterFactory = @Composable { EmptyPainter } val mapperFactory = Mapper { _, _ -> } val keyerFactory = Keyer { _, _, _ -> null } val fetcherFactory = Fetcher.Factory { _, _ -> @@ -78,8 +76,6 @@ class ImageRequestTest { extra { put("a", "aaa") } - placeholderPainter(placeholderPainterFactory) - errorPainter(errorPainterFactory) skipEvent = true components { add(mapperFactory) @@ -89,8 +85,6 @@ class ImageRequestTest { } } assertEquals(request.extra["a"], "aaa") - assertEquals(request.placeholderPainter, placeholderPainterFactory) - assertEquals(request.errorPainter, errorPainterFactory) assertEquals(request.skipEvent, true) assertNotNull(request.components) assertEquals(request.components.mappers.first(), mapperFactory) From 8aefa929d8a5223558c5ce04fc222392a1a2f6d4 Mon Sep 17 00:00:00 2001 From: seiko Date: Sat, 4 Nov 2023 20:08:44 +0800 Subject: [PATCH 79/99] add @Composable AutoSizeBox --- image-loader/build.gradle.kts | 2 + .../com/seiko/imageloader/AutoSizeBox.kt | 188 ++++++++++++++++++ .../com/seiko/imageloader/AutoSizeImage.kt | 43 +--- .../imageloader/CachedPositionAndSize.kt | 9 + .../com/seiko/imageloader/Remember.kt | 0 .../com/seiko/imageloader/RememberExt.kt | 0 .../imageloader/model/ImageRequestTest.kt | 2 - 7 files changed, 207 insertions(+), 37 deletions(-) create mode 100644 image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt rename image-loader/src/commonMain/{kotlin => compose}/com/seiko/imageloader/AutoSizeImage.kt (93%) create mode 100644 image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt rename image-loader/src/commonMain/{kotlin => compose}/com/seiko/imageloader/Remember.kt (100%) rename image-loader/src/commonMain/{kotlin => compose}/com/seiko/imageloader/RememberExt.kt (100%) diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 46cae0db..378fa201 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -19,7 +19,9 @@ kotlin { } } commonMain { + kotlin.srcDir("src/$name/compose") dependencies { + api(compose.foundation) api(compose.ui) api(libs.kotlinx.coroutines.core) api(libs.okio) diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt b/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt new file mode 100644 index 00000000..d15f9b5d --- /dev/null +++ b/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt @@ -0,0 +1,188 @@ +package com.seiko.imageloader + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.isSpecified +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.node.LayoutModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.platform.InspectorInfo +import androidx.compose.ui.unit.Constraints +import com.seiko.imageloader.model.ImageAction +import com.seiko.imageloader.model.ImageEvent +import com.seiko.imageloader.model.ImageRequest +import com.seiko.imageloader.option.AsyncSizeResolver +import com.seiko.imageloader.option.SizeResolver +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +@Composable +fun AutoSizeBox( + request: ImageRequest, + modifier: Modifier = Modifier, + imageLoader: ImageLoader = LocalImageLoader.current, + contentAlignment: Alignment = Alignment.Center, + propagateMinConstraints: Boolean = false, + content: @Composable BoxScope.(ImageAction) -> Unit, +) { + var action by remember { + mutableStateOf(ImageEvent.Start) + } + Box( + modifier = modifier.autoSizeBoxNode( + request = request, + imageLoader = imageLoader, + onImageActionChange = { action = it }, + ), + contentAlignment = contentAlignment, + propagateMinConstraints = propagateMinConstraints, + ) { + content(action) + } +} + +private fun Modifier.autoSizeBoxNode( + request: ImageRequest, + imageLoader: ImageLoader, + onImageActionChange: (ImageAction) -> Unit, +): Modifier = this then AutoSizeBoxNodeElement( + request = request, + imageLoader = imageLoader, + onImageActionChange = onImageActionChange, +) + +private data class AutoSizeBoxNodeElement( + val request: ImageRequest, + val imageLoader: ImageLoader, + val onImageActionChange: (ImageAction) -> Unit, +) : ModifierNodeElement() { + + override fun create(): AutoSizeBoxNode { + return AutoSizeBoxNode( + request = request, + imageLoader = imageLoader, + onImageActionChange = onImageActionChange, + ) + } + + override fun update(node: AutoSizeBoxNode) { + node.update( + request = request, + imageLoader = imageLoader, + onImageActionChange = onImageActionChange, + ) + } + + override fun InspectorInfo.inspectableProperties() { + name = "autoSizeBox" + properties["request"] = request + properties["imageLoader"] = imageLoader + properties["onImageActionChange"] = onImageActionChange + } +} + +private class AutoSizeBoxNode( + request: ImageRequest, + private var imageLoader: ImageLoader, + private var onImageActionChange: (ImageAction) -> Unit, +) : Modifier.Node(), LayoutModifierNode { + + private var currentImageJob: Job? = null + + private var cachedSize: Size = Size.Unspecified + + private var isReset = false + + private var request: ImageRequest = modifyRequest(request, cachedSize) + + override val shouldAutoInvalidate: Boolean + get() = false + + override fun onAttach() { + super.onAttach() + isReset = false + launchImage() + } + + override fun onReset() { + super.onReset() + isReset = true + } + + override fun onDetach() { + super.onDetach() + if (!isReset) { + cachedSize = Size.Unspecified + } + } + + fun update( + request: ImageRequest, + imageLoader: ImageLoader, + onImageActionChange: (ImageAction) -> Unit, + ) { + val finalRequest = modifyRequest(request, cachedSize) + val isRequestChange = this.request != finalRequest + + this.request = request + this.imageLoader = imageLoader + this.onImageActionChange = onImageActionChange + + if (isAttached && isRequestChange) { + launchImage() + } + } + + private fun launchImage() { + currentImageJob?.cancel() + currentImageJob = coroutineScope.launch { + imageLoader.async(request).collect { action -> + onImageActionChange(action) + } + } + } + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints, + ): MeasureResult { + cachedSize = constraints.inferredSize() + + val sizeResolver = request.sizeResolver + if (sizeResolver is AsyncSizeResolver) { + sizeResolver.setSize(cachedSize) + } + + val placeable = measurable.measure(constraints) + return layout(placeable.width, placeable.height) { + placeable.placeRelative(0, 0) + } + } +} + +internal fun modifyRequest( + request: ImageRequest, + cachedSize: Size, +): ImageRequest { + return if (request.sizeResolver == SizeResolver.Unspecified) { + ImageRequest(request) { + if (cachedSize.isSpecified && !cachedSize.isEmpty()) { + size(SizeResolver(cachedSize)) + } else { + size(AsyncSizeResolver()) + } + } + } else { + request + } +} diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt b/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeImage.kt similarity index 93% rename from image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt rename to image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeImage.kt index b17bb9ff..60bdd1bd 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/AutoSizeImage.kt +++ b/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeImage.kt @@ -6,9 +6,7 @@ import androidx.compose.runtime.withFrameMillis import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size -import androidx.compose.ui.geometry.isSpecified import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.DefaultAlpha import androidx.compose.ui.graphics.drawscope.ContentDrawScope @@ -42,8 +40,6 @@ import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.AsyncSizeResolver -import com.seiko.imageloader.option.SizeResolver -import com.seiko.imageloader.option.toScale import com.seiko.imageloader.util.AnimationPainter import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -72,7 +68,7 @@ fun AutoSizeImage( Modifier } Layout( - modifier.then(semantics).clipToBounds().autoSizeNode( + modifier.then(semantics).clipToBounds().autoSizeImageNode( request = request, alignment = alignment, contentScale = contentScale, @@ -87,7 +83,7 @@ fun AutoSizeImage( } } -private fun Modifier.autoSizeNode( +private fun Modifier.autoSizeImageNode( request: ImageRequest, alignment: Alignment, contentScale: ContentScale, @@ -117,6 +113,7 @@ private data class AutoSizeImageNodeElement( private val placeholderPainter: Painter?, private val errorPainter: Painter?, ) : ModifierNodeElement() { + override fun create(): AutoSizeImageNode { return AutoSizeImageNode( request = request, @@ -167,8 +164,6 @@ private class AutoSizeImageNode( private var errorPainter: Painter?, ) : Modifier.Node(), LayoutModifierNode, DrawModifierNode, CompositionLocalConsumerModifierNode { - private var request: ImageRequest = modifyRequest(request) - private var currentImageJob: Job? = null private var currentPlayerJob: Job? = null @@ -180,6 +175,8 @@ private class AutoSizeImageNode( private var hasFixedSize: Boolean = false private var isReset: Boolean = false + private var request: ImageRequest = modifyRequest(request, cachedSize) + override val shouldAutoInvalidate: Boolean get() = false @@ -189,17 +186,13 @@ private class AutoSizeImageNode( launchImage() } - override fun onDetach() { - super.onDetach() - clear() - } - override fun onReset() { super.onReset() isReset = true } - private fun clear() { + override fun onDetach() { + super.onDetach() // if this node is reset from pool, not need to reset size if (!isReset) { hasFixedSize = false @@ -218,7 +211,7 @@ private class AutoSizeImageNode( placeholderPainter: Painter?, errorPainter: Painter?, ) { - val finalRequest = modifyRequest(request) + val finalRequest = modifyRequest(request, cachedSize) val isRequestChange = this.request != finalRequest this.request = finalRequest @@ -235,21 +228,6 @@ private class AutoSizeImageNode( } } - private fun modifyRequest(request: ImageRequest): ImageRequest { - return if (request.sizeResolver == SizeResolver.Unspecified) { - ImageRequest(request) { - if (cachedSize.isSpecified && !cachedSize.isEmpty()) { - size(SizeResolver(cachedSize)) - } else { - size(AsyncSizeResolver()) - } - scale(contentScale.toScale()) - } - } else { - request - } - } - private fun launchImage() { val imageLoader = imageLoader ?: currentValueOf(LocalImageLoader) currentImageJob?.cancel() @@ -381,11 +359,6 @@ private class AutoSizeImageNode( ) } - private data class CachedPositionAndSize( - val position: Offset, - val size: Size, - ) - override fun equals(other: Any?): Boolean { return (other is AutoSizeImageNode) && request == other.request && diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt b/image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt new file mode 100644 index 00000000..ed0d3f78 --- /dev/null +++ b/image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt @@ -0,0 +1,9 @@ +package com.seiko.imageloader + +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size + +internal data class CachedPositionAndSize( + val position: Offset, + val size: Size, +) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/compose/com/seiko/imageloader/Remember.kt similarity index 100% rename from image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt rename to image-loader/src/commonMain/compose/com/seiko/imageloader/Remember.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt b/image-loader/src/commonMain/compose/com/seiko/imageloader/RememberExt.kt similarity index 100% rename from image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt rename to image-loader/src/commonMain/compose/com/seiko/imageloader/RememberExt.kt diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt index ed43af2d..5979ffce 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/model/ImageRequestTest.kt @@ -1,8 +1,6 @@ package com.seiko.imageloader.model -import androidx.compose.runtime.Composable import com.seiko.imageloader.BitmapConfig -import com.seiko.imageloader.EmptyPainter import com.seiko.imageloader.cache.CachePolicy import com.seiko.imageloader.component.decoder.Decoder import com.seiko.imageloader.component.fetcher.Fetcher From 18957e89507202893be76edccc1a69a797b95bda Mon Sep 17 00:00:00 2001 From: seiko Date: Sat, 4 Nov 2023 20:09:09 +0800 Subject: [PATCH 80/99] config -Xexpect-actual-classes --- image-loader/build.gradle.kts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 378fa201..5701d59b 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -90,6 +90,13 @@ kotlin { kotlin.srcDir("src/$name/singleton") } } + targets.all { + compilations.all { + compilerOptions.configure { + freeCompilerArgs.add("-Xexpect-actual-classes") + } + } + } } @Suppress("UnstableApiUsage") From fa7a6c06df43700f30b95981bdb0c4bf5e73f690 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 10:49:53 +0800 Subject: [PATCH 81/99] add isOnlyPostFirstEvent param to skip next event if ImageRequest change --- image-loader/build.gradle.kts | 1 - .../com/seiko/imageloader/Remember.kt | 0 .../com/seiko/imageloader/RememberExt.kt | 0 .../seiko/imageloader/compose}/AutoSizeBox.kt | 21 +++++++++++-- .../imageloader/compose}/AutoSizeImage.kt | 31 +++++++++++++------ .../compose}/CachedPositionAndSize.kt | 2 +- .../seiko/imageloader/model/ImageRequest.kt | 11 +++++++ 7 files changed, 52 insertions(+), 14 deletions(-) rename image-loader/src/commonMain/{compose => kotlin}/com/seiko/imageloader/Remember.kt (100%) rename image-loader/src/commonMain/{compose => kotlin}/com/seiko/imageloader/RememberExt.kt (100%) rename image-loader/src/commonMain/{compose/com/seiko/imageloader => kotlin/com/seiko/imageloader/compose}/AutoSizeBox.kt (88%) rename image-loader/src/commonMain/{compose/com/seiko/imageloader => kotlin/com/seiko/imageloader/compose}/AutoSizeImage.kt (94%) rename image-loader/src/commonMain/{compose/com/seiko/imageloader => kotlin/com/seiko/imageloader/compose}/CachedPositionAndSize.kt (82%) diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 5701d59b..0d6b2dc9 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -19,7 +19,6 @@ kotlin { } } commonMain { - kotlin.srcDir("src/$name/compose") dependencies { api(compose.foundation) api(compose.ui) diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt similarity index 100% rename from image-loader/src/commonMain/compose/com/seiko/imageloader/Remember.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/RememberExt.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt similarity index 100% rename from image-loader/src/commonMain/compose/com/seiko/imageloader/RememberExt.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeBox.kt similarity index 88% rename from image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeBox.kt index d15f9b5d..2801af55 100644 --- a/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeBox.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeBox.kt @@ -1,4 +1,4 @@ -package com.seiko.imageloader +package com.seiko.imageloader.compose import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -18,6 +18,8 @@ import androidx.compose.ui.node.LayoutModifierNode import androidx.compose.ui.node.ModifierNodeElement import androidx.compose.ui.platform.InspectorInfo import androidx.compose.ui.unit.Constraints +import com.seiko.imageloader.ImageLoader +import com.seiko.imageloader.LocalImageLoader import com.seiko.imageloader.model.ImageAction import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest @@ -33,6 +35,7 @@ fun AutoSizeBox( imageLoader: ImageLoader = LocalImageLoader.current, contentAlignment: Alignment = Alignment.Center, propagateMinConstraints: Boolean = false, + isOnlyPostFirstEvent: Boolean = true, content: @Composable BoxScope.(ImageAction) -> Unit, ) { var action by remember { @@ -43,6 +46,7 @@ fun AutoSizeBox( request = request, imageLoader = imageLoader, onImageActionChange = { action = it }, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, ), contentAlignment = contentAlignment, propagateMinConstraints = propagateMinConstraints, @@ -55,16 +59,19 @@ private fun Modifier.autoSizeBoxNode( request: ImageRequest, imageLoader: ImageLoader, onImageActionChange: (ImageAction) -> Unit, + isOnlyPostFirstEvent: Boolean, ): Modifier = this then AutoSizeBoxNodeElement( request = request, imageLoader = imageLoader, onImageActionChange = onImageActionChange, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, ) private data class AutoSizeBoxNodeElement( val request: ImageRequest, val imageLoader: ImageLoader, val onImageActionChange: (ImageAction) -> Unit, + val isOnlyPostFirstEvent: Boolean, ) : ModifierNodeElement() { override fun create(): AutoSizeBoxNode { @@ -80,6 +87,7 @@ private data class AutoSizeBoxNodeElement( request = request, imageLoader = imageLoader, onImageActionChange = onImageActionChange, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, ) } @@ -130,11 +138,16 @@ private class AutoSizeBoxNode( request: ImageRequest, imageLoader: ImageLoader, onImageActionChange: (ImageAction) -> Unit, + isOnlyPostFirstEvent: Boolean, ) { - val finalRequest = modifyRequest(request, cachedSize) + val finalRequest = modifyRequest( + request = request, + cachedSize = cachedSize, + skipEvent = isOnlyPostFirstEvent, + ) val isRequestChange = this.request != finalRequest - this.request = request + this.request = finalRequest this.imageLoader = imageLoader this.onImageActionChange = onImageActionChange @@ -173,6 +186,7 @@ private class AutoSizeBoxNode( internal fun modifyRequest( request: ImageRequest, cachedSize: Size, + skipEvent: Boolean = false, ): ImageRequest { return if (request.sizeResolver == SizeResolver.Unspecified) { ImageRequest(request) { @@ -181,6 +195,7 @@ internal fun modifyRequest( } else { size(AsyncSizeResolver()) } + this.skipEvent = skipEvent } } else { request diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeImage.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt similarity index 94% rename from image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeImage.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt index 60bdd1bd..6a86c44a 100644 --- a/image-loader/src/commonMain/compose/com/seiko/imageloader/AutoSizeImage.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt @@ -1,4 +1,4 @@ -package com.seiko.imageloader +package com.seiko.imageloader.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.RememberObserver @@ -36,10 +36,13 @@ import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.constrainHeight import androidx.compose.ui.unit.constrainWidth import androidx.compose.ui.unit.toOffset +import com.seiko.imageloader.ImageLoader +import com.seiko.imageloader.LocalImageLoader import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.AsyncSizeResolver +import com.seiko.imageloader.toPainter import com.seiko.imageloader.util.AnimationPainter import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -54,9 +57,10 @@ fun AutoSizeImage( contentScale: ContentScale = ContentScale.Fit, alpha: Float = DefaultAlpha, colorFilter: ColorFilter? = null, - imageLoader: ImageLoader? = null, + imageLoader: ImageLoader = LocalImageLoader.current, placeholderPainter: (@Composable () -> Painter)? = null, errorPainter: (@Composable () -> Painter)? = null, + isOnlyPostFirstEvent: Boolean = true, ) { // same with @Composable Image(painter) val semantics = if (contentDescription != null) { @@ -77,6 +81,7 @@ fun AutoSizeImage( imageLoader = imageLoader, placeholderPainter = placeholderPainter?.invoke(), errorPainter = errorPainter?.invoke(), + isOnlyPostFirstEvent = isOnlyPostFirstEvent, ), ) { _, constraints -> layout(constraints.minWidth, constraints.minHeight) {} @@ -89,9 +94,10 @@ private fun Modifier.autoSizeImageNode( contentScale: ContentScale, alpha: Float, colorFilter: ColorFilter?, - imageLoader: ImageLoader?, + imageLoader: ImageLoader, placeholderPainter: Painter?, errorPainter: Painter?, + isOnlyPostFirstEvent: Boolean, ): Modifier = this then AutoSizeImageNodeElement( request = request, alignment = alignment, @@ -101,6 +107,7 @@ private fun Modifier.autoSizeImageNode( imageLoader = imageLoader, placeholderPainter = placeholderPainter, errorPainter = errorPainter, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, ) private data class AutoSizeImageNodeElement( @@ -109,9 +116,10 @@ private data class AutoSizeImageNodeElement( private val contentScale: ContentScale, private val alpha: Float, private val colorFilter: ColorFilter?, - private val imageLoader: ImageLoader?, + private val imageLoader: ImageLoader, private val placeholderPainter: Painter?, private val errorPainter: Painter?, + private val isOnlyPostFirstEvent: Boolean, ) : ModifierNodeElement() { override fun create(): AutoSizeImageNode { @@ -137,6 +145,7 @@ private data class AutoSizeImageNodeElement( imageLoader = imageLoader, placeholderPainter = placeholderPainter, errorPainter = errorPainter, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, ) } @@ -147,7 +156,7 @@ private data class AutoSizeImageNodeElement( properties["contentScale"] = contentScale properties["alpha"] = alpha properties["colorFilter"] = colorFilter - properties["imageLoader"] = imageLoader ?: "Default" + properties["imageLoader"] = imageLoader properties["placeholderPainter"] = placeholderPainter properties["errorPainter"] = errorPainter } @@ -159,7 +168,7 @@ private class AutoSizeImageNode( private var contentScale: ContentScale, private var alpha: Float, private var colorFilter: ColorFilter?, - private var imageLoader: ImageLoader?, + private var imageLoader: ImageLoader, private var placeholderPainter: Painter?, private var errorPainter: Painter?, ) : Modifier.Node(), LayoutModifierNode, DrawModifierNode, CompositionLocalConsumerModifierNode { @@ -207,11 +216,16 @@ private class AutoSizeImageNode( contentScale: ContentScale, alpha: Float, colorFilter: ColorFilter?, - imageLoader: ImageLoader?, + imageLoader: ImageLoader, placeholderPainter: Painter?, errorPainter: Painter?, + isOnlyPostFirstEvent: Boolean, ) { - val finalRequest = modifyRequest(request, cachedSize) + val finalRequest = modifyRequest( + request = request, + cachedSize = cachedSize, + skipEvent = isOnlyPostFirstEvent, + ) val isRequestChange = this.request != finalRequest this.request = finalRequest @@ -229,7 +243,6 @@ private class AutoSizeImageNode( } private fun launchImage() { - val imageLoader = imageLoader ?: currentValueOf(LocalImageLoader) currentImageJob?.cancel() currentImageJob = coroutineScope.launch { imageLoader.async(request).collect { action -> diff --git a/image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt similarity index 82% rename from image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt index ed0d3f78..37667ca0 100644 --- a/image-loader/src/commonMain/compose/com/seiko/imageloader/CachedPositionAndSize.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt @@ -1,4 +1,4 @@ -package com.seiko.imageloader +package com.seiko.imageloader.compose import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index eca4ce24..de55e36e 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -40,6 +40,17 @@ class ImageRequest internal constructor( result = 31 * result + interceptors.hashCode() return result } + + override fun toString(): String { + return "ImageRequest(" + + "data=${data}," + + "extra=${extra}," + + "sizeResolver=${sizeResolver}," + + "skipEvent=${skipEvent}," + + "optionsBuilders=${optionsBuilders}," + + "components=${components}," + + "interceptors=${interceptors})" + } } class ImageRequestBuilder internal constructor() { From 8131bcc4a5889829ee54cf930ae8d4ed53af8ff2 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 10:50:21 +0800 Subject: [PATCH 82/99] update demo --- .../seiko/imageloader/demo/scene/Common.kt | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index bea02e45..a3dcdfad 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -25,15 +24,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import com.seiko.imageloader.compose.AutoSizeBox import com.seiko.imageloader.demo.model.Image import com.seiko.imageloader.demo.util.NullDataInterceptor import com.seiko.imageloader.demo.util.decodeJson -import com.seiko.imageloader.model.ImageEvent +import com.seiko.imageloader.model.ImageAction import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageRequestBuilder -import com.seiko.imageloader.model.ImageResult -import com.seiko.imageloader.rememberImageAction -import com.seiko.imageloader.rememberImageActionPainter +import com.seiko.imageloader.rememberImageSuccessPainter import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -77,7 +75,7 @@ fun ImageItem( Box(modifier, Alignment.Center) { val dataState by rememberUpdatedState(data) val blockState by rememberUpdatedState(block) - val requestState = remember { + val request by remember { derivedStateOf { ImageRequest { data(dataState) @@ -92,27 +90,27 @@ fun ImageItem( } } } - val action by rememberImageAction(requestState) - val painter = rememberImageActionPainter(action) - Image( - painter = painter, - contentDescription = null, - contentScale = contentScale, - modifier = Modifier.fillMaxSize(), - ) - when (val current = action) { - is ImageEvent.StartWithDisk, - is ImageEvent.StartWithFetch, - -> { - CircularProgressIndicator() - } - is ImageResult.OfSource -> { - Text("image result is source") - } - is ImageResult.OfError -> { - Text(current.error.message ?: "Error") + + AutoSizeBox( + request, + Modifier.matchParentSize(), + ) { action -> + when (action) { + is ImageAction.Loading -> { + CircularProgressIndicator() + } + is ImageAction.Success -> { + Image( + rememberImageSuccessPainter(action), + contentDescription = "image", + contentScale = contentScale, + modifier = Modifier.matchParentSize(), + ) + } + is ImageAction.Failure -> { + Text(action.error.message ?: "Error") + } } - else -> Unit } } } From 236fa5fab53da39cad30a5ade8fd10dfed15bdd1 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 10:52:46 +0800 Subject: [PATCH 83/99] remove ImageLoader.async(Flow) --- .../com/seiko/imageloader/ImageLoader.kt | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 8c5a7a3d..4b8a682e 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -9,21 +9,17 @@ import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.option.Options import com.seiko.imageloader.util.ioDispatcher import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.transformLatest import kotlin.coroutines.CoroutineContext @Immutable interface ImageLoader { val config: ImageLoaderConfig - fun async(requestFlow: Flow): Flow - - fun async(request: ImageRequest): Flow = async(flowOf(request)) + fun async(request: ImageRequest): Flow companion object } @@ -41,26 +37,24 @@ private class RealImageLoader( private val requestCoroutineContext: CoroutineContext, override val config: ImageLoaderConfig, ) : ImageLoader { - @OptIn(ExperimentalCoroutinesApi::class) - override fun async(requestFlow: Flow) = requestFlow - .transformLatest { request -> - if (!request.skipEvent) { - emit(ImageEvent.Start) - } - val initialSize = request.sizeResolver.size() - val options = Options(config.defaultOptions) { - size = initialSize - } - val chain = InterceptorChainImpl( - initialRequest = request, - initialOptions = options, - config = config, - flowCollector = this, - ) - emit(chain.proceed(request)) - }.catch { - if (it !is CancellationException) { - emit(ImageResult.OfError(it)) - } - }.flowOn(requestCoroutineContext) + override fun async(request: ImageRequest) = flow { + if (!request.skipEvent) { + emit(ImageEvent.Start) + } + val initialSize = request.sizeResolver.size() + val options = Options(config.defaultOptions) { + size = initialSize + } + val chain = InterceptorChainImpl( + initialRequest = request, + initialOptions = options, + config = config, + flowCollector = this, + ) + emit(chain.proceed(request)) + }.catch { + if (it !is CancellationException) { + emit(ImageResult.OfError(it)) + } + }.flowOn(requestCoroutineContext) } From 2431e2469428a90d018cb0ebf5bd022bbb6f3a84 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 10:52:54 +0800 Subject: [PATCH 84/99] apply spotless --- .../com/seiko/imageloader/compose/AutoSizeImage.kt | 1 - .../com/seiko/imageloader/model/ImageRequest.kt | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt index 6a86c44a..07d1588c 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.node.CompositionLocalConsumerModifierNode import androidx.compose.ui.node.DrawModifierNode import androidx.compose.ui.node.LayoutModifierNode import androidx.compose.ui.node.ModifierNodeElement -import androidx.compose.ui.node.currentValueOf import androidx.compose.ui.node.invalidateDraw import androidx.compose.ui.node.invalidateMeasurement import androidx.compose.ui.platform.InspectorInfo diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt index de55e36e..90485afd 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/model/ImageRequest.kt @@ -43,13 +43,13 @@ class ImageRequest internal constructor( override fun toString(): String { return "ImageRequest(" + - "data=${data}," + - "extra=${extra}," + - "sizeResolver=${sizeResolver}," + - "skipEvent=${skipEvent}," + - "optionsBuilders=${optionsBuilders}," + - "components=${components}," + - "interceptors=${interceptors})" + "data=$data," + + "extra=$extra," + + "sizeResolver=$sizeResolver," + + "skipEvent=$skipEvent," + + "optionsBuilders=$optionsBuilders," + + "components=$components," + + "interceptors=$interceptors)" } } From b8b05e24f169c7d11c96e58b39e8a7f3042e9b47 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 10:54:16 +0800 Subject: [PATCH 85/99] remove some ext --- .../kotlin/com/seiko/imageloader/Remember.kt | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt index 2dbf2851..f8eabe33 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow import androidx.compose.runtime.withFrameMillis import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.FilterQuality @@ -17,27 +16,6 @@ import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageResult import com.seiko.imageloader.util.AnimationPainter -import kotlinx.coroutines.flow.Flow - -@Composable -fun rememberImageAction( - request: State, - imageLoader: ImageLoader = LocalImageLoader.current, -): State { - return remember(request, imageLoader) { - imageLoader.async(snapshotFlow { request.value }) - }.collectAsState(ImageEvent.Start) -} - -@Composable -fun rememberImageAction( - request: Flow, - imageLoader: ImageLoader = LocalImageLoader.current, -): State { - return remember(request, imageLoader) { - imageLoader.async(request) - }.collectAsState(ImageEvent.Start) -} @Composable fun rememberImageAction( From 06523bb5d9fb3afc77cb11814133f681ef156de7 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 10:55:01 +0800 Subject: [PATCH 86/99] update LocalImageLoader --- .../singleton/com/seiko/imageloader/LocalImageLoader.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt index 8a32d43c..2140c7d5 100644 --- a/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt +++ b/image-loader/src/commonMain/singleton/com/seiko/imageloader/LocalImageLoader.kt @@ -3,14 +3,12 @@ package com.seiko.imageloader import androidx.compose.runtime.Composable import androidx.compose.runtime.ProvidedValue import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.runtime.staticCompositionLocalOf import com.seiko.imageloader.cache.memory.MemoryCache import com.seiko.imageloader.component.setupDefaultComponents import com.seiko.imageloader.intercept.InterceptorsBuilder import com.seiko.imageloader.model.ImageResult -// TODO need to update -val LocalImageLoader = staticCompositionLocalOf { error("please provide ImageLoader first.") } +val LocalImageLoader = createImageLoaderProvidableCompositionLocal() // maybe it's no longer needed here expect class ImageLoaderProvidableCompositionLocal { From c5c8c2caee271695ed335f5100a42a4970505318 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 14:36:47 +0800 Subject: [PATCH 87/99] move AutoSizeBox & AutoSizeImage --- .../kotlin/com/seiko/imageloader/demo/scene/Common.kt | 2 +- .../seiko/imageloader/compose/CachedPositionAndSize.kt | 9 --------- .../com/seiko/imageloader/{compose => ui}/AutoSizeBox.kt | 8 +++++++- .../seiko/imageloader/{compose => ui}/AutoSizeImage.kt | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) delete mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt rename image-loader/src/commonMain/kotlin/com/seiko/imageloader/{compose => ui}/AutoSizeBox.kt (97%) rename image-loader/src/commonMain/kotlin/com/seiko/imageloader/{compose => ui}/AutoSizeImage.kt (99%) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index a3dcdfad..3072d89c 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -24,7 +24,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import com.seiko.imageloader.compose.AutoSizeBox +import com.seiko.imageloader.ui.AutoSizeBox import com.seiko.imageloader.demo.model.Image import com.seiko.imageloader.demo.util.NullDataInterceptor import com.seiko.imageloader.demo.util.decodeJson diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt deleted file mode 100644 index 37667ca0..00000000 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/CachedPositionAndSize.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.seiko.imageloader.compose - -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size - -internal data class CachedPositionAndSize( - val position: Offset, - val size: Size, -) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeBox.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeBox.kt similarity index 97% rename from image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeBox.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeBox.kt index 2801af55..ef809b56 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeBox.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeBox.kt @@ -1,4 +1,4 @@ -package com.seiko.imageloader.compose +package com.seiko.imageloader.ui import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -9,6 +9,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.isSpecified import androidx.compose.ui.layout.Measurable @@ -201,3 +202,8 @@ internal fun modifyRequest( request } } + +internal data class CachedPositionAndSize( + val position: Offset, + val size: Size, +) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt similarity index 99% rename from image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt index 07d1588c..8553d7fe 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/compose/AutoSizeImage.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt @@ -1,4 +1,4 @@ -package com.seiko.imageloader.compose +package com.seiko.imageloader.ui import androidx.compose.runtime.Composable import androidx.compose.runtime.RememberObserver From 033481f77e4845b4bd66a74771740de0f482eb16 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 14:37:11 +0800 Subject: [PATCH 88/99] apply spotless --- .../kotlin/com/seiko/imageloader/demo/scene/Common.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt index 3072d89c..74591bbe 100644 --- a/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt +++ b/app/common/src/commonMain/kotlin/com/seiko/imageloader/demo/scene/Common.kt @@ -24,7 +24,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import com.seiko.imageloader.ui.AutoSizeBox import com.seiko.imageloader.demo.model.Image import com.seiko.imageloader.demo.util.NullDataInterceptor import com.seiko.imageloader.demo.util.decodeJson @@ -32,6 +31,7 @@ import com.seiko.imageloader.model.ImageAction import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageRequestBuilder import com.seiko.imageloader.rememberImageSuccessPainter +import com.seiko.imageloader.ui.AutoSizeBox import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext From ab735a8e748a68995454d5202ccb55e38bfb5bce Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 14:53:36 +0800 Subject: [PATCH 89/99] fix ImageLoaderTest --- .../kotlin/com/seiko/imageloader/ImageLoaderTest.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index a63daaa3..437c984e 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -9,6 +9,8 @@ import com.seiko.imageloader.component.fetcher.Fetcher import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageResult +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.runTest import kotlin.test.BeforeTest @@ -65,7 +67,8 @@ class ImageLoaderTest { emit(ImageRequest("2")) emit(ImageRequest("3") { skipEvent = true }) } - imageLoader.async(requestFlow).test { + @OptIn(ExperimentalCoroutinesApi::class) + requestFlow.flatMapLatest { imageLoader.async(it) }.test { // 1 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) From 8dd964ca19a67494e95675cc6a1962e937118b8a Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 15:28:43 +0800 Subject: [PATCH 90/99] ignore Unspecified Size from SizeResolver --- .../commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt index 4b8a682e..3c03125e 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ImageLoader.kt @@ -1,6 +1,7 @@ package com.seiko.imageloader import androidx.compose.runtime.Immutable +import androidx.compose.ui.geometry.isSpecified import com.seiko.imageloader.intercept.InterceptorChainImpl import com.seiko.imageloader.model.ImageAction import com.seiko.imageloader.model.ImageEvent @@ -43,7 +44,9 @@ private class RealImageLoader( } val initialSize = request.sizeResolver.size() val options = Options(config.defaultOptions) { - size = initialSize + if (initialSize.isSpecified) { + size = initialSize + } } val chain = InterceptorChainImpl( initialRequest = request, From 947f3f53c8a5c86a0c14a46d27a862baffb232f4 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 15:29:08 +0800 Subject: [PATCH 91/99] update -Xexpect-actual-classes config --- .../main/kotlin/KotlinMultiplatformConventionPlugin.kt | 8 ++++++++ image-loader/build.gradle.kts | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt index a76e99e5..91d302c2 100644 --- a/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KotlinMultiplatformConventionPlugin.kt @@ -49,6 +49,14 @@ class KotlinMultiplatformConventionPlugin : Plugin { } } } + targets.configureEach { + compilations.configureEach { + compilerOptions.configure { + // https://youtrack.jetbrains.com/issue/KT-61573 + freeCompilerArgs.add("-Xexpect-actual-classes") + } + } + } } configKotlin() } diff --git a/image-loader/build.gradle.kts b/image-loader/build.gradle.kts index 0d6b2dc9..5d95c469 100644 --- a/image-loader/build.gradle.kts +++ b/image-loader/build.gradle.kts @@ -89,13 +89,6 @@ kotlin { kotlin.srcDir("src/$name/singleton") } } - targets.all { - compilations.all { - compilerOptions.configure { - freeCompilerArgs.add("-Xexpect-actual-classes") - } - } - } } @Suppress("UnstableApiUsage") From e70a6b167b303fc1fa80a4b5946b36aabb02efbc Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 15:32:02 +0800 Subject: [PATCH 92/99] fix ImageLoaderTest --- .../kotlin/com/seiko/imageloader/ImageLoaderTest.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt index 437c984e..443fe59d 100644 --- a/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt +++ b/image-loader/src/commonTest/kotlin/com/seiko/imageloader/ImageLoaderTest.kt @@ -9,9 +9,9 @@ import com.seiko.imageloader.component.fetcher.Fetcher import com.seiko.imageloader.model.ImageEvent import com.seiko.imageloader.model.ImageRequest import com.seiko.imageloader.model.ImageResult -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.transform import kotlinx.coroutines.test.runTest import kotlin.test.BeforeTest import kotlin.test.Test @@ -67,8 +67,7 @@ class ImageLoaderTest { emit(ImageRequest("2")) emit(ImageRequest("3") { skipEvent = true }) } - @OptIn(ExperimentalCoroutinesApi::class) - requestFlow.flatMapLatest { imageLoader.async(it) }.test { + requestFlow.transform { emitAll(imageLoader.async(it)) }.test { // 1 assertEquals(ImageEvent.Start, awaitItem()) assertEquals(ImageEvent.StartWithFetch, awaitItem()) From c7bf1ea2003e2fa19aeefbbbb252edd92bf1dfad Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 15:40:25 +0800 Subject: [PATCH 93/99] rename RememberExt file --- .../com/seiko/imageloader/{RememberExt.kt => Remember.ext.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename image-loader/src/commonMain/kotlin/com/seiko/imageloader/{RememberExt.kt => Remember.ext.kt} (100%) diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.ext.kt similarity index 100% rename from image-loader/src/commonMain/kotlin/com/seiko/imageloader/RememberExt.kt rename to image-loader/src/commonMain/kotlin/com/seiko/imageloader/Remember.ext.kt From 092e74dc42e002ba8866ca48bbbb939dca6760b6 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 15:40:37 +0800 Subject: [PATCH 94/99] update app.web config --- app/web/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/web/build.gradle.kts b/app/web/build.gradle.kts index 0f48a320..abc74569 100644 --- a/app/web/build.gradle.kts +++ b/app/web/build.gradle.kts @@ -18,7 +18,7 @@ kotlin { implementation(libs.moko.resources) } } - getByName("jsMain") { + jsMain { // https://github.com/icerockdev/moko-resources/issues/531 dependsOn(commonMain.get()) } From 256e1d2d95cb9fe05ddd56d2f3b2811223f57693 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 16:10:23 +0800 Subject: [PATCH 95/99] add AutoSizeWidget ext --- .../com/seiko/imageloader/ui/AutoSizeImage.kt | 2 +- .../imageloader/ui/AutoSizeWidget.ext.kt | 115 ++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeWidget.ext.kt diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt index 8553d7fe..c3adfec8 100644 --- a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeImage.kt @@ -47,6 +47,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlin.math.roundToInt +// AutoSizeImage ≈ AutoSizeBox + Painter @Composable fun AutoSizeImage( request: ImageRequest, @@ -61,7 +62,6 @@ fun AutoSizeImage( errorPainter: (@Composable () -> Painter)? = null, isOnlyPostFirstEvent: Boolean = true, ) { - // same with @Composable Image(painter) val semantics = if (contentDescription != null) { Modifier.semantics { this.contentDescription = contentDescription diff --git a/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeWidget.ext.kt b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeWidget.ext.kt new file mode 100644 index 00000000..f507ff4d --- /dev/null +++ b/image-loader/src/commonMain/kotlin/com/seiko/imageloader/ui/AutoSizeWidget.ext.kt @@ -0,0 +1,115 @@ +package com.seiko.imageloader.ui + +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.DefaultAlpha +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import com.seiko.imageloader.ImageLoader +import com.seiko.imageloader.LocalImageLoader +import com.seiko.imageloader.model.ImageAction +import com.seiko.imageloader.model.ImageRequest + +@Composable +fun AutoSizeBox( + url: String, + modifier: Modifier = Modifier, + imageLoader: ImageLoader = LocalImageLoader.current, + contentAlignment: Alignment = Alignment.Center, + propagateMinConstraints: Boolean = false, + isOnlyPostFirstEvent: Boolean = true, + content: @Composable BoxScope.(ImageAction) -> Unit, +) { + AutoSizeBox( + request = remember(url) { ImageRequest(url) }, + modifier = modifier, + imageLoader = imageLoader, + contentAlignment = contentAlignment, + propagateMinConstraints = propagateMinConstraints, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, + content = content, + ) +} + +@Composable +fun AutoSizeBox( + resId: Int, + modifier: Modifier = Modifier, + imageLoader: ImageLoader = LocalImageLoader.current, + contentAlignment: Alignment = Alignment.Center, + propagateMinConstraints: Boolean = false, + isOnlyPostFirstEvent: Boolean = true, + content: @Composable BoxScope.(ImageAction) -> Unit, +) { + AutoSizeBox( + request = remember(resId) { ImageRequest(resId) }, + modifier = modifier, + imageLoader = imageLoader, + contentAlignment = contentAlignment, + propagateMinConstraints = propagateMinConstraints, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, + content = content, + ) +} + +@Composable +fun AutoSizeImage( + url: String, + contentDescription: String?, + modifier: Modifier = Modifier, + alignment: Alignment = Alignment.Center, + contentScale: ContentScale = ContentScale.Fit, + alpha: Float = DefaultAlpha, + colorFilter: ColorFilter? = null, + imageLoader: ImageLoader = LocalImageLoader.current, + placeholderPainter: (@Composable () -> Painter)? = null, + errorPainter: (@Composable () -> Painter)? = null, + isOnlyPostFirstEvent: Boolean = true, +) { + AutoSizeImage( + request = remember(url) { ImageRequest(url) }, + contentDescription = contentDescription, + modifier = modifier, + alignment = alignment, + contentScale = contentScale, + alpha = alpha, + colorFilter = colorFilter, + imageLoader = imageLoader, + placeholderPainter = placeholderPainter, + errorPainter = errorPainter, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, + ) +} + +@Composable +fun AutoSizeImage( + resId: Int, + contentDescription: String?, + modifier: Modifier = Modifier, + alignment: Alignment = Alignment.Center, + contentScale: ContentScale = ContentScale.Fit, + alpha: Float = DefaultAlpha, + colorFilter: ColorFilter? = null, + imageLoader: ImageLoader = LocalImageLoader.current, + placeholderPainter: (@Composable () -> Painter)? = null, + errorPainter: (@Composable () -> Painter)? = null, + isOnlyPostFirstEvent: Boolean = true, +) { + AutoSizeImage( + request = remember(resId) { ImageRequest(resId) }, + contentDescription = contentDescription, + modifier = modifier, + alignment = alignment, + contentScale = contentScale, + alpha = alpha, + colorFilter = colorFilter, + imageLoader = imageLoader, + placeholderPainter = placeholderPainter, + errorPainter = errorPainter, + isOnlyPostFirstEvent = isOnlyPostFirstEvent, + ) +} From 7bf5fce38827d5fdf2d8c66eb8e9e825a50efcd3 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 16:10:37 +0800 Subject: [PATCH 96/99] update README.md --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a72dfc00..534bc215 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,25 @@ fun Content() { CompositionLocalProvider( LocalImageLoader provides remember { generateImageLoader() }, ) { + // Option 1 on 1.7.0+ + AutoSizeImage( + "https://...", + contentDescription = "image", + ) + // Option 2 on 1.7.0+ + AutoSizeBox("https://...") { action -> + when (action) { + is ImageAction.Success -> { + Image( + rememberImageSuccessPainter(action), + contentDescription = "image", + ) + } + is ImageAction.Loading -> {} + is ImageAction.Failure -> {} + } + } + // Option 3 val painter = rememberImagePainter("https://..") Image( painter = painter, @@ -67,9 +86,13 @@ fun Content() { } ``` +Use priority: `AutoSizeImage` -> `AutoSizeBox` -> `rememberImagePainter`. + +`AutoSizeBox` & `AutoSizeImage` are based on **Modifier.Node**, `AutoSizeImage` ≈ `AutoSizeBox` + `Painter`. + #### in Android -```kotlin title="MainActivity.kt" +```kotlin fun generateImageLoader(): ImageLoader { return ImageLoader { options { @@ -96,7 +119,7 @@ fun generateImageLoader(): ImageLoader { #### in Jvm -```kotlin title="Main.kt" +```kotlin fun generateImageLoader(): ImageLoader { return ImageLoader { components { From 0aefd224fe4c809ae4bf1f3ff1b513b77308624b Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 16:57:32 +0800 Subject: [PATCH 97/99] version to 1.7.0 --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f84e74bf..54bef2f7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -87,10 +87,10 @@ object ProjectVersion { private const val major = "1" // functionality in a backwards compatible manner - private const val monir = "6" + private const val monir = "7" // backwards compatible bug fixes - private const val path = "8" + private const val path = "0" const val version = "$major.$monir.$path" } From 7713e9e329dbb5b0987031be79d53c367cbfdf33 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 17:39:45 +0800 Subject: [PATCH 98/99] update docs --- README.md | 11 +++++----- docs/docs/core/basic.md | 40 ++++++++++++++++++++++++++++------- docs/docs/core/imageloader.md | 37 +++++++++++++++++++------------- docs/docs/setup.mdx | 10 ++++----- 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 534bc215..bd616703 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,17 @@ kotlin { sourceSets { val commonMain by getting { dependencies { -+ api("io.github.qdsfdhvh:image-loader:1.6.8") ++ api("io.github.qdsfdhvh:image-loader:1.7.0") // optional - Moko Resources Decoder -+ api("io.github.qdsfdhvh:image-loader-extension-moko-resources:1.6.8") ++ api("io.github.qdsfdhvh:image-loader-extension-moko-resources:1.7.0") // optional - Blur Interceptor (only support bitmap) -+ api("io.github.qdsfdhvh:image-loader-extension-blur:1.6.8") ++ api("io.github.qdsfdhvh:image-loader-extension-blur:1.7.0") } } val jvmMain by getting { dependencies { // optional - ImageIO Decoder -+ api("io.github.qdsfdhvh:image-loader-extension-imageio:1.6.8") ++ api("io.github.qdsfdhvh:image-loader-extension-imageio:1.7.0") } } } @@ -77,9 +77,8 @@ fun Content() { } } // Option 3 - val painter = rememberImagePainter("https://..") Image( - painter = painter, + painter = rememberImagePainter("https://.."), contentDescription = "image", ) } diff --git a/docs/docs/core/basic.md b/docs/docs/core/basic.md index 65b09eff..1d1684e5 100644 --- a/docs/docs/core/basic.md +++ b/docs/docs/core/basic.md @@ -5,13 +5,35 @@ Just use it like this for display image: ```kotlin -val painter = rememberImagePainter("https://..") +// Option 1 on 1.7.0+ +AutoSizeImage( + "https://...", + contentDescription = "image", +) +// Option 2 on 1.7.0+ +AutoSizeBox("https://...") { action -> + when (action) { + is ImageAction.Success -> { + Image( + rememberImageSuccessPainter(action), + contentDescription = "image", + ) + } + is ImageAction.Loading -> {} + is ImageAction.Failure -> {} + } +} +// Option 3 Image( - painter = painter, + painter = rememberImagePainter("https://.."), contentDescription = "image", ) ``` +Use priority: `AutoSizeImage` -> `AutoSizeBox` -> `rememberImagePainter`. + +`AutoSizeBox` & `AutoSizeImage` are based on **Modifier.Node**, `AutoSizeImage` ≈ `AutoSizeBox` + `Painter`. + PS: default `Imageloader` will reload when it's displayed, is not friendly for `https` link, so it is recommended to custom `ImageLoader` and configure the cache. ## Custom ImageLoader @@ -24,11 +46,7 @@ fun Content() { CompositionLocalProvider( LocalImageLoader provides remember { generateImageLoader() }, ) { - val painter = rememberImagePainter("https://..") - Image( - painter = painter, - contentDescription = "image", - ) + // App } } ``` @@ -45,6 +63,8 @@ fun generateImageLoader(): ImageLoader { setupDefaultComponents() } interceptor { + // cache 100 success image result, without bitmap + defaultImageResultMemoryCache() memoryCacheConfig { // Set the max size to 25% of the app's available memory. maxSizePercent(context, 0.25) @@ -67,6 +87,8 @@ fun generateImageLoader(): ImageLoader { setupDefaultComponents() } interceptor { + // cache 100 success image result, without bitmap + defaultImageResultMemoryCache() memoryCacheConfig { maxSizeBytes(32 * 1024 * 1024) // 32MB } @@ -95,7 +117,9 @@ fun generateImageLoader(): ImageLoader { components { setupDefaultComponents() } - interceptor { + interceptor { + // cache 100 success image result, without bitmap + defaultImageResultMemoryCache() memoryCacheConfig { maxSizeBytes(32 * 1024 * 1024) // 32MB } diff --git a/docs/docs/core/imageloader.md b/docs/docs/core/imageloader.md index 45729a31..aeacc8b2 100644 --- a/docs/docs/core/imageloader.md +++ b/docs/docs/core/imageloader.md @@ -11,22 +11,30 @@ interface ImageLoader { `ImageAction` structure is as follows: ```kotlin -sealed interface ImageAction - -sealed interface ImageEvent : ImageAction { - object Start : ImageEvent - object StartWithMemory : ImageEvent - object StartWithDisk : ImageEvent - object StartWithFetch : ImageEvent - data class Progress(val progress: Float) : ImageEvent +sealed interface ImageAction { + sealed interface Loading : ImageAction + sealed interface Success : ImageAction + sealed interface Failure : ImageAction { + val error: Throwable + } +} + +sealed interface ImageEvent : ImageAction.Loading { + data object Start : ImageEvent + data object StartWithMemory : ImageEvent + data object StartWithDisk : ImageEvent + data object StartWithFetch : ImageEvent } sealed interface ImageResult : ImageAction { - data class Source() : ImageResult - data class Bitmap() : ImageResult - data class Image() : ImageResult - data class Painter() : ImageResult - data class Error() : ImageResult + data class OfBitmap() : ImageResult, ImageAction.Success + data class OfImage() : ImageResult, ImageAction.Success + data class OfPainter() :ImageResult, ImageAction.Success + data class OfError(override val error: Throwable) : ImageResult, ImageAction.Failure + data class OfSource() : ImageResult, ImageAction.Failure { + override val error: Throwable + get() = IllegalStateException("failure to decode image source") + } } ``` @@ -35,7 +43,7 @@ sealed interface ImageResult : ImageAction { This is the most center feature of `ImageLoader`, The loading of the entire image is implemented by the default 3 + 2 interceptors: - **MappedInterceptor** -- MemoryCacheInterceptor +- MemoryCacheInterceptors - **DecodeInterceptor** - DiskCacheInterceptor - **FetchInterceptor** @@ -95,7 +103,6 @@ ImageLoader { retryIfDiskDecodeError = true imageConfig = Options.ImageConfig.ARGB_8888 scale = Scale.AUTO - sizeResolver = SizeResolver.Unspecified memoryCachePolicy = CachePolicy.ENABLED diskCachePolicy = CachePolicy.ENABLED playAnimate = true diff --git a/docs/docs/setup.mdx b/docs/docs/setup.mdx index 1aaa4f2a..5edce839 100644 --- a/docs/docs/setup.mdx +++ b/docs/docs/setup.mdx @@ -15,17 +15,17 @@ kotlin { sourceSets { val commonMain by getting { dependencies { -+ api("io.github.qdsfdhvh:image-loader:1.6.8") ++ api("io.github.qdsfdhvh:image-loader:1.7.0") // optional - Moko Resources Decoder -+ api("io.github.qdsfdhvh:image-loader-extension-moko-resources:1.6.8") ++ api("io.github.qdsfdhvh:image-loader-extension-moko-resources:1.7.0") // optional - Blur Interceptor (only support bitmap) -+ api("io.github.qdsfdhvh:image-loader-extension-blur:1.6.8") ++ api("io.github.qdsfdhvh:image-loader-extension-blur:1.7.0") } } val jvmMain by getting { dependencies { // optional - ImageIO Decoder -+ api("io.github.qdsfdhvh:image-loader-extension-imageio:1.6.8") ++ api("io.github.qdsfdhvh:image-loader-extension-imageio:1.7.0") } } } @@ -38,7 +38,7 @@ Copy the following snippets if you are using [gradle version catalog](https://do ```xml title="libs.versions.toml" [versions] -image-loader = "1.6.1" +image-loader = "1.7.0" [libraries] image-loader = { module = "io.github.qdsfdhvh:image-loader", version.ref = "image-loader" } From d0f5f6beef5f8b52b5ffccc3220c2b43efd0e3d3 Mon Sep 17 00:00:00 2001 From: seiko Date: Sun, 5 Nov 2023 17:41:01 +0800 Subject: [PATCH 99/99] update docs --- docs/src/pages/index.mdx | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/src/pages/index.mdx b/docs/src/pages/index.mdx index b67889ac..66212ae8 100644 --- a/docs/src/pages/index.mdx +++ b/docs/src/pages/index.mdx @@ -11,9 +11,27 @@ ```kotlin @Composeable fun Content() { - val painter = rememberImagePainter("https://...") + // Option 1 on 1.7.0+ + AutoSizeImage( + "https://...", + contentDescription = "image", + ) + // Option 2 on 1.7.0+ + AutoSizeBox("https://...") { action -> + when (action) { + is ImageAction.Success -> { + Image( + rememberImageSuccessPainter(action), + contentDescription = "image", + ) + } + is ImageAction.Loading -> {} + is ImageAction.Failure -> {} + } + } + // Option 3 Image( - painter = painter, + painter = rememberImagePainter("https://.."), contentDescription = "image", ) }