Code Monkey home page Code Monkey logo

kamel's Introduction

Kamel

Version Snapshot License Kotlin Compose Multiplatform

Kamel is an asynchronous media loading library for Compose Multiplatform. It provides a simple, customizable and efficient way to load, cache, decode and display images in your application. By default, it uses Ktor client for loading resources.

Table of contents

Setup

Kamel is published on Maven Central:

repositories {
    mavenCentral()
    // ...
}

Multi-platform

Add the dependency to the common source-set:

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation("media.kamel:kamel-image:0.9.5")
                // ...
            }
        }
    }
}

Single-platform

Add the dependency to the dependencies block:

dependencies {
    implementation("media.kamel:kamel-image:0.9.5")
    // ...
}

Ktor HttpClient Engine

Make sure to add a dependency for Ktor HttpClient engine for your platforms using this link.

Usage

Loading an image resource

To load an image asynchronously, you can use asyncPainterResource composable, it can load images from different data sources:

// String
asyncPainterResource(data = "https://www.example.com/image.jpg")

// Ktor Url
asyncPainterResource(data = Url("https://www.example.com/image.jpg"))

// URI
asyncPainterResource(data = URI("https://www.example.com/image.png"))

// File (JVM, Native)
asyncPainterResource(data = File("/path/to/image.png"))

// File (JS)
asyncPainterResource(data = File(org.w3c.files.File(arrayOf(blob), "/path/to/image.png")))

// URL
asyncPainterResource(data = URL("https://www.example.com/image.jpg"))

// and more...

asyncPainterResource can be used to load SVG, XML, JPEG, and PNG by default depending on the platform implementation.

asyncPainterResource returns a Resource<Painter> object which can be used to display the image using KamelImage composable.

Platform specific implementations

Since there isn't any shared resource system between Android and Desktop, some implementations (e.g. fetchers and mappers) are only available for a specific platform:

Desktop only implementations

To load an image file from desktop application resources, you have to add resourcesFetcher to the KamelConfig:

val desktopConfig = KamelConfig {
    takeFrom(KamelConfig.Default)
    // Available only on Desktop.
    resourcesFetcher()
    // Available only on Desktop.
    // An alternative svg decoder
    batikSvgDecoder()
}

Assuming there's an image.png file in the /resources directory in the project:

CompositionLocalProvider(LocalKamelConfig provides desktopConfig) {
    asyncPainterResource("image.png")
}

Android only implementations

To load an image file from android application resources, you have to add resourcesFetcher and resourcesIdMapper to the KamelConfig:

val context: Context = LocalContext.current

val androidConfig = KamelConfig {
    takeFrom(KamelConfig.Default)
    // Available only on Android.
    resourcesFetcher(context)
    // Available only on Android.
    resourcesIdMapper(context)
}

Assuming there's an image.png file in the /res/raw directory in the project:

CompositionLocalProvider(LocalKamelConfig provides androidConfig) {
    asyncPainterResource(R.raw.image)
}

Configuring an image resource

asyncPainterResource supports configuration using a trailing lambda:

val painterResource: Resource<Painter> = asyncPainterResource("https://www.example.com/image.jpg") {

    // CoroutineContext to be used while loading the image.
    coroutineContext = Job() + Dispatcher.IO

    // Customizes HTTP request
    requestBuilder { // this: HttpRequestBuilder
        header("Key", "Value")
        parameter("Key", "Value")
        cacheControl(CacheControl.MAX_AGE)
    }

}

Displaying an image resource

KamelImage is a composable function that takes a Resource<Painter> object, display it and provide extra functionality:

KamelImage(
    resource = painterResource,
    contentDescription = "Profile",
)

KamelImage can also be used to get the exception using onFailure, and progress using onLoading parameters, to display a snackbar or a progress indicator, depending on the case:

val coroutineScope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Box {
    KamelImage(
        resource = painterResource,
        contentDescription = "Profile",
        onLoading = { progress -> CircularProgressIndicator(progress) },
        onFailure = { exception ->
            coroutineScope.launch {
                snackbarHostState.showSnackbar(
                    message = exception.message.toString(),
                    actionLabel = "Hide",
                    duration = SnackbarDuration.Short
                )
            }
        }
    )
    SnackbarHost(hostState = snackbarHostState, modifier = Modifier.padding(16.dp))
}

You can also provide your own custom implementation using a simple when expression:

when (val resource = asyncPainterResource("https://www.example.com/image.jpg")) {
    is Resource.Loading -> {
        Text("Loading...")
    }
    is Resource.Success -> {
        val painter: Painter = resource.value
        Image(painter, contentDescription = "Profile")
    }
    is Resource.Failure -> {
        log(resource.exception)
        val fallbackPainter = painterResource("/path/to/fallbackImage.jpg")
        Image(fallbackPainter, contentDescription = "Profile")
    }
}

Crossfade animation

You can enable, disable or customize crossfade (fade-in) animation through the animationSpec parameter. Setting animationSpec to null will disable the animation:

KamelImage(
    resource = imageResource,
    contentDescription = "Profile",
    // null by default
    animationSpec = tween(),
)

Configuring Kamel

The default implementation is KamelConfig.Default. If you wish to configure it, you can do it the following way:

val customKamelConfig = KamelConfig {
    // Copies the default implementation if needed
    takeFrom(KamelConfig.Default)

    // Sets the number of images to cache
    imageBitmapCacheSize = DefaultCacheSize

    // adds an ImageBitmapDecoder
    imageBitmapDecoder()

    // adds an ImageVectorDecoder (XML)
    imageVectorDecoder()

    // adds an SvgDecoder (SVG)
    svgDecoder()

    // adds a FileFetcher
    fileFetcher()

    // Configures Ktor HttpClient
    httpFetcher {
        // httpCache is defined in kamel-core and configures the ktor client 
        // to install a HttpCache feature with the implementation provided by Kamel.
        // The size of the cache can be defined in Bytes.
        httpCache(10 * 1024 * 1024  /* 10 MiB */)

        defaultRequest {
            url("https://www.example.com/")
            cacheControl(CacheControl.MaxAge(maxAgeSeconds = 10000))
        }

        install(HttpRequestRetry) {
            maxRetries = 3
            retryIf { httpRequest, httpResponse ->
                !httpResponse.status.isSuccess()
            }
        }
        
        // Requires adding "io.ktor:ktor-client-logging:$ktor_version"
        Logging {
            level = LogLevel.INFO
            logger = Logger.SIMPLE
        }
    }

    // more functionality available.
}

Memory cache size (number of entries to cache)

Kamel provides a generic Cache<K,V> interface, the default implementation uses LRU memory cache mechanism backed by LinkedHashMap. You can provide a number of entries to cache for each type like so:

KamelConfig {
    // 100 by default
    imageBitmapCacheSize = 500
    // 100 by default
    imageVectorCacheSize = 300
    // 100 by default
    svgCacheSize = 200
}

Disk cache size (in bytes)

Kamel can create a persistent disk cache for images by implementing ktor's CacheStorage feature. The default config KamelConfig.Default installs this feature with a 10 MiB disk cache size. The underlying disk cache is based on coil's multiplatform DiskLruCache implementation.

KamelConfig {
    httpFetcher {
        // The size of the cache can be defined in bytes. Or DefaultHttpCacheSize (10 MiB) can be used. 
        httpCache(DefaultHttpCacheSize)
    }
}

Applying Kamel configuration

You can use LocalKamelConfig to apply your custom configuration:

CompositionLocalProvider(LocalKamelConfig provides customKamelConfig) {
    asyncPainterResource("image.jpg")
}

Contributions

Contributions are always welcome!. If you'd like to contribute, please feel free to create a PR or open an issue.

License

Copyright 2021 Ali Albaali

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

kamel's People

Contributors

alex009 avatar alialbaali avatar christiandeange avatar cmota avatar datl4g avatar iruizmar avatar kamiox avatar luca992 avatar outadoc avatar psuzn avatar sebastianaigner avatar syer10 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kamel's Issues

Add persistent cache

Perhaps it would be worth adding image caching to the device memory so that you can always access them without a network?

Add js support

