Skip to content

[Android] Support file chooser #22

@dd10-e

Description

@dd10-e

Hello !

Thank you for your project. This is mostly i wanted for the Compose Multiplatform ecosystem, nice work !
I would like to add support of file chooser on Android, that is not supported by default. On IOS, Apple handle this by default.

On android.webkit.WebView, we can suppport it by overwriting calling onShowFileChooser :

// in WebChromeClient() implementation

override fun onShowFileChooser(
      webView: WebView?,
      callback: ValueCallback<Array<Uri>>?,
      fileChooserParams: FileChooserParams?
  ): Boolean {
      // custom code
  }

On IOS, there is nothing to do as it is already supported. And i don't see any way to customize the behavior.

Would you be ok to accept this feature ?

Design proposition

I think the library can take the responsability of sending events only instead of implementing UI ?

I imagine we can add this code in WebViewState :

// WebViewState.kt

    var fileChooserState: FileChooserState by mutableStateOf(FileChooserState.Idle)
        internal set


// FileChooserState.kt
sealed class FileChooserState {
    data object Idle : FileChooserState()

    data object Opened : FileChooserState()

    data class Completed(
        val uris: List<String>,
    ) : FileChooserState()

    data object Cancelled : FileChooserState()
}

fun WebViewState.completeFileChooser(uris: List<String>) {
    fileChooserState = FileChooserState.Completed(uris = uris)
}

fun WebViewState.cancelFileChooser() {
    fileChooserState = FileChooserState.Cancelled
}

fun WebViewState.resetFileChooser() {
    fileChooserState = FileChooserState.Idle
}


// WebviewAndroid.kt
override fun onShowFileChooser(
      webView: WebView?,
      callback: ValueCallback<Array<Uri>>?,
      fileChooserParams: FileChooserParams?
  ): Boolean {
      callback?.let {
          fileChooserCallback = it
          state.fileChooserState = FileChooserState.Opened
      }
      return true
  }


 LaunchedEffect(state.fileChooserState) {
      when (val chooserState = state.fileChooserState) {
          is FileChooserState.Completed -> {
              chromeClient.fileChooserCallback?.onReceiveValue(
                  chooserState.uris.map { it.toUri() }.toTypedArray()
              )
              chromeClient.fileChooserCallback = null
              state.resetFileChooser()
          }
          is FileChooserState.Cancelled -> {
              chromeClient.fileChooserCallback?.onReceiveValue(null)
              chromeClient.fileChooserCallback = null
              state.resetFileChooser()
          }
          else -> {}
      }
  }

What do you think about this approach ? The main advantages here is that we can customize file chooser UI as we want on Android. I am not aware of desktop implementation through.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions