commonMain.io.nacular.doodle.image.impl.ImageLoaderImpl.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of browser Show documentation
Show all versions of browser Show documentation
A pure Kotlin, UI framework for the Web and Desktop
package io.nacular.doodle.image.impl
import io.nacular.doodle.datatransport.LocalFile
import io.nacular.doodle.dom.HTMLImageElement
import io.nacular.doodle.dom.HtmlFactory
import io.nacular.doodle.image.Image
import io.nacular.doodle.image.ImageLoader
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
internal class ImageLoaderImpl(private val htmlFactory: HtmlFactory, private val images: MutableMap = mutableMapOf()): ImageLoader {
private val loading = mutableMapOf()
private val pendingCoroutines = mutableMapOf>>()
override suspend fun load(source: String, description: String): Image? = suspendCoroutine { coroutine ->
when (source) {
in images -> coroutine.resume(images[source])
in loading -> pendingCoroutines.getOrPut(source) { mutableListOf() }.plusAssign(coroutine)
else -> {
loading[source] = htmlFactory.createImage(source).apply {
onload = {
loading -= source
images[source] = ImageImpl(this)
description.takeIf { it.isNotBlank() }?.let { this.alt = it }
notify(source, coroutine)
removeListeners(this)
}
onerror = {
loading -= source
removeListeners(this)
notify(source, coroutine)
}
}
}
}
}
private fun notify(source: String, current: Continuation) {
val image = images[source]
current.resume(image)
pendingCoroutines[source]?.forEach { it.resume(image) }
pendingCoroutines.remove(source)
}
override suspend fun load(file: LocalFile, description: String): Image? = file.readBase64()?.let { load("data:*/*;base64,$it", description) }
override fun unload(image: Image) {
images.remove(image.source)
}
private fun removeListeners(image: HTMLImageElement) {
image.onload = null
image.onerror = null
}
}