Hello

Compose-jb is adding support for web foundation and material libraries.

I want to share all of my code across platforms (jvm ,android, web) and this library doesn't support js yet.

I think it's a good point to start implementing it until release of the stable compose release.

1.2.0-alpha01-dev620 adds support for js, should be enough to start implementing a solution for js.

Unable to load image on IOS physical device with kamel v 0.8.0

I am unable to get image loading on a physical IOS device with version kamel 0.8.0 even though it works on Emulator.
However everything works for versions <= 0.7.3

From this https://github.com/JetBrains/compose-multiplatform-ios-android-template, i added the following dependencies:

  • Ktor
  • kamel
okio.IOException: Operation not permitted
    at 0   My application                      0x10023c6bb        kfun:kotlin.Exception#<init>(kotlin.String?;kotlin.Throwable?){} + 147 
    at 1   My application                      0x100c6b75f        kfun:okio.IOException#<init>(kotlin.String?;kotlin.Throwable?){} + 147 
    at 2   My application                      0x100c6b7ef        kfun:okio.IOException#<init>(kotlin.String?){} + 123 
    at 3   My application                      0x100c50f5b        kfun:okio#errnoToIOException(kotlin.Int){}okio.IOException + 523 
    at 4   My application                      0x100c7b48b        kfun:okio#variantSink__at__okio.PosixFileSystem(okio.Path;kotlin.Boolean){}okio.Sink + 715 
    at 5   My application                      0x100c557cf        kfun:okio.PosixFileSystem#sink(okio.Path;kotlin.Boolean){}okio.Sink + 199 
    at 6   My application                      0x100c3b76b        kfun:okio.ForwardingFileSystem#sink(okio.Path;kotlin.Boolean){}okio.Sink + 327 
    at 7   My application                      0x100c9ba87        kfun:io.kamel.core.cache.disk.DiskLruCache.object-1.sink#internal + 327 
    at 8   My application                      0x100c91cbb        kfun:io.kamel.core.cache.disk.DiskLruCache.writeJournal#internal + 1135 
    at 9   My application                      0x100c8f41b        kfun:io.kamel.core.cache.disk.DiskLruCache.initialize#internal + 1455 
    at 10  My application                      0x100c932ab        kfun:io.kamel.core.cache.disk.DiskLruCache#get(kotlin.String){}io.kamel.core.cache.disk.DiskLruCache.Snapshot? + 551 
    at 11  My application                      0x100c89657        kfun:io.kamel.core.cache.disk.DiskCacheStorage#find#suspend(io.ktor.http.Url;kotlin.collections.Map<kotlin.String,kotlin.String>;kotlin.coroutines.Continuation<io.ktor.client.plugins.cache.storage.CachedResponseData?>){}kotlin.Any? + 615 
    at 12  My application                      0x100c8a10f        kfun:io.kamel.core.cache.disk.DiskCacheStorage.$findAllCOROUTINE$0.invokeSuspend#internal + 511 
    at 13  My application                      0x100c8a477        kfun:io.kamel.core.cache.disk.DiskCacheStorage#findAll#suspend(io.ktor.http.Url;kotlin.coroutines.Continuation<kotlin.collections.Set<io.ktor.client.plugins.cache.storage.CachedResponseData>>){}kotlin.Any + 315 
    at 14  My application                      0x100c07a3b        kfun:io.ktor.client.plugins.cache.HttpCache.$findResponseCOROUTINE$7.invokeSuspend#internal + 1871 
    at 15  My application                      0x100c087bf        kfun:io.ktor.client.plugins.cache.HttpCache.findResponse#internal.601 + 415 
    at 16  My application                      0x100c01737        kfun:io.ktor.client.plugins.cache.HttpCache.Companion.$install$lambda$0COROUTINE$3.invokeSuspend#internal + 1935 
    at 17  My application                      0x100c0294f        kfun:io.ktor.client.plugins.cache.HttpCache.Companion.install$lambda$0#internal + 395 
    at 18  My application                      0x100c04003        kfun:io.ktor.client.plugins.cache.HttpCache.Companion.$install$lambda$0$FUNCTION_REFERENCE$0.invoke#internal + 191 
    at 19  My application                      0x100b813f7        kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1063 
    at 20  My application                      0x100b80beb        kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceed#suspend(kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 511 
    at 21  My application                      0x100b80f87        kfun:io.ktor.util.pipeline.SuspendFunctionGun#execute#suspend(1:0;kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 563 
    at 22  My application                      0x100b7bd7b        kfun:io.ktor.util.pipeline.Pipeline#execute#suspend(1:1;1:0;kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 427 
    at 23  My application                      0x100bf8b3f        kfun:io.ktor.client.plugins.HttpSend.DefaultSender.$executeCOROUTINE$1.invokeSuspend#internal + 1187 
    at 24  My application                      0x100bf8f37        kfun:io.ktor.client.plugins.HttpSend.DefaultSender.execute#internal + 315 
    at 25  My application                      0x100bf3423        kfun:io.ktor.client.plugins.HttpRedirect.Plugin.$install$lambda$0COROUTINE$1.invokeSuspend#internal + 587 
    at 26  My application                      0x100bf3abb        kfun:io.ktor.client.plugins.HttpRedirect.Plugin.install$lambda$0#internal + 395 
    at 27  My application                      0x100bf3bc3        kfun:io.ktor.client.plugins.HttpRedirect.Plugin.$install$lambda$0$FUNCTION_REFERENCE$0.invoke#internal + 191 
    at 28  My application                      0x100bf8133        kfun:io.ktor.client.plugins.HttpSend.InterceptedSender.execute#internal + 335 
    at 29  My application                      0x100bea163        kfun:io.ktor.client.plugins.HttpCallValidator.Companion.$install$lambda$3COROUTINE$2.invokeSuspend#internal + 587 
    at 30  My application                      0x100bea613        kfun:io.ktor.client.plugins.HttpCallValidator.Companion.install$lambda$3#internal + 363 
    at 31  My application                      0x100beaa1f        kfun:io.ktor.client.plugins.HttpCallValidator.Companion.$install$lambda$3$FUNCTION_REFERENCE$2.invoke#internal + 187 
    at 32  My application                      0x100bf8133        kfun:io.ktor.client.plugins.HttpSend.InterceptedSender.execute#internal + 335 
    at 33  My application                      0x100bf7737        kfun:io.ktor.client.plugins.HttpSend.Plugin.$install$lambda$0COROUTINE$0.invokeSuspend#internal + 2871 
    at 34  My application                      0x100bf7be3        kfun:io.ktor.client.plugins.HttpSend.Plugin.install$lambda$0#internal + 395 
    at 35  My application                      0x100bf7ceb        kfun:io.ktor.client.plugins.HttpSend.Plugin.$install$lambda$0$FUNCTION_REFERENCE$0.invoke#internal + 191 
    at 36  My application                      0x100b813f7        kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1063 
    at 37  My application                      0x100b80beb        kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceed#suspend(kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 511 
    at 38  My application                      0x100b80d2b        kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceedWith#suspend(1:0;kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 171 
    at 39  My application                      0x100be8f7b        kfun:io.ktor.client.plugins.HttpCallValidator.Companion.$install$lambda$1COROUTINE$0.invokeSuspend#internal + 819 
    at 40  My application                      0x100be94bb        kfun:io.ktor.client.plugins.HttpCallValidator.Companion.install$lambda$1#internal + 363 
    at 41  My application                      0x100bea717        kfun:io.ktor.client.plugins.HttpCallValidator.Companion.$install$lambda$1$FUNCTION_REFERENCE$0.invoke#internal + 187 
    at 42  My application                      0x100b813f7        kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1063 
    at 43  My application                      0x100b80beb        kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceed#suspend(kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 511 
    at 44  My application                      0x100bf4c1f        kfun:io.ktor.client.plugins.HttpRequestLifecycle.Plugin.$install$lambda$0COROUTINE$0.invokeSuspend#internal + 1015 
    at 45  My application                      0x100bf520f        kfun:io.ktor.client.plugins.HttpRequestLifecycle.Plugin.install$lambda$0#internal + 363 
    at 46  My application                      0x100bf5313        kfun:io.ktor.client.plugins.HttpRequestLifecycle.Plugin.$install$lambda$0$FUNCTION_REFERENCE$0.invoke#internal + 187 
    at 47  My application                      0x100b813f7        kfun:io.ktor.util.pipeline.SuspendFunctionGun.loop#internal + 1063 
    at 48  My application                      0x100b80beb        kfun:io.ktor.util.pipeline.SuspendFunctionGun#proceed#suspend(kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 511 
    at 49  My application                      0x100b80f87        kfun:io.ktor.util.pipeline.SuspendFunctionGun#execute#suspend(1:0;kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 563 
    at 50  My application                      0x100b7bd7b        kfun:io.ktor.util.pipeline.Pipeline#execute#suspend(1:1;1:0;kotlin.coroutines.Continuation<1:0>){}kotlin.Any + 427 
    at 51  My application                      0x100bc865f        kfun:io.ktor.client.HttpClient.$executeCOROUTINE$0.invokeSuspend#internal + 603 
    at 52  My application                      0x100bc893b        kfun:io.ktor.client.HttpClient#execute#suspend(io.ktor.client.request.HttpRequestBuilder;kotlin.coroutines.Continuation<io.ktor.client.call.HttpClientCall>){}kotlin.Any + 315 
    at 53  My application                      0x100c2726f        kfun:io.ktor.client.statement.HttpStatement.$executeUnsafeCOROUTINE$3.invokeSuspend#internal + 615 
    at 54  My application                      0x100c275b7        kfun:io.ktor.client.statement.HttpStatement#executeUnsafe#suspend(kotlin.coroutines.Continuation<io.ktor.client.statement.HttpResponse>){}kotlin.Any + 283 
    at 55  My application                      0x100c2659b        kfun:io.ktor.client.statement.HttpStatement.$executeCOROUTINE$0.invokeSuspend#internal + 727 
    at 56  My application                      0x100c26e47        kfun:io.ktor.client.statement.HttpStatement#execute#suspend(kotlin.coroutines.SuspendFunction1<io.ktor.client.statement.HttpResponse,0:0>;kotlin.coroutines.Continuation<0:0>){0ยง<kotlin.Any?>}kotlin.Any? + 315 
    at 57  My application                      0x100c26f13        kfun:io.ktor.client.statement.HttpStatement#execute#suspend(kotlin.coroutines.Continuation<io.ktor.client.statement.HttpResponse>){}kotlin.Any + 135 
    at 58  My application                      0x100ca003b        kfun:io.kamel.core.fetcher.HttpFetcher.$fetch$lambda$1COROUTINE$0.invokeSuspend#internal + 1143 
    at 59  My application                      0x100ca06bb        kfun:io.kamel.core.fetcher.HttpFetcher.fetch$lambda$1#internal + 395 
    at 60  My application                      0x100ca07ab        kfun:io.kamel.core.fetcher.HttpFetcher.$fetch$lambda$1$FUNCTION_REFERENCE$0.invoke#internal + 167 
    at 61  My application                      0x1003f0edf        kfun:kotlinx.coroutines.flow.ChannelFlowBuilder.collectTo#internal + 303 
    at 62  My application                      0x100403a5f        kfun:kotlinx.coroutines.flow.internal.ChannelFlow.<get-collectToFun>$lambda$0#internal + 171 
    at 63  My application                      0x100403c8f        kfun:kotlinx.coroutines.flow.internal.ChannelFlow.$<get-collectToFun>$lambda$0$FUNCTION_REFERENCE$1.invoke#internal + 159 
    at 64  My application                      0x10024b90f        kfun:kotlin.coroutines.intrinsics.object-3.invokeSuspend#internal + 799 
    at 65  My application                      0x100248a87        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 651 
    at 66  My application                      0x1004128b7        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 2715 
    at 67  My application                      0x100415f97        kfun:kotlinx.coroutines.internal.LimitedDispatcher.Worker.run#internal + 307 
    at 68  My application                      0x10044442f        kfun:kotlinx.coroutines.MultiWorkerDispatcher.$workerRunLoop$lambda$2COROUTINE$0.invokeSuspend#internal + 2591 
    at 69  My application                      0x100248a87        kfun:kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(kotlin.Result<kotlin.Any?>){} + 651 
    at 70  My application                      0x1004128b7        kfun:kotlinx.coroutines.DispatchedTask#run(){} + 2715 
    at 71  My application                      0x1003a584f        kfun:kotlinx.coroutines.EventLoopImplBase#processNextEvent(){}kotlin.Long + 1431 
    at 72  My application                      0x10043ac83        kfun:kotlinx.coroutines.BlockingCoroutine.joinBlocking#internal + 483 
    at 73  My application                      0x10043a43f        kfun:kotlinx.coroutines#runBlocking(kotlin.coroutines.CoroutineContext;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>){0ยง<kotlin.Any?>}0:0 + 1615 
    at 74  My application                      0x10043a67b        kfun:kotlinx.coroutines#runBlocking$default(kotlin.coroutines.CoroutineContext?;kotlin.coroutines.SuspendFunction1<kotlinx.coroutines.CoroutineScope,0:0>;kotlin.Int){0ยง<kotlin.Any?>}0:0 + 271 
    at 75  My application                      0x100441e13        kfun:kotlinx.coroutines.MultiWorkerDispatcher.workerRunLoop#internal + 203 
    at 76  My application                      0x10044366f        kfun:kotlinx.coroutines.MultiWorkerDispatcher.<init>$lambda$1$lambda$0#internal + 91 
    at 77  My application                      0x100444d6f        kfun:kotlinx.coroutines.MultiWorkerDispatcher.$<init>$lambda$1$lambda$0$FUNCTION_REFERENCE$5.invoke#internal + 95 
    at 78  My application                      0x100444e83        kfun:kotlinx.coroutines.MultiWorkerDispatcher.$<init>$lambda$1$lambda$0$FUNCTION_REFERENCE$5.$<bridge-UNN>invoke(){}#internal + 95 
    at 79  My application                      0x100256437        WorkerLaunchpad + 195 
    at 80  My application                      0x10100ee93        _ZN6Worker19processQueueElementEb + 2603 
    at 81  My application                      0x10100e30b        _ZN12_GLOBAL__N_113workerRoutineEPv + 219 
    at 82  libsystem_pthread.dylib             0x21ab9a4d3        _pthread_start + 135 
    at 83  libsystem_pthread.dylib             0x21ab99a0f        thread_start + 7 

