diff --git a/sdk-core/src/main/java/com/xuqm/sdk/file/FileSDK.kt b/sdk-core/src/main/java/com/xuqm/sdk/file/FileSDK.kt index 8306959..e513b7d 100644 --- a/sdk-core/src/main/java/com/xuqm/sdk/file/FileSDK.kt +++ b/sdk-core/src/main/java/com/xuqm/sdk/file/FileSDK.kt @@ -3,11 +3,13 @@ package com.xuqm.sdk.file import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent +import android.content.ContentValues import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build import android.os.Environment +import android.provider.MediaStore import android.webkit.MimeTypeMap import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat @@ -269,6 +271,46 @@ object FileSDK { return target } + /** + * Saves an image file to the system photo gallery (MediaStore). + * Returns true if the file is an image and was saved successfully. + */ + fun saveImageToGallery(context: Context, file: File): Boolean { + val mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension(file.extension.lowercase()) ?: return false + if (!mimeType.startsWith("image/")) return false + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + runCatching { + val values = ContentValues().apply { + put(MediaStore.Images.Media.DISPLAY_NAME, file.name) + put(MediaStore.Images.Media.MIME_TYPE, mimeType) + put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES) + put(MediaStore.Images.Media.IS_PENDING, 1) + } + val uri = context.contentResolver.insert( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values + ) ?: return false + context.contentResolver.openOutputStream(uri)?.use { out -> + file.inputStream().use { it.copyTo(out) } + } + values.clear() + values.put(MediaStore.Images.Media.IS_PENDING, 0) + context.contentResolver.update(uri, values, null, null) + true + }.getOrDefault(false) + } else { + @Suppress("DEPRECATION") + runCatching { + val picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + picturesDir.mkdirs() + val dest = uniqueFile(picturesDir, file.name) + file.copyTo(dest) + context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(dest))) + true + }.getOrDefault(false) + } + } + fun openFile(context: Context, file: File) { val mimeType = MimeTypeMap.getSingleton() .getMimeTypeFromExtension(file.extension.lowercase()) diff --git a/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt b/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt index fa8156e..fd7dd5c 100644 --- a/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt +++ b/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt @@ -272,9 +272,12 @@ fun XWebViewView( runCatching { FileSDK.saveBlobDownload(context, b64, filename, config.downloadDestination) }.onSuccess { file -> + // For image files, save to the system gallery (相册) so they appear in Photos + val savedToGallery = runCatching { FileSDK.saveImageToGallery(context, file) }.getOrDefault(false) withContext(Dispatchers.Main) { dispatchDownloadEvent("__xwvDownloadDone", url, ",success:true") - FileSDK.openFile(context, file) + // Only open with file viewer when not saved to gallery (e.g. zip, docx) + if (!savedToGallery) FileSDK.openFile(context, file) } }.onFailure { e -> withContext(Dispatchers.Main) {