Refactor(FileUtils): Optimize code
This commit is contained in:
@@ -225,7 +225,7 @@ private fun initWebView(
|
|||||||
webview.settings.javaScriptEnabled = true
|
webview.settings.javaScriptEnabled = true
|
||||||
webview.settings.domStorageEnabled = true
|
webview.settings.domStorageEnabled = true
|
||||||
webview.addJavascriptInterface(
|
webview.addJavascriptInterface(
|
||||||
NativeWebApi(context = context, webView = webview, permissionLauncher),
|
NativeWebApi(context = context, permissionLauncher = permissionLauncher),
|
||||||
"NativeApi"
|
"NativeApi"
|
||||||
)
|
)
|
||||||
webview.setDownloadListener { url, userAgent, _, mimetype, _ ->
|
webview.setDownloadListener { url, userAgent, _, mimetype, _ ->
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package top.fatweb.oxygen.toolbox.util
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import kotlin.let
|
||||||
|
|
||||||
|
fun saveToDownloads(
|
||||||
|
context: Context,
|
||||||
|
permissionLauncher: ManagedActivityResultLauncher<String, Boolean>,
|
||||||
|
data: ByteArray,
|
||||||
|
fileName: String
|
||||||
|
) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
saveFileToDownloads(context = context, data = data, fileName = fileName)
|
||||||
|
} else {
|
||||||
|
saveFileToDownloads(
|
||||||
|
context = context,
|
||||||
|
permissionLauncher = permissionLauncher,
|
||||||
|
data = data,
|
||||||
|
fileName = fileName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
|
private fun saveFileToDownloads(
|
||||||
|
context: Context,
|
||||||
|
data: ByteArray,
|
||||||
|
fileName: String
|
||||||
|
): Boolean {
|
||||||
|
val resolver = context.contentResolver
|
||||||
|
|
||||||
|
val contentValues = ContentValues().apply {
|
||||||
|
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
|
||||||
|
put(MediaStore.Downloads.MIME_TYPE, "application/octet-stream")
|
||||||
|
put(MediaStore.Downloads.IS_PENDING, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
||||||
|
val fileUri = resolver.insert(collection, contentValues)
|
||||||
|
|
||||||
|
return fileUri?.let { uri ->
|
||||||
|
resolver.openOutputStream(uri)?.use { outputStream ->
|
||||||
|
outputStream.write(data)
|
||||||
|
outputStream.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
contentValues.clear()
|
||||||
|
contentValues.put(MediaStore.Downloads.IS_PENDING, 0)
|
||||||
|
resolver.update(uri, contentValues, null, null)
|
||||||
|
true
|
||||||
|
} ?: run {
|
||||||
|
Timber.e("Could not save file $fileName to Downloads")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveFileToDownloads(
|
||||||
|
context: Context,
|
||||||
|
permissionLauncher: ManagedActivityResultLauncher<String, Boolean>,
|
||||||
|
data: ByteArray,
|
||||||
|
fileName: String
|
||||||
|
): Boolean {
|
||||||
|
if (!runBlocking {
|
||||||
|
Permissions.requestWriteExternalStoragePermission(
|
||||||
|
context,
|
||||||
|
permissionLauncher
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val downloadsDir =
|
||||||
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||||
|
val file = File(downloadsDir, fileName)
|
||||||
|
|
||||||
|
return try {
|
||||||
|
FileOutputStream(file).apply {
|
||||||
|
write(data)
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Timber.e(e, "Could not save file $fileName to ${file.absolutePath}")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,26 +2,14 @@ package top.fatweb.oxygen.toolbox.util
|
|||||||
|
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.ContentValues
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.CLIPBOARD_SERVICE
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.os.Build
|
|
||||||
import android.os.Environment
|
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.webkit.JavascriptInterface
|
import android.webkit.JavascriptInterface
|
||||||
import android.webkit.WebView
|
|
||||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class NativeWebApi(
|
class NativeWebApi(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val webView: WebView,
|
|
||||||
private val permissionLauncher: ManagedActivityResultLauncher<String, Boolean>
|
private val permissionLauncher: ManagedActivityResultLauncher<String, Boolean>
|
||||||
) {
|
) {
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
@@ -43,66 +31,11 @@ class NativeWebApi(
|
|||||||
fun saveToDownloads(dataBase64: String, fileName: String): Boolean {
|
fun saveToDownloads(dataBase64: String, fileName: String): Boolean {
|
||||||
val data = Base64.decode(dataBase64, Base64.DEFAULT)
|
val data = Base64.decode(dataBase64, Base64.DEFAULT)
|
||||||
|
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
return saveToDownloads(
|
||||||
saveFileToDownloads(data = data, fileName = fileName)
|
context = context,
|
||||||
} else {
|
permissionLauncher = permissionLauncher,
|
||||||
saveFileToExternalDownloads(data = data, fileName = fileName)
|
data = data,
|
||||||
}
|
fileName = fileName
|
||||||
}
|
)
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
|
||||||
private fun saveFileToDownloads(data: ByteArray, fileName: String): Boolean {
|
|
||||||
val resolver = context.contentResolver
|
|
||||||
|
|
||||||
val contentValues = ContentValues().apply {
|
|
||||||
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
|
|
||||||
put(MediaStore.Downloads.MIME_TYPE, "application/octet-stream")
|
|
||||||
put(MediaStore.Downloads.IS_PENDING, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
|
||||||
val fileUri = resolver.insert(collection, contentValues)
|
|
||||||
|
|
||||||
return fileUri?.let { uri ->
|
|
||||||
resolver.openOutputStream(uri)?.use { outputStream ->
|
|
||||||
outputStream.write(data)
|
|
||||||
outputStream.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
contentValues.clear()
|
|
||||||
contentValues.put(MediaStore.Downloads.IS_PENDING, 0)
|
|
||||||
resolver.update(uri, contentValues, null, null)
|
|
||||||
true
|
|
||||||
} ?: let {
|
|
||||||
Timber.e("Could not save file $fileName to Downloads")
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveFileToExternalDownloads(data: ByteArray, fileName: String): Boolean {
|
|
||||||
if (!runBlocking { Permissions.requestWriteExternalStoragePermission(context, permissionLauncher) }) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val downloadsDir =
|
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
|
||||||
val file = File(downloadsDir, fileName)
|
|
||||||
|
|
||||||
return try {
|
|
||||||
FileOutputStream(file).apply {
|
|
||||||
write(data)
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
true
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Timber.e(e, "Could not save file $fileName to ${file.absolutePath}")
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun callback(callback: String, vararg args: Any) {
|
|
||||||
val jsCode =
|
|
||||||
"$callback(${args.map { if (it is String) "'$it'" else it }.joinToString(", ")})"
|
|
||||||
webView.evaluateJavascript(jsCode, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user