Crash with try/catch in loadImage*Resource

If a operation is cancelled then it crashes the whole application. I can fix this in a PR pretty easily, so I will submit one soon.

java.lang.IllegalStateException: Flow exception transparency is violated:
    Previous 'emit' call has thrown exception kotlinx.coroutines.JobCancellationException: ScopeCoroutine is cancelling; job=ScopeCoroutine{Cancelled}@611efa09, but then emission attempt of value 'Failure(exception=io.ktor.utils.io.charsets.MalformedInputException: Input length = 1)' has been detected.
    Emissions from 'catch' blocks are prohibited in order to avoid unspecified behaviour, 'Flow.catch' operator can be used instead.
    For a more detailed explanation, please refer to Flow documentation.
	at kotlinx.coroutines.flow.internal.SafeCollector.exceptionTransparencyViolated(SafeCollector.kt:123) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.flow.internal.SafeCollector.checkContext(SafeCollector.kt:86) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.flow.internal.SafeCollector.emit(SafeCollector.kt:74) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.flow.internal.SafeCollector.emit(SafeCollector.kt:59) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at io.kamel.core.ImageLoadingKt$loadImageBitmapResource$1.invokeSuspend(ImageLoading.kt:38) ~[kamel-core-jvm-0.3.0-2477871edd7fe8212ada30a4ce4fd246.jar:?]
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ~[kotlin-stdlib-1.6.10-c8ad75ca9e878d58128a377dded62d32.jar:1.6.10-release-923(1.6.10)]
	at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:33) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46) ~[kotlin-stdlib-1.6.10-c8ad75ca9e878d58128a377dded62d32.jar:1.6.10-release-923(1.6.10)]
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:39) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) ~[kotlinx-coroutines-core-jvm-1.6.0-1be8331acfc1add3a0362630f747944e.jar:?]

lazyImageResource error on Compose for Desktop (JVM) with latest Compose builds

Trying to use lazyImageResource() with Compose Desktop builds 0.4.0-build190 and above will throw
Exception in thread "AWT-EventQueue-0 @coroutine#3" java.lang.NoSuchMethodError: 'void androidx.compose.runtime.Composer.startReplaceableGroup(int, java.lang.String)'

Seems to be related to the launch of Compose 1.0.0-beta07 which comes with the following note:

Note: Libraries dependent on Compose will need to recompile with version 1.0.0โ€‘beta07. Otherwise, libraries may encounter a NoSuchMethodError, such as:
java.lang.NoSuchMethodError: No interface method startReplaceableGroup(ILjava/lang/String;)V in class Landroidx/compose/runtime/Composer; or its super classes. (Ia34e6)

god,i find you

god man, i cant believe this is a image load library for desktop, i try my best to find a image loading library for desktop for a long time, at last i see your library in others project, so i come here.
please update introduction in github search, let more people see these image loading library for compose for desktop

Support for Content scheme URIs for Android

Content URIs (android.net.Uri) do not work on Android (tested on Android 13). I also tried to convert android.net.Uri to a string then back to java.net.Uri, that doesn't work either. I believe this has not been implemented yet, probably because Content URIs require Context.

Typically, the Content URI is used to retrieve a bitmap like this (which as you can see, uses a Context) :

context, imageUri ->
val bitmap: Bitmap
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    val source = ImageDecoder.createSource(context.contentResolver, imageUri)
    bitmap = ImageDecoder.decodeBitmap(source)
} else {
    bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, imageUri)
}

I haven't dived into Kamel's source code, so I know little to none about how everything is implemented. However, in Compose multiplatform, the API exposes a ImageBitmap which is platform-agnostic. On Android side, we can use Bitmap.asimageBitmap() extension function to convert an Android's Bitmap into Compose ImageBitmap.

In androidMain, we can also retrieve a Context using LocalContext.current.

In a Compose multiplatform app, I encountered the use-case where i have to use a KamelImage to show data from an Uri, but that Uri can either be an Uri that points to a Content scheme URI if I am on Android, or a remote URI if I am on iOS.

Update compose-jb and kotlin version

Hi all, Thanks for this library, which is helpful, if you can update je-compose 1.3.0-beta04-dev873 to and Kotlin to 1.7.20 ,
because there is a crash when attempting to load a PNG image
val painterResource: Resource<Painter> = lazyPainterResource("https://cdn-bjkcl.nitrocdn.com/ZfEHGrbhkMgKTiTsiXTlOoOZBeNqAgPw/assets/static/optimized/rev-e4ff0d1/wp-content/uploads/2018/10/practice.png")
Error
java.lang.IllegalArgumentException: Failed to Image::makeFromEncoded

See this for more details JetBrains/compose-multiplatform#124

Note :- I think if we update the compose will solve the problem , I'm not pretty sure +_+.

Shared resource system

In the README you write "Since there isn't any shared resource system between Android and Desktop [...]". This is not really true. The standard Java resource handling mechanism works like a charm on both systems.

Failed to resolve Desktop Compose on Android

I'm trying to use this on a pure android project but whenever I try to implementation it I get:
Failed to resolve: org.jetbrains.compose.ui:ui:1.2.0-alpha01-dev753
Failed to resolve: org.jetbrains.compose.foundation:foundation:1.2.0-alpha01-dev753
Failed to resolve: org.jetbrains.compose.runtime:runtime:1.2.0-alpha01-dev753

I don't believe I'm doing something wrong as I just put the code in like:
implementation("com.alialbaali.kamel:kamel-image:0.4.1")

Am I missing something or just having a brain fart?

Lazy Column Item Performance issue

Using Compose Multiplatform ->

When using asyncPainterResource within a lazy colum or lazy row, the performance is broken under Android app, not happening in iOS App.

It seems the issue is related to the resource being held by the thread trying to download and paint the image.

We've tried to define a coroutine scope context specifically for each asyncPainterResource but the issue is still there.

Let us share the code we're testing:

@Composable
fun ArtWorkList(artworks: List<ArtWorkData>, modifier: Modifier = Modifier, isLoading: Boolean, onPagination: CoroutineScope.() -> Unit) {
    val lazyColumnState = rememberLazyListState()
    val shouldPaginate by remember { derivedStateOf {
        (isLoading && lazyColumnState.layoutInfo.totalItemsCount > 0 && (lazyColumnState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -9) >= artworks.size - 1 && lazyColumnState.firstVisibleItemIndex != 0)
    } }

    LazyColumn(horizontalAlignment = Alignment.CenterHorizontally, state = lazyColumnState) {
        items(artworks) {artwork ->
            Card(modifier = Modifier.padding(6.dp), elevation = 4.dp) {
                Column {
                    ArtWorkImage(artwork.downloadUrl, modifier = Modifier.height(194.dp))
                    Text("By: ${artwork.author}", style = MaterialTheme.typography.h4)
                }
            }
        }
        item {
            if (isLoading) {
                LinearProgressIndicator()
            }
        }
    }
    LaunchedEffect(shouldPaginate, onPagination)
}

@Composable
fun ArtWorkImage(value: String, modifier: Modifier = Modifier) {
    val scope = rememberCoroutineScope()
    val resource = asyncPainterResource(data = Url(value), key = value) {
        coroutineContext = scope.coroutineContext
    }
    Box(modifier = modifier.border(BorderStroke(1.dp, Color.Black)), contentAlignment = Alignment.Center) {
        KamelImage(
            resource = resource,
            contentDescription = value,
            onLoading = { progress -> CircularProgressIndicator(progress) },
            onFailure = {
                Text(it.toString())
            }
        )
    }
}

@Serializable
data class ArtWorkData(
    val id: String,
    val author: String,
    val url: String,
    @SerialName("download_url")
    val downloadUrl: String
)

Even though the code is handling pagination, the issue happens without pagination.

Attaching a video where the app freezes without pagination enabled.

device-2023-06-13-140330.mp4

"Unable to find a fetcher for class io.ktor.http.Url" in iOS only

We started using Kamel recently and just realized our images are not loading on iOS. Everything works fine on Android, though.

Our code looks like the one below:

            KamelImage(
                resource = asyncPainterResource(player.avatarUrl),
                onLoading = { progress -> CircularProgressIndicator(progress) },
                onFailure = { e ->
                    showDefaultAvatar = true
                    println(e.message.toString())                   // <-- this is printing the error in the title, on iOS only
                },
                contentDescription = "Avatar",
                modifier = modifierAvatar,
            )

We have Ktor engines for all platforms. Is this error message correct?

[Feature Request] Progress float in Resource.Loading

With Ktor 1.6.0, it now allows callbacks with the download progress. For example I do this in my KtorImage composable

    val image = client.get<ByteReadChannel>(url) {
        onDownload { bytesSentTotal, contentLength ->
            progress.value = (bytesSentTotal.toFloat() / contentLength).coerceAtMost(1.0F)
        }
    }.toByteArray()

It allows me to set a CircularProgressIndicator with the progress as the real download progress.

Allow construction of HttpFetcher with already made client

For my application I have a Ktor HttpClient that I use everywhere since it is configured for a specific server. Previously I used for construction of the HttpFetcher.

httpFetcher(httpClient.engine) {
   install(httpClient)
}

But recently a feature I needed was added to the Kamel HttpClient and it fails to use that feature.
Sadly I cant construct the HttpFetcher myself since its internal. To get past this I copied the HttpFetcher and am using it directly passing my HttpClient to it. It would be nice to add this to Kamel like so

httpFetcher(httpClient)

Radle build error using `commonMain`

Hi Ali,
thanks for creating this library! I'm looking for something like this for ages.

I try to use it in a KMM app and I added the dependency to commonMain.
But if I try to grade sync it, I'll get the following error. Do you have any idea why?

