Support file saver dialog for JS and WASM targets too
Hi, it would be nice if the file saver dialog would be available for the web platforms too. An implementation could be based on the very popular FileSaver library.
Hi @mipastgt! Thanks for creating this issue! I'll check it out.
It could be as simple as that:
In build.gradle.kts in wasmJsMain.dependencies
implementation(npm("file-saver", "2.0.5"))
In your code:
@ExperimentalWebApi
@JsModule("file-saver")
external class FileSaverJs {
companion object {
fun saveAs(blob: Blob, fileName: String)
}
}
It doesn't look like file-saver is highly required in current case.
Repo looks like unsupported :(
Following snippet can be used instead.
Yes, but note the comment in this more recent version of the snippet.
@mipastgt file-saver provides other behaviour?
Yes, as far as I can tell (I tried it on my mac) it always shows the dialog in the same way as you would expect it from a desktop application.
I'm testing file-saver library on mac with chrome but when I call saveAs(:blob, :fileName), it doesn't open the file saver dialog. However, the file is properly downloaded in the download folder.
It behaves the same way as FileKit.download() (https://filekit.mintlify.app/dialogs/file-saver#download-file-on-the-web)
I think @mipastgt that in your browser settings, you have the option "Ask where to save each file before downloading" enabled as suggested in this issue: https://github.com/eligrey/FileSaver.js/issues/630
Finally, I'm not sure if forcing the browser to open to file saver dialog is possible. Did I miss something?
Yes, you are right. I just re-checked that and when I disable the "asking" in Chrome, then FileSaver also just saves the file in the default location.
I don't think it is possible to support file saver dialogs for web targets right now. I'm closing this issue, but we can reopen if we found a way to support that in the future.
Works in Chrome - https://developer.mozilla.org/en-US/docs/Web/API/Window/showSaveFilePicker
Thanks, I wasn't aware this API existed!
Yesterday I was able to make it work in js and wasm targets on chromium based browsers. Also, I was able to create a PlatformFile from the return of showSaveFilePicker().
But I encountered a problem when I tried to use this API on an unsupported browser like Safari: after calling showSaveFilePicker(), the Compose app crashes and didn't respond at all and log this exception in the console:
JsException: Can't find variable: showSaveFilePicker
The main problem here is that I can't catch the exception with the classic try / catch. The exception is thrown somewhere else in the internals of KMP.
I'm not sure how to handle unsupported web APIs. Is it the responsibility of the developer to check if he can call certain web API or if it is to the library to check (and simplify the developer experience)?
Have you tried following this recommendation? https://developer.chrome.com/docs/capabilities/web-apis/file-system-access#feature_detection