Are there any file picker etc libraries that suppo...
# compose-web
j
Are there any file picker etc libraries that support Wasm based Compose for Web right now?
👀 1
j
Is doesn't look like it has Wasm support yet?
y
i am using it in my web multiplatform app what do u mean?
j
it's a different target
d
You are welcome to fork code from my project, if it helps: https://github.com/varabyte/kobweb/blob/0.15.4/frontend/compose-html-ext/src/jsMain/kotlin/com/varabyte/kobweb/compose/file/FileUtils.kt My project is a Compose HTML project so you probably don't want the full thing. I'm not experiences with WASM at this point but I've heard it can interact with the DOM, which is what this code is doing (basically creating a temporary
Input
element, using it for its file loading functionality, and discarding it)
j
Thanks @David Herman I tryied it, and it works with WASM 👌
loadDataUrlFromDisk
couses
CastClassException
(
String
vs
JSString
), but with
ByteArray
everything works like a charm. @John O'Reilly
Copy code
Button(
                modifier = Modifier
                    .fillMaxSize(),
                onClick = {
                    document.loadMultipleFromDisk(
                        accept = ".png",
                        onError = {
                        },
                        onLoad = {
                            selectedFiles = it
                        }
                    )
                }) {
                Text("Select file/s")
            }

fun Document.loadMultipleFromDisk(
    accept: String = "",
    onError: (List<LoadContext>) -> Unit = {},
    onLoad: (List<LoadedFile<ByteArray>>) -> Unit,
) {
    loadMultipleFromDisk<ArrayBuffer, ByteArray>(
        accept,
        FileReader::readAsArrayBuffer,
        { result ->
            val intArray = Int8Array(result)
            ByteArray(intArray.byteLength) { i -> intArray[i] }
        },
        onError,
        onLoad
    )
}

private fun <I, O> Document.loadMultipleFromDisk(
    accept: String = "",
    triggerLoad: FileReader.(Blob) -> Unit,
    deserialize: (I) -> O,
    onError: (List<LoadContext>) -> Unit = {},
    onLoad: (List<LoadedFile<O>>) -> Unit,
) {
    loadFromDisk(accept, multiple = true, onChange = { changeEvt ->
        val selectedFiles = changeEvt.target?.unsafeCast<HTMLInputElement>()?.files ?: return@loadFromDisk
        val failedToLoadFiles = mutableListOf<LoadContext>()
        val loadedFiles = mutableListOf<LoadedFile<O>>()

        fun triggerCallbacksIfReady() {
            if (failedToLoadFiles.size + loadedFiles.size == selectedFiles.length) {
                failedToLoadFiles.takeIf { it.isNotEmpty() }?.let { onError(it) }
                loadedFiles.takeIf { it.isNotEmpty() }?.let { onLoad(it) }
            }
        }
        for (i in 0 until selectedFiles.length) {
            val file = selectedFiles[i] ?: return@loadFromDisk
            val reader = FileReader()

            reader.onabort = { handleUnexpectedOnAbort("loadMultipleFromDisk") }
            reader.onerror = {
                failedToLoadFiles.add(createLoadContext(file, it))
                triggerCallbacksIfReady()
            }
            reader.onload = { loadEvt ->
                val loadContext = createLoadContext(file, loadEvt)
                try {
                    val result = loadEvt.target?.unsafeCast<FileReader>()?.result!! as I
                    loadedFiles.add(LoadedFile(loadContext, deserialize(result)))
                } catch (_: Throwable) {
                    failedToLoadFiles.add(loadContext)
                }
                triggerCallbacksIfReady()
            }
            reader.triggerLoad(file)
        }
    })
}

private fun Document.loadFromDisk(
    accept: String,
    multiple: Boolean,
    onChange: ((Event) -> Unit)
) {
    val tempInput = (createElement("input") as HTMLInputElement).apply {
        type = "file"
        style.display = "none"
        this.accept = accept
        this.multiple = multiple
    }

    tempInput.onchange = onChange
    body!!.append(tempInput)
    tempInput.click()
    tempInput.remove()
}
👍 1
I cant map kotlin
String
to javaScript
JSArray(ByteArray)
in
Blob
constructor. Any ideas?
197 Views