A problem occurred configuring project ':shared'.
> Could not resolve all dependencies for configuration ':shared:iosArm64CompileKlibraries'.
   > Could not resolve com.alialbaali.kamel:kamel-image:0.4.0.
     Required by:
         project :shared
      > No matching variant of com.alialbaali.kamel:kamel-image:0.4.0 was found. The consumer was configured to find a usage of 'kotlin-api' of a library, preferably optimized for non-jvm, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native', attribute 'org.jetbrains.kotlin.native.target' with value 'ios_arm64' but:
          - Variant 'debugApiElements-published' capability com.alialbaali.kamel:kamel-image:0.4.0 declares an API of a library:
              - Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'debugRuntimeElements-published' capability com.alialbaali.kamel:kamel-image:0.4.0 declares a runtime of a library:
              - Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'desktopApiElements-published' capability com.alialbaali.kamel:kamel-image:0.4.0 declares an API of a library:
              - Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'desktopRuntimeElements-published' capability com.alialbaali.kamel:kamel-image:0.4.0 declares a runtime of a library:
              - Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'metadataApiElements' capability com.alialbaali.kamel:kamel-image:0.4.0 declares a library:
              - Incompatible because this component declares a usage of 'kotlin-metadata' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'common' and the consumer needed a usage of 'kotlin-api' of a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'releaseApiElements-published' capability com.alialbaali.kamel:kamel-image:0.4.0 declares an API of a library:
              - Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'releaseRuntimeElements-published' capability com.alialbaali.kamel:kamel-image:0.4.0 declares a runtime of a library:
              - Incompatible because this component declares a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm' and the consumer needed a component, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'native'
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
          - Variant 'samplessources' capability com.alialbaali.kamel:kamel-image:0.4.0:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java environment (preferred optimized for non-jvm)
                  - Doesn't say anything about its usage (required a usage of 'kotlin-api')
                  - Doesn't say anything about org.jetbrains.kotlin.native.target (required 'ios_arm64')
                  - Doesn't say anything about org.jetbrains.kotlin.platform.type (required 'native')

Kamel with Ktor 2.0.0-beta-1 triggers a NoClassDefFoundError for Desktop app

Hello,

I was using Kamel with Ktor 2.0.0-beta-1 and when building the Desktop client I've had this error:

Reason=java.lang.NoClassDefFoundError: io/ktor/client/features/BodyProgressKt

This seems to happen due to the different packaging that Ktor had when upgrading to the major version 2.0.

I've fixed it locally, and there's an upcoming PR for it ๐Ÿ™‚

Edit: I've updated the PR to ktor 2.0.0

Classes not found when running on iOS

I have added the dependency to common source set since I am using it for a multiplatform project and it works fine when I run Android app, but when I run it on iOS, I get following error.

Could not find "/Users/mac/.gradle/caches/modules-2/files-2.1/media.kamel/kamel-image-iosarm64/0.7.2/33fd052e978bb1ea02569817afbfd6929a1e350a/kamel-image.klib" in [/Users/mac/Documents/Markaz-Supplier/markazSupplierIos/Pods, /Users/mac/.konan/klib, /Users/mac/.konan/kotlin-native-prebuilt-macos-x86_64-1.8.20/klib/common, /Users/mac/.konan/kotlin-native-prebuilt-macos-x86_64-1.8.20/klib/platform/ios_arm64]

Updating to compose 1.2.0-alpha build issue

This is not an issue with the current release. But I am attempting to update the project to use the latest compose-jb alpha 1.2.0-alpha01-dev707 supporting kotlin 1.6.21 to add js and native targets.

When building I get the error:

LazyPainterResource.kt: (49, 17): @Composable invocations can only happen from the context of a @Composable function

which is caused by: rememberVectorPainter being called in the map callback where map is not a @Composable function. And also it is called inside a flow. Which isn't allowed in the latest compose version. So this would probably need a rework.

        "xml" -> kamelConfig.loadImageVectorResource(data, resourceConfig).map { resource ->
            resource.map { imageVector ->
                rememberVectorPainter(imageVector)
            }
        }

I'm trying to think of a way to handle this. Would completely removing use of flows by loadImageVectorResource be an acceptable solution for vectors, as rememberVectorPainter can't be called inside a flow?

which would look something like this:

        "xml" -> flowOf(kamelConfig.loadImageVectorResource(coroutineScope, data, resourceConfig)
            .map { imageVector ->
                rememberVectorPainter(imageVector)
            }
        )

Or does anyone have another suggestion?

Is Library Ready for Use?

Hey, Library Looks Good , is it ready for loading Images Over Net in a KMP project consisting of Desktop , Android Platforms.

[Feature Request] Support direct ImageBitmaps instead of only Painters

I was looking into this library to replace my custom KtorImage composable I use around my app. But one thing I noticed is that there isn't a way to pass a FilterQuality parameter like I would use with my ImageBitmaps to allow for cleaner display(not grainy). I played around with using a custom set of composables with your Resource class, but it seems only Painters are supported for loading, the ImageBitmap version is deprecated. So I cant pass a FilterQuality parameter to a Image composable because FilterQuality is only supported for ImageBitmaps.

cannot inline bytecode built with JVM target 11

Hi ,
I am using this library on my Compose ios multiplatform app. Everything works fine on the ios app but when I compile and run Android app it throws this error.
Cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option

And the error it throws on this line when I try to make asyncPainterResource:
val painterResource = asyncPainterResource(data = "https://image.tmdb.org/t/p/original${item.imageUrl}")

I have my common build.gradle file here : https://pastebin.com/WcbmF812

version Used : media.kamel:kamel-image:0.5.1

UnsatisfiedLinkError synchronizing in compose multiplatform Desktop JVM

I am getting this error when I add the Kamel lib in my project.

you are without my imports:

implementation("io.ktor:ktor-client-core:2.3.3")
implementation("io.ktor:ktor-client-cio:2.3.3")
implementation("io.ktor:ktor-serialization-gson:2.3.3")
implementation("io.ktor:ktor-serialization-kotlinx-cbor:2.3.3")
implementation("io.ktor:ktor-client-content-negotiation:2.3.3")
implementation("io.ktor:ktor-client-auth:2.3.3")
implementation("media.kamel:kamel-image:0.7.2")
....
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'long org.jetbrains.skiko.MetalApiKt.chooseAdapter(int)'
	at org.jetbrains.skiko.MetalApiKt.chooseAdapter(Native Method)
	at org.jetbrains.skiko.MetalApiKt.chooseMetalAdapter(MetalApi.kt:10)
	at org.jetbrains.skiko.redrawer.MetalRedrawer.<init>(MetalRedrawer.kt:64)
	at org.jetbrains.skiko.Actuals_awtKt$makeDefaultRenderFactory$1.createRedrawer(Actuals.awt.kt:26)
	at org.jetbrains.skiko.SkiaLayer$redrawerManager$1.invoke(SkiaLayer.awt.kt:304)
	at org.jetbrains.skiko.SkiaLayer$redrawerManager$1.invoke(SkiaLayer.awt.kt:302)
	at org.jetbrains.skiko.redrawer.RedrawerManager.findNextWorkingRenderApi(RedrawerManager.kt:31)
	at org.jetbrains.skiko.SkiaLayer.init(SkiaLayer.awt.kt:334)
	at org.jetbrains.skiko.SkiaLayer.addNotify(SkiaLayer.awt.kt:161)
	at androidx.compose.ui.awt.WindowComposeBridge$component$1.addNotify(WindowComposeBridge.desktop.kt:45)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at androidx.compose.ui.awt.ComposeWindowDelegate$_pane$1.addNotify(ComposeWindowDelegate.desktop.kt:84)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at java.desktop/javax.swing.JRootPane.addNotify(JRootPane.java:729)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/java.awt.Window.addNotify(Window.java:791)
	at java.desktop/java.awt.Frame.addNotify(Frame.java:495)
	at java.desktop/java.awt.Window.pack(Window.java:829)
	at androidx.compose.ui.util.Windows_desktopKt.setSizeImpl-6HolHcs(Windows.desktop.kt:115)
	at androidx.compose.ui.util.Windows_desktopKt.setSizeSafely-hQcJfNw(Windows.desktop.kt:54)
	at androidx.compose.ui.window.Window_desktopKt$Window$5.invoke(Window.desktop.kt:236)
	at androidx.compose.ui.window.Window_desktopKt$Window$5.invoke(Window.desktop.kt:173)
	at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:422)
	at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:416)
	at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:82)
	at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:80)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:59)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:55)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2300)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:471)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:234)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke$performUpdate(UpdateEffect.desktop.kt:55)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:64)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:47)
	at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
	at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1137)
	at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:828)
	at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:849)
	at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1041)
	at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:520)
	at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

