@@ -2,10 +2,15 @@ package me.bmax.apatch.ui
22
33import android.annotation.SuppressLint
44import android.app.ActivityManager
5+ import android.content.ActivityNotFoundException
6+ import android.content.Intent
57import android.graphics.Color
8+ import android.net.Uri
69import android.os.Build
710import android.os.Bundle
811import android.view.ViewGroup
12+ import android.webkit.ValueCallback
13+ import android.webkit.WebChromeClient
914import android.webkit.WebResourceRequest
1015import android.webkit.WebResourceResponse
1116import android.webkit.WebView
@@ -14,6 +19,8 @@ import android.widget.FrameLayout
1419import androidx.activity.ComponentActivity
1520import androidx.activity.compose.setContent
1621import androidx.activity.enableEdgeToEdge
22+ import androidx.activity.result.ActivityResultLauncher
23+ import androidx.activity.result.contract.ActivityResultContracts
1724import androidx.compose.foundation.background
1825import androidx.compose.foundation.layout.Box
1926import androidx.compose.foundation.layout.fillMaxSize
@@ -45,6 +52,8 @@ class WebUIActivity : ComponentActivity() {
4552 private lateinit var insets: Insets
4653 private var insetsContinuation: CancellableContinuation <Unit >? = null
4754 private var isInsetsEnabled = false
55+ private lateinit var fileChooserLauncher: ActivityResultLauncher <Intent >
56+ private var filePathCallback: ValueCallback <Array <Uri >>? = null
4857
4958 override fun onCreate (savedInstanceState : Bundle ? ) {
5059
@@ -72,6 +81,27 @@ class WebUIActivity : ComponentActivity() {
7281 }
7382 setupWebView()
7483 }
84+
85+ fileChooserLauncher = registerForActivityResult(
86+ ActivityResultContracts .StartActivityForResult ()
87+ ) { result ->
88+ val uris: Array <Uri >? = when (result.resultCode) {
89+ RESULT_OK -> result.data?.let { data ->
90+ when {
91+ data.clipData != null -> {
92+ Array (data.clipData!! .itemCount) { i ->
93+ data.clipData!! .getItemAt(i).uri // Multiple files
94+ }
95+ }
96+ data.data != null -> { arrayOf(data.data!! ) } // Single file
97+ else -> null
98+ }
99+ }
100+ else -> null
101+ }
102+ filePathCallback?.onReceiveValue(uris)
103+ filePathCallback = null
104+ }
75105 }
76106
77107 private suspend fun setupWebView () {
@@ -172,6 +202,28 @@ class WebUIActivity : ComponentActivity() {
172202 webViewInterface = WebViewInterface (this @WebUIActivity, this )
173203 addJavascriptInterface(webViewInterface, " ksu" )
174204 setWebViewClient(webViewClient)
205+ webChromeClient = object : WebChromeClient () {
206+ override fun onShowFileChooser (
207+ webView : WebView ? ,
208+ filePathCallback : ValueCallback <Array <Uri >>? ,
209+ fileChooserParams : FileChooserParams ?
210+ ): Boolean {
211+ this @WebUIActivity.filePathCallback?.onReceiveValue(null )
212+ this @WebUIActivity.filePathCallback = filePathCallback
213+ val intent = fileChooserParams?.createIntent() ? : Intent (Intent .ACTION_GET_CONTENT ).apply { type = " */*" }
214+ if (fileChooserParams?.mode == FileChooserParams .MODE_OPEN_MULTIPLE ) {
215+ intent.putExtra(Intent .EXTRA_ALLOW_MULTIPLE , true )
216+ }
217+ try {
218+ fileChooserLauncher.launch(intent)
219+ } catch (_: ActivityNotFoundException ) {
220+ filePathCallback?.onReceiveValue(null )
221+ this @WebUIActivity.filePathCallback = null
222+ return false
223+ }
224+ return true
225+ }
226+ }
175227 loadUrl(" https://mui.kernelsu.org/index.html" )
176228 }
177229 }
0 commit comments