Compose Multiplatform support
Is your feature request related to a problem? Please describe. As an Android Developer, I would love to use Coil with Compose Desktop in the same way I use Coil for Compose on Android.
Describe the solution you'd like Ideally, it would be the best to have the same approach we have on Android, so that the knowledge can be reused.
Additional context
I think it would be OK to link the image download scope to either a LaunchedEffect in a Composable, or just link it to the Application lifecycle.
~I agree this would be cool to have. That said, I think this is very very unlikely to be implemented as Coil heavily relies on a number of Android framework classes (Bitmap, BitmapFactory, ImageDecoder) and integrates closely with Views and Lifecycles. Also, Coil depends on a number of AndroidX libraries and OkHttp which aren't (and likely won't) be multiplatform. Overall, it's a lot of work and I don't have plans to work on it. Going to leave this open as a catch-all for multiplatform questions.~
Check here for an update. TLDR: This is now planned!
On compose I wrapped coil and wrote two actual functions. On desktop its look as
package components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import com.tradernet.data.source.getHttpClient
import io.ktor.client.request.*
import org.jetbrains.skija.Image
import androidx.compose.foundation.Image as ComposeImage
suspend fun loadPicture(url: String): Result<ImageBitmap> {
val client = getHttpClient()
return try {
val image = client.get<ByteArray>(url)
Result.success(Image.makeFromEncoded(image).asImageBitmap())
} catch (e: Exception) {
Result.failure(e)
}
}
@Composable
actual fun ExternalImage(url: String, modifier: Modifier, OnFail: @Composable () -> Unit) {
var isLoading by remember { mutableStateOf(false) }
var hasFail by remember { mutableStateOf(false) }
var imageBitmap: ImageBitmap? by remember { mutableStateOf(null) }
LaunchedEffect(url) {
isLoading = true
loadPicture(url)
.onSuccess {
imageBitmap = it
}
.onFailure {
hasFail = true
}
isLoading = false
}
when {
isLoading -> {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
CircularProgressIndicator()
}
}
hasFail -> {
OnFail()
}
else -> {
imageBitmap?.let { bitmap ->
ComposeImage(
bitmap = bitmap,
contentDescription = "",
contentScale = ContentScale.FillWidth,
alpha = DefaultAlpha,
colorFilter = null,
)
} ?: OnFail()
}
}
}
it's a variant I took from https://stackoverflow.com/questions/66002696/how-to-load-image-from-remote-url-in-kotlin-compose-desktop. What's missing is caching mechanism.
I too would love to see a coil-desktop implementation, even if it was just using JVM calls under the hood, similar to this post https://dev.to/gerardpaligot/sharing-compose-components-between-android-and-desktop-17kg
Thanks @jershell . Just a note for those who will try to reuse your snippet: it was easier for me to use skiko v0.5.3 instead of skija, and then just swap the line in the try catch with:
Result.success(Image.makeFromEncoded(image).toComposeImageBitmap())
Works but yikes for the caching indeed, so +1 for Coil-desktop. Not sure if there is multiplatform alternatives or even work-in-progress on this topic, please share if you know something.
In case it's relevant to the feasibility - https://github.com/square/okhttp/issues/6963
Libraries like Square Wire (gRPC) are also blocked on a multiplatform OkHttp Call.Factory. I hope in 2022, we get a good suite of KMP libraries for IO, Networking, RPC, Images, so hope this becomes feasible at some point.
For multiplatform projects there is the Kamel, based on watch I saw of the source code, almost all the source is based on Ktor Client, Skiko and Androidx Compose, this meas that even now that is working on Desktop and don't see how hard would be to make it support on iOS in the future.
Hi, since coil 2.0 do you have any plans to implement this feature?
Porting the library from okhttp to ktor(which can still use okhttp) will be a great start to make this library multiplatform.
Coroutines, ktor and okio are all multiplatform libraries.
Adding ktor means adding more code in Android apps with no purpose. Either Coil stick to Android and it should not try to move to ktor (and keep a lightweight performant library), or it's decided that Coil wants to go full KMP. I think a lot of Android projects will not move to KMP right now, so Coil is still a very good option as is.
Since Kamel is going multi-platform from start, maybe better to consider adding missing things to Kamel instead of trying to port a lot of Android specific code to KMP?
This issue is for compose desktop which works on the jvm, not KMP, which I do think would be an easier ask.
I am using this library for now which works great: https://github.com/alialbaali/Kamel/pull/14#issuecomment-1150598198
Yes desktop (jvm) version would be great, all of infrastructure as far as coroutines, okhttp etc should be there, so "only" Bitmap & friends would need to be wrapped
Compose has a ImageBitmap , maybe that is a way?
Note that if you want to write a proper multiplatform (mac, win, linux) desktop app, youre option basically is just Electron (VS Code, Spotify, Slack, etc), which is ..not great performance.
I could see a world where compose desktop could be very popular.
You can use libs like https://github.com/alialbaali/Kamel or https://github.com/ltttttttttttt/load-the-image and use @jershell's idea to wrap this libs with expect/actual.
there is already an image loader that use coil as foundation to load images https://github.com/qdsfdhvh/compose-imageloader
Hi folks, big update! There are now plans to add Kotlin Multiplatform support to Coil and this will be the main feature of 3.x. I can't offer a timeline, but this is top of mind.
The plan is to leave Coil's public API largely the same (except for Android-specific classes) for an initial alpha then iterate on other public API changes we want to make for 3.x. Some of the main initial changes we'll need to make will be to abstract away usages of Bitmap and Drawable and replace BitmapFactory with a multiplatform solution. Fortunately, Compose Multiplatform should make migrating the coil-compose artifact fairly straightforward. I'm heading on holiday until May 7th, but will follow up with more details afterwards.
To be clear, by Kotlin Multiplatform support do you mean support for Compose Multiplatform or some UI framework independent solution (which will be much more complicated I think)? Also what platforms do you plan to support in addition to Android?
@colinrtwhite have you considered applying for a grant for this - http://kotlinfoundation.org/grants
@mxalbert1996 The goal is to support Kotlin Multiplatform and Compose Multiplatform with as many targets as possible. The Android target will have the most functionality by supporting lifecycles, views, and other Android concepts. Other targets will be focused on supporting fetching + decoding images with integration with coroutines and less platform-specific support.
I think we can accomplish this by replacing BitmapFactory with skiko, which is the image decoder used by Compose Multiplatform, for non-Android targets. Migrating to Compose Multiplatform should be pretty straightforward once coil-base has been converted to multiplatform. We'll just need to swap AndroidX Compose with Jetbrains Compose.
The biggest challenge I see at the moment is refactoring Context references so ImageLoader and other classes aren't coupled with Context. Currently, we pass a Context object deep into ImageLoader's classes.
Good news! Any idea if skiko will be more or less performant than BitmapFactory on Android?
For the Context I tend to use a ContentProvider that hold a static reference to the application Context, so that it can be used in androidMain code without being declared in commonMain. Do you see any issue with this approach? Is there a limitation with theme / image loading requiring the Activity/fragment context instead?
@colinrtwhite Don't you think about making a development branch for working on this feature so we can contribute and make this process faster
@glureau My guess is it would be slightly slower given BitmapFactory is an Android framework class, which is why we should continue to use BitmapFactory on Android and skiko only on non-Android targets. For Context I'd prefer to avoid content providers and have the user pass a Context when building the ImageLoader.
@MohamedRejeb Will do! I'm going to create a 3.x branch that folks can contribute to once I've handled some of the initial multiplatform migration.
To use BitmapFactory on Android is the right decision because Skiko is not a lightweight library 😉
@colinrtwhite Is there a plan to migrate from OkHttp to Ktor for sending HTTP requests to support for Kotlin Multiplatform Mobile?
Or are you planning to use different HTTP clients depending on the environment?
@sonatard That's still up for discussion. I think it's likely we migrate to Ktor and make it an optional dependency to support https://github.com/coil-kt/coil/issues/1648.
I'm relieved that Ktor has become the standard.
As many libraries are advancing their support for KMM using Ktor, it's pleasing to be able to reduce dependencies on other libraries like okHttp.
Most will driver ktor with okhttp
On Wed, 17 May 2023, 03:49 sonatard, @.***> wrote:
I'm relieved that Ktor has become the standard.
As many libraries are advancing their support for KMM using Ktor, it's pleasing to be able to reduce dependencies on other libraries like okHttp.
— Reply to this email directly, view it on GitHub https://github.com/coil-kt/coil/issues/842#issuecomment-1550570657, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALPBKTY3Y3RPIRNP6EDSODXGQVBZANCNFSM5BOPLKOA . You are receiving this because you commented.Message ID: @.***>
Hmm, is it? Stable?
On Sat, 20 May 2023, 16:41 Natan Lifshitz, @.***> wrote:
Why migrate to ktor if okhttp already supports Kotlin Multiplatform?
— Reply to this email directly, view it on GitHub https://github.com/coil-kt/coil/issues/842#issuecomment-1555926634, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALPBKRMNRD4AMGN5XRUFR3XHDJYPANCNFSM5BOPLKOA . You are receiving this because you commented.Message ID: @.***>
I'm relieved that Ktor has become the standard.
As many libraries are advancing their support for KMM using Ktor, it's pleasing to be able to reduce dependencies on other libraries like okHttp.
+1 for using ktor
Hi Please pace yourself
I've been lurking this thread, just wanted to say congratulations https://kotlinfoundation.org/news/grants-program-winners-23/