When an image fails to load, it is retried infinitely and recomposes as fast as possible

First, thanks for the great lib! I have a single problem with it so far, and here it is ๐Ÿ™‚

When an image fails to load (no network, bad URL, any time of error I've tested), the HTTP call is retried as fast as possible without any delay, maxing out the CPU. Additionally, the onFailure block is recomposed every time this happens, since we're throwing a new exception on every cycle.

This might cause a DDOS on the server that is supposed to serve the request, and in my case leads to throttling of the API I'm using.

How to reproduce:

  1. In io.kamel.samples.Gallery, set ItemsCount to 1. This will make it easier to see the problem.
  2. In io.kamel.samples.Utils, break the URL so that it fails to load any image. For example, change picsum.photos to picsum.phtos.
  3. In io.kamel.samples.SampleImage, in the onFailure block, add a log directive such as println(exception).
  4. Run ./gradlew :kamel-samples:run and observe the logs.

What happens:

The log is spammed with java.nio.channels.UnresolvedAddressException as fast as the CPU can handle.

What was expected:

I see a single Exception logged. Alternatively, the image load is retried every N seconds, with N configurable in KamelConfig.

The effect can also be observed on an image with crossfade = true and a loading placeholder, you can see the image fade in and out as fast as it can.

Thanks!

Support Image Resizing

If we load a very large size picture the App will crash because oom problem, this is a IOS only issue. cause the IOS will draw the bmp in the memory first, if the picture size(4096*4096) not acutal file size is very large, then there will be a oom error when we use the picture.

GIF suppport

Does Kamel support GIFs (animated image)? I couldn't find any mention of it in README or using repository search.

Support for bitmap or drawable in Android target

Would it be possible to provide a Bitmap or Drawable in addition to Painter when the image is successfully downloaded in Android target similar to Coil-Compose?
Coil:

DisposableEffect(url) {
    val request = ImageRequest.Builder(context)
        .data(data = url)
        .target { drawable ->
            val bitmap = drawable.toBitmapOrNull() ?: return@target
            // TODO use bitmap
        }
        .build()

    val disposable = ImageLoader.Builder(context)
        .components { add(SvgDecoder.Factory()) }
        .build()
        .enqueue(request)

    onDispose {
        disposable.dispose()
    }
}

Failed to Image::makeFromEncoded

Loading some image URLs fail on Desktop JVM. (Not tested on Android)

Exception: Failed to Image::makeFromEncoded

Example URL: https://img-cdn.hltv.org/teamlogo/6LVaK1MVX06kO1ChAq22v6.svg?ixlib=java-2.1.0&s=1ad0be7366aab3ef6825996762c3e615

My KamelConfig:

KamelConfig {
    takeFrom(KamelConfig.Default)
    resourcesFetcher()
    svgDecoder()
    imageVectorDecoder()
}

Example Image display:

KamelImage(
	resource = asyncPainterResource("https://img-cdn.hltv.org/teamlogo/6LVaK1MVX06kO1ChAq22v6.svg?ixlib=java-2.1.0&s=1ad0be7366aab3ef6825996762c3e615"),
	contentDescription = null
)

Unable to find a decode

Error when trying to load svg image.

Sample:

    KamelImage(lazyPainterResource(
            Url("https://www.svgrepo.com/show/424692/energy-factory-illustration-7.svg")),
            contentDescription = null,
            onFailure = { it.printStackTrace() }
        )

StackTrace:

java.lang.IllegalStateException: Unable to find a decoder for io.kamel.core.decoder.Decoder<androidx.compose.ui.graphics.painter.Painter>
	at io.kamel.core.ImageLoadingKt.requestSvgResource(ImageLoading.kt:168)
	at io.kamel.core.ImageLoadingKt.access$requestSvgResource(ImageLoading.kt:1)
	at io.kamel.core.ImageLoadingKt$loadSvgResource$1.invokeSuspend(ImageLoading.kt:74)
	at io.kamel.core.ImageLoadingKt$loadSvgResource$1.invoke(ImageLoading.kt)
	at io.kamel.core.ImageLoadingKt$loadSvgResource$1.invoke(ImageLoading.kt)
	at kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61)
	at kotlinx.coroutines.flow.AbstractFlow.collect(Flow.kt:230)
	at kotlinx.coroutines.flow.FlowKt__ErrorsKt.catchImpl(Errors.kt:156)
	at kotlinx.coroutines.flow.FlowKt.catchImpl(Unknown Source)
	at kotlinx.coroutines.flow.FlowKt__ErrorsKt$catch$$inlined$unsafeFlow$1.collect(SafeCollector.common.kt:113)
	at androidx.compose.runtime.SnapshotStateKt__SnapshotFlowKt$collectAsState$1$2.invokeSuspend(SnapshotFlow.kt:67)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

null cannot be cast to non-null type android.graphics.Bitmap

java.lang.NullPointerException: null cannot be cast to non-null type android.graphics.Bitmap
    at io.kamel.image.decoder.ImageBitmapDecoder.decode(AndroidImageBitmapDecoder.kt:21)
    at io.kamel.image.decoder.ImageBitmapDecoder$decode$1.invokeSuspend(Unknown Source:15)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
    at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

This is the image

@file:Suppress("INLINE_FROM_HIGHER_PLATFORM")
package com.tarehimself.mangaz.ui.screens.search

import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.dp
import com.tarehimself.mangaz.getPlatform
import io.kamel.core.Resource
import io.kamel.image.asyncPainterResource

@Composable
fun SearchResult(data: String) {
    Surface(
        modifier = Modifier.height(300.dp).border(
            width = 2.dp,
            color = Color.Transparent,
            shape = RoundedCornerShape(5.dp)
        ).padding(horizontal = 5.dp, vertical = 5.dp),
        color = Color.Transparent,
    ) {
        when (val resource = asyncPainterResource("https://www.example.com/image.jpg")) {
            is Resource.Loading -> {
                Text("Loading...")
            }
            is Resource.Success -> {
                val painter: Painter = resource.value
                Image(painter= painter, contentDescription = "Profile",modifier = Modifier.fillMaxSize())
            }
            is Resource.Failure -> {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = Color.Red,
                ){
                    TextField(value = resource.exception.stackTraceToString(), onValueChange = {})
                }
            }
        }
    }
}

And this is the config

@Composable
fun App(){
    val kamelConfig = KamelConfig {
        takeFrom(KamelConfig.Default)
    }

    CompositionLocalProvider(LocalKamelConfig provides kamelConfig) {
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colors.background,

            ) {
            SearchScreen()
        }
    }
}

The error is happening on android

0.7.1 version requires -jvm-target specification

Error message is Cannot inline bytecode built with JVM target 17 into bytecode that is being built with JVM target 11. Please specify proper '-jvm-target' option. It will be nice to have in read me file the description of causes and ways to solve for multiplatform project.

Proguard removing necessary fetcher classes

I'm forced to add this to my proguard rules otherwise Kamel refuses to load due to not being able to find classes through reflection

-keep class io.kamel.** { *; }

Is there a more accurate ruleset I can use rather than marking the whole lib to keep?

Fail to set image on desktop app with 1.0.0-alpha4-build361

Hello!

First, let me say that this is a great lib ๐Ÿ™‚ . It really eases handling images on different platforms.

I've just noticed that with the latest version of compose (JetBrains), it's not possible to use Kamel Image on desktop apps:

Reason=java.lang.NoClassDefFoundError: org/jetbrains/skija/Image

Kamel default Android config pulls in desktop loader?

