All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.io.nacular.doodle.image.impl.ImageLoaderImpl.kt Maven / Gradle / Ivy

There is a newer version: 0.10.2
Show newest version
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
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy