mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-26 08:54:42 +01:00
Query files from media store
This commit is contained in:
parent
c6e6b99128
commit
b71620ee28
3 changed files with 129 additions and 0 deletions
|
@ -3,6 +3,7 @@
|
|||
package="com.nkming.nc_photos">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="28"
|
||||
tools:ignore="ScopedStorage" />
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.nkming.nc_photos.plugin
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
|
@ -16,6 +19,9 @@ import java.io.File
|
|||
* Write binary content to a file in the Download directory. Return the Uri to
|
||||
* the file
|
||||
* fun saveFileToDownload(content: ByteArray, filename: String, subDir: String?): String
|
||||
*
|
||||
* Return files under @c relativePath and its sub dirs
|
||||
* fun queryFiles(relativePath: String): List<Map>
|
||||
*/
|
||||
class MediaStoreChannelHandler(context: Context) :
|
||||
MethodChannel.MethodCallHandler, ActivityAware {
|
||||
|
@ -67,6 +73,14 @@ class MediaStoreChannelHandler(context: Context) :
|
|||
}
|
||||
}
|
||||
|
||||
"queryFiles" -> {
|
||||
try {
|
||||
queryFiles(call.argument("relativePath")!!, result)
|
||||
} catch (e: Throwable) {
|
||||
result.error("systemException", e.message, null)
|
||||
}
|
||||
}
|
||||
|
||||
else -> result.notImplemented()
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +116,86 @@ class MediaStoreChannelHandler(context: Context) :
|
|||
}
|
||||
}
|
||||
|
||||
private fun queryFiles(relativePath: String, result: MethodChannel.Result) {
|
||||
if (!PermissionUtil.hasReadExternalStorage(context)) {
|
||||
activity?.let { PermissionUtil.requestReadExternalStorage(it) }
|
||||
result.error("permissionError", "Permission not granted", null)
|
||||
return
|
||||
}
|
||||
|
||||
val pathColumnName: String
|
||||
val pathArg: String
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
pathColumnName = MediaStore.Images.Media.RELATIVE_PATH
|
||||
pathArg = "${relativePath}/%"
|
||||
} else {
|
||||
@Suppress("Deprecation")
|
||||
pathColumnName = MediaStore.Images.Media.DATA
|
||||
pathArg = "%/${relativePath}/%"
|
||||
}
|
||||
val projection = arrayOf(
|
||||
MediaStore.Images.Media._ID,
|
||||
MediaStore.Images.Media.DATE_MODIFIED,
|
||||
MediaStore.Images.Media.MIME_TYPE,
|
||||
MediaStore.Images.Media.DATE_TAKEN,
|
||||
MediaStore.Images.Media.DISPLAY_NAME,
|
||||
pathColumnName
|
||||
)
|
||||
val selection = StringBuilder().apply {
|
||||
append("${MediaStore.Images.Media.MIME_TYPE} LIKE ?")
|
||||
append("AND $pathColumnName LIKE ?")
|
||||
}.toString()
|
||||
val selectionArgs = arrayOf("image/%", pathArg)
|
||||
val files = context.contentResolver.query(
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
projection, selection, selectionArgs, null
|
||||
)!!.use {
|
||||
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
|
||||
val dateModifiedColumn =
|
||||
it.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED)
|
||||
val mimeTypeColumn =
|
||||
it.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE)
|
||||
val dateTakenColumn =
|
||||
it.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN)
|
||||
val displayNameColumn =
|
||||
it.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
|
||||
val pathColumn = it.getColumnIndexOrThrow(pathColumnName)
|
||||
val products = mutableListOf<Map<String, Any>>()
|
||||
while (it.moveToNext()) {
|
||||
val id = it.getLong(idColumn)
|
||||
val dateModified = it.getLong(dateModifiedColumn)
|
||||
val mimeType = it.getString(mimeTypeColumn)
|
||||
val dateTaken = it.getLong(dateTakenColumn)
|
||||
val displayName = it.getString(displayNameColumn)
|
||||
val path = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// RELATIVE_PATH
|
||||
"${it.getString(pathColumn).trimEnd('/')}/$displayName"
|
||||
} else {
|
||||
// DATA
|
||||
it.getString(pathColumn)
|
||||
}
|
||||
val contentUri = ContentUris.withAppendedId(
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id
|
||||
)
|
||||
products.add(buildMap {
|
||||
put("uri", contentUri.toString())
|
||||
put("displayName", displayName)
|
||||
put("path", path)
|
||||
put("dateModified", dateModified * 1000)
|
||||
put("mimeType", mimeType)
|
||||
if (dateTaken != 0L) put("dateTaken", dateTaken)
|
||||
})
|
||||
Log.d(
|
||||
TAG,
|
||||
"[queryEnhancedPhotos] Found $displayName, path=$path, uri=$contentUri"
|
||||
)
|
||||
}
|
||||
products
|
||||
}
|
||||
Log.i(TAG, "[queryEnhancedPhotos] Found ${files.size} files")
|
||||
result.success(files)
|
||||
}
|
||||
|
||||
private fun inputToUri(fromFile: String): Uri {
|
||||
val testUri = Uri.parse(fromFile)
|
||||
return if (testUri.scheme == null) {
|
||||
|
|
|
@ -4,6 +4,18 @@ import 'package:flutter/services.dart';
|
|||
import 'package:nc_photos_plugin/src/exception.dart';
|
||||
import 'package:nc_photos_plugin/src/k.dart' as k;
|
||||
|
||||
class MediaStoreQueryResult {
|
||||
const MediaStoreQueryResult(this.uri, this.displayName, this.path,
|
||||
this.dateModified, this.mimeType, this.dateTaken);
|
||||
|
||||
final String uri;
|
||||
final String displayName;
|
||||
final String path;
|
||||
final int dateModified;
|
||||
final String? mimeType;
|
||||
final int? dateTaken;
|
||||
}
|
||||
|
||||
class MediaStore {
|
||||
static Future<String> saveFileToDownload(
|
||||
Uint8List content,
|
||||
|
@ -51,6 +63,28 @@ class MediaStore {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return files under [relativePath] and its sub dirs
|
||||
static Future<List<MediaStoreQueryResult>> queryFiles(
|
||||
String relativePath) async {
|
||||
try {
|
||||
final List results =
|
||||
await _methodChannel.invokeMethod("queryFiles", <String, dynamic>{
|
||||
"relativePath": relativePath,
|
||||
});
|
||||
return results
|
||||
.cast<Map>()
|
||||
.map((e) => MediaStoreQueryResult(e["uri"], e["displayName"],
|
||||
e["path"], e["dateModified"], e["mimeType"], e["dateTaken"]))
|
||||
.toList();
|
||||
} on PlatformException catch (e) {
|
||||
if (e.code == _exceptionCodePermissionError) {
|
||||
throw const PermissionException();
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const _methodChannel = MethodChannel("${k.libId}/media_store_method");
|
||||
|
||||
static const _exceptionCodePermissionError = "permissionError";
|
||||
|
|
Loading…
Add table
Reference in a new issue