I have a multiplatform project that I just updated to Kamel 0.8.1 (it was on 0.7.x). On launch of the Android app, which has a KamelIImage on the main screen, it crashes with the following error:

java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/ProcessHandle;
   at io.kamel.core.cache.HttpCache_desktopKt.dataPath(httpCache.desktop.kt:15)
   at io.kamel.core.cache.HttpCache_desktopKt.<clinit>(httpCache.desktop.kt:29)
   at io.kamel.core.config.KamelConfigBuilder$httpCache$1.invoke(KamelConfigBuilder.kt:70)
   at io.kamel.core.config.KamelConfigBuilder$httpCache$1.invoke(KamelConfigBuilder.kt:69)
   at io.ktor.client.HttpClientConfig$install$2.invoke(HttpClientConfig.kt:76)
   at io.ktor.client.HttpClientConfig$install$2.invoke(HttpClientConfig.kt:72)
   at io.ktor.client.plugins.cache.HttpCache$Companion.prepare(HttpCache.kt:121)
   at io.ktor.client.plugins.cache.HttpCache$Companion.prepare(HttpCache.kt:115)
   at io.ktor.client.HttpClientConfig$install$3.invoke(HttpClientConfig.kt:84)
   at io.ktor.client.HttpClientConfig$install$3.invoke(HttpClientConfig.kt:81)
   at io.ktor.client.HttpClientConfig.install(HttpClientConfig.kt:104)
   at io.ktor.client.HttpClient.<init>(HttpClient.kt:172)
   at io.ktor.client.HttpClient.<init>(HttpClient.kt:84)
   at io.ktor.client.HttpClientKt.HttpClient(HttpClient.kt:43)
   at io.ktor.client.HttpClientJvmKt.HttpClient(HttpClientJvm.kt:21)

(truncated, it was a very long stack trace)

What I don't understand is why my Android app is referencing desktop code. Is there something wrong with my dependencies? Previous versions worked fine.

Duplicate dependencies with compose

Please update compose version to support 1.1.0

Duplicate class androidx.compose.runtime.saveable.ListSaverKt found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.ListSaverKt$listSaver$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.MapSaverKt found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.MapSaverKt$mapSaver$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.MapSaverKt$mapSaver$2 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt$mutableStateSaver$1$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt$mutableStateSaver$1$2 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt$rememberSaveable$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt$rememberSaveable$1$invoke$$inlined$onDispose$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt$rememberSaveable$1$valueProvider$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.RememberSaveableKt$rememberSaveable$1$valueProvider$1$1$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolder found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$Companion found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$Companion$Saver$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$Companion$Saver$2 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$RegistryHolder found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$RegistryHolder$registry$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$SaveableStateProvider$1$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class 
...
other deps...
...
androidx.compose.runtime.saveable.SaveableStateHolderImpl$SaveableStateProvider$1$1$invoke$$inlined$onDispose$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderImpl$SaveableStateProvider$2 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderKt found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateHolderKt$rememberSaveableStateHolder$1 found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateRegistry found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime (org.jetbrains.compose.runtime:runtime-saveable-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.runtime.saveable.SaveableStateRegistry$Entry found in modules runtime-saveable-1.1.0-runtime (androidx.compose.runtime:runtime-saveable:1.1.0) and runtime-saveable-debug-runtime 
Duplicate class androidx.compose.ui.graphics.ClipOp found in modules ui-graphics-1.1.0-runtime (androidx.compose.ui:ui-graphics:1.1.0) and ui-graphics-debug-runtime (org.jetbrains.compose.ui:ui-graphics-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.graphics.ClipOp$Companion found in modules ui-graphics-1.1.0-runtime (androidx.compose.ui:ui-graphics:1.1.0) and ui-graphics-debug-runtime (org.jetbrains.compose.ui:ui-graphics-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.graphics.Color found in modules ui-graphics-1.1.0-runtime (androidx.compose.ui:ui-graphics:1.1.0) and ui-graphics-debug-runtime (org.jetbrains.compose.ui:ui-graphics-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.graphics.Color$Companion found in modules ui-graphics-1.1.0-runtime (androidx.compose.ui:ui-graphics:1.1.0) and ui-graphics-debug-runtime (org.jetbrains.compose.ui:ui-graphics-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.graphics.ColorFilter found in modules ui-graphics-1.1.0-runtime (androidx.compose.ui:ui-graphics:1.1.0) and ui-graphics-debug-runtime (org.jetbrains.compose.ui:ui-graphics-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.graphics.ColorFilter$Companion found in modules ui-graphics-1.1.0-runtime plicate class androidx.compose.ui.window.PopupLayout$2 found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupLayout$WhenMappings found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupLayout$canCalculatePosition$2 found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupLayoutHelper found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupLayoutHelperImpl found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupLayoutHelperImpl29 found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupPositionProvider found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.PopupProperties found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.SecureFlagPolicy found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.SecureFlagPolicy_androidKt found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)
Duplicate class androidx.compose.ui.window.SecureFlagPolicy_androidKt$WhenMappings found in modules ui-1.1.0-runtime (androidx.compose.ui:ui:1.1.0) and ui-debug-runtime (org.jetbrains.compose.ui:ui-android-debug:1.0.0-alpha2)

Go to the documentation to learn how to Fix dependency resolution errors.

Could not use in Preview mode

Could not use in Preview mode. I got this error

image

I guess we have to use LocalInspectionMode.current check somewhere inside to show some mock Image

Stack trace:
java.lang.NoSuchMethodError: 'layoutlib.internal.kotlin.coroutines.CoroutineContext io.ktor.util.CoroutinesUtilsKt.SilentSupervisor$default(layoutlib.internal.kotlinx.coroutines.Job, int, java.lang.Object)'
at io.ktor.client.engine.HttpClientEngineBase$coroutineContext$2.invoke(HttpClientEngineBase.kt:22)
at io.ktor.client.engine.HttpClientEngineBase$coroutineContext$2.invoke(HttpClientEngineBase.kt:21)
at layoutlib.internal.kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.ktor.client.engine.HttpClientEngineBase.getCoroutineContext(HttpClientEngineBase.kt:21)
at io.ktor.client.HttpClient.(HttpClient.kt:90)
at io.ktor.client.HttpClient.(HttpClient.kt:84)
at io.ktor.client.HttpClientKt.HttpClient(HttpClient.kt:43)
at io.ktor.client.HttpClientJvmKt.HttpClient(HttpClient
Jvm.kt:21)
at io.kamel.core.config.KamelConfigBuilderKt.httpFetcher(KamelConfigBuilder.kt:89)
at io.kamel.core.config.KamelConfigBuilderKt.httpFetcher$default(KamelConfigBuilder.kt:87)
at io.kamel.image.config.KamelConfigKt.getDefault(KamelConfig.kt:19)
at io.kamel.image.config.KamelConfigKt$LocalKamelConfig$1.invoke(KamelConfig.kt:30)
at io.kamel.image.config.KamelConfigKt$LocalKamelConfig$1.invoke(KamelConfig.kt:30)
at layoutlib.internal.kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at androidx.compose.runtime.LazyValueHolder.getCurrent(ValueHolders.kt:29)
at androidx.compose.runtime.LazyValueHolder.getValue(ValueHolders.kt:31)
at androidx.compose.runtime.ComposerImpl.resolveCompositionLocal(Composer.kt:2090)
at androidx.compose.runtime.ComposerImpl.consume(Composer.kt:2058)
at ru.shumskii.bartender.common.screens.randomize.RandomizeScreenKt$RandomizeScreenData$1$1.invoke(RandomizeScreen.kt:343)
at ru.shumskii.bartender.common.screens.randomize.RandomizeScreenKt$RandomizeScreenData$1$1.invoke(RandomizeScreen.kt:155)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.material.SurfaceKt$Surface$1.invoke(Surface.kt:137)
at androidx.compose.material.SurfaceKt$Surface$1.invoke(Surface.kt:118)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material.SurfaceKt.Surface-F-jzlyU(Surface.kt:115)
at ru.shumskii.bartender.common.screens.randomize.RandomizeScreenKt$RandomizeScreenData$1.invoke(RandomizeScreen.kt:151)
at ru.shumskii.bartender.common.screens.randomize.RandomizeScreenKt$RandomizeScreenData$1.invoke(RandomizeScreen.kt:150)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.material.ScaffoldKt$ScaffoldLayout$1$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:322)
at androidx.compose.material.ScaffoldKt$ScaffoldLayout$1$1$1$bodyContentPlaceables$1.invoke(Scaffold.kt:320)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(SubcomposeLayout.kt:778)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$subcompose$3$1$1.invoke(SubcomposeLayout.kt:446)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:78)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3373)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3363)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3363)
at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3298)
at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:587)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:966)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3973)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:519)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto(SubcomposeLayout.kt:466)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:439)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:430)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:419)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:740)
at androidx.compose.material.ScaffoldKt$ScaffoldLayout$1$1$1.invoke(Scaffold.kt:320)
at androidx.compose.material.ScaffoldKt$ScaffoldLayout$1$1$1.invoke(Scaffold.kt:243)
at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1$measure$1.placeChildren(SubcomposeLayout.kt:610)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1.invoke(LayoutNodeLayoutDelegate.kt:276)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1.invoke(LayoutNodeLayoutDelegate.kt:268)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutSnapshotReads$ui_release(OwnerSnapshotObserver.kt:77)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.layoutChildren(LayoutNodeLayoutDelegate.kt:268)
at androidx.compose.ui.node.LayoutNode.onNodePlaced$ui_release(LayoutNode.kt:956)
at androidx.compose.ui.node.InnerNodeCoordinator.placeAt-f8xVGno(InnerNodeCoordinator.kt:137)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:445)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1.invoke(LayoutNodeLayoutDelegate.kt:451)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1.invoke(LayoutNodeLayoutDelegate.kt:445)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutModifierSnapshotReads$ui_release(OwnerSnapshotObserver.kt:92)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeOuterCoordinator-f8xVGno(LayoutNodeLayoutDelegate.kt:445)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeAt-f8xVGno(LayoutNodeLayoutDelegate.kt:428)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:445)
at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50$default(Placeable.kt:223)
at androidx.compose.foundation.layout.BoxKt.placeInBox(Box.kt:186)
at androidx.compose.foundation.layout.BoxKt.access$placeInBox(Box.kt:1)
at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1$measure$2.invoke(Box.kt:126)
at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1$measure$2.invoke(Box.kt:125)
at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1.invoke(LayoutNodeLayoutDelegate.kt:276)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1.invoke(LayoutNodeLayoutDelegate.kt:268)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutSnapshotReads$ui_release(OwnerSnapshotObserver.kt:77)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.layoutChildren(LayoutNodeLayoutDelegate.kt:268)
at androidx.compose.ui.node.LayoutNode.onNodePlaced$ui_release(LayoutNode.kt:956)
at androidx.compose.ui.node.InnerNodeCoordinator.placeAt-f8xVGno(InnerNodeCoordinator.kt:137)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeWithLayer(Placeable.kt:468)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeWithLayer$default(Placeable.kt:286)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier$measure$1.invoke(GraphicsLayerModifier.kt:637)
at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier$measure$1.invoke(GraphicsLayerModifier.kt:636)
at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70)
at androidx.compose.ui.node.LayoutModifierNodeCoordinator.placeAt-f8xVGno(LayoutModifierNodeCoordinator.kt:202)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeWithLayer-aW-9-wM(Placeable.kt:471)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1.invoke(LayoutNodeLayoutDelegate.kt:453)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1.invoke(LayoutNodeLayoutDelegate.kt:445)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutModifierSnapshotReads$ui_release(OwnerSnapshotObserver.kt:92)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeOuterCoordinator-f8xVGno(LayoutNodeLayoutDelegate.kt:445)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeAt-f8xVGno(LayoutNodeLayoutDelegate.kt:428)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelativeWithLayer(Placeable.kt:460)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelativeWithLayer$default(Placeable.kt:266)
at androidx.compose.ui.layout.RootMeasurePolicy$measure$2.invoke(RootMeasurePolicy.kt:43)
at androidx.compose.ui.layout.RootMeasurePolicy$measure$2.invoke(RootMeasurePolicy.kt:39)
at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1.invoke(LayoutNodeLayoutDelegate.kt:276)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$layoutChildren$1$1.invoke(LayoutNodeLayoutDelegate.kt:268)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutSnapshotReads$ui_release(OwnerSnapshotObserver.kt:77)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.layoutChildren(LayoutNodeLayoutDelegate.kt:268)
at androidx.compose.ui.node.LayoutNode.onNodePlaced$ui_release(LayoutNode.kt:956)
at androidx.compose.ui.node.InnerNodeCoordinator.placeAt-f8xVGno(InnerNodeCoordinator.kt:137)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:445)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1.invoke(LayoutNodeLayoutDelegate.kt:451)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinator$1.invoke(LayoutNodeLayoutDelegate.kt:445)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutModifierSnapshotReads$ui_release(OwnerSnapshotObserver.kt:92)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeOuterCoordinator-f8xVGno(LayoutNodeLayoutDelegate.kt:445)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeAt-f8xVGno(LayoutNodeLayoutDelegate.kt:428)
at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:35)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative(Placeable.kt:434)
at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative$default(Placeable.kt:199)
at androidx.compose.ui.node.LayoutNode.place$ui_release(LayoutNode.kt:828)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:443)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:39)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:330)
at androidx.compose.ui.platform.AndroidComposeView.onLayout_Original(AndroidComposeView.android.kt:905)
at androidx.compose.ui.platform.AndroidComposeView.onLayout(AndroidComposeView.android.kt)
at android.view.View.layout_Original(View.java:23694)
at android.view.View_Delegate.layout(View_Delegate.java:91)
at android.view.View.layout(View.java:23680)
at android.view.ViewGroup.layout(ViewGroup.java:6413)
at androidx.compose.ui.platform.AbstractComposeView.internalOnLayout$ui_release(ComposeView.android.kt:322)
at androidx.compose.ui.platform.AbstractComposeView.onLayout_Original(ComposeView.android.kt:313)
at androidx.compose.ui.platform.AbstractComposeView.onLayout(ComposeView.android.kt)
at android.view.View.layout_Original(View.java:23694)
at android.view.View_Delegate.layout(View_Delegate.java:91)
at android.view.View.layout(View.java:23680)
at android.view.ViewGroup.layout(ViewGroup.java:6413)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at androidx.compose.ui.tooling.ComposeViewAdapter.onLayout_Original(ComposeViewAdapter.kt:294)
at androidx.compose.ui.tooling.ComposeViewAdapter.onLayout(ComposeViewAdapter.kt)
at android.view.View.layout_Original(View.java:23694)
at android.view.View_Delegate.layout(View_Delegate.java:91)
at android.view.View.layout(View.java:23680)
at android.view.ViewGroup.layout(ViewGroup.java:6413)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout_Original(View.java:23694)
at android.view.View_Delegate.layout(View_Delegate.java:91)
at android.view.View.layout(View.java:23680)
at android.view.ViewGroup.layout(ViewGroup.java:6413)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1103)
at android.view.View.layout_Original(View.java:23694)
at android.view.View_Delegate.layout(View_Delegate.java:91)
at android.view.View.layout(View.java:23680)
at android.view.ViewGroup.layout(ViewGroup.java:6413)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout_Original(View.java:23694)
at android.view.View_Delegate.layout(View_Delegate.java:91)
at android.view.View.layout(View.java:23680)
at android.view.ViewGroup.layout(ViewGroup.java:6413)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:372)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:450)
at com.android.tools.idea.layoutlib.LayoutLibrary.createSession(LayoutLibrary.java:122)
at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:727)
at com.android.tools.idea.rendering.RenderTask.lambda$inflate$9(RenderTask.java:884)
at com.android.tools.idea.rendering.RenderExecutor$runAsyncActionWithTimeout$3.run(RenderExecutor.kt:195)
at com.android.tools.idea.rendering.RenderExecutor$PriorityRunnable.run(RenderExecutor.kt:293)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.