update "mediumType" to be optional parameter of "listAlbums" to allow fetch both type of media

This commit is contained in:
Wenqi Li 2023-05-11 21:56:25 +08:00
parent 1db9b6966e
commit 6976ab8d3b
4 changed files with 92 additions and 63 deletions

View File

@ -98,7 +98,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
executor.submit { executor.submit {
result.success( result.success(
listAlbums(mediumType!!) listAlbums(mediumType)
) )
} }
} }
@ -111,11 +111,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val take = call.argument<Int>("take") val take = call.argument<Int>("take")
executor.submit { executor.submit {
result.success( result.success(
when (mediumType) { listMedia(mediumType, albumId!!, newest!!, total!!, skip, take)
imageType -> listImages(albumId!!, newest!!, total!!, skip, take)
videoType -> listVideos(albumId!!, newest!!, total!!, skip, take)
else -> null
}
) )
} }
} }
@ -173,24 +169,24 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} }
private fun listAlbums(mediumType: String): List<Map<String, Any>> { private fun listAlbums(mediumType: String?): List<Map<String, Any?>> {
return when (mediumType) { return when (mediumType) {
imageType -> { imageType -> {
listImageAlbums() listImageAlbums().values.toList()
} }
videoType -> { videoType -> {
listVideoAlbums() listVideoAlbums().values.toList()
} }
else -> { else -> {
listOf() listAllAlbums().values.toList()
} }
} }
} }
private fun listImageAlbums(): List<Map<String, Any>> { private fun listImageAlbums(): Map<String, Map<String, Any>> {
this.context.run { this.context.run {
var total = 0 var total = 0
val albumHashMap = mutableMapOf<String, MutableMap<String, Any>>() val albumHashMap = hashMapOf<String, HashMap<String, Any>>()
val imageProjection = arrayOf( val imageProjection = arrayOf(
MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
@ -214,7 +210,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val album = albumHashMap[bucketId] val album = albumHashMap[bucketId]
if (album == null) { if (album == null) {
val folderName = cursor.getString(bucketColumn) val folderName = cursor.getString(bucketColumn)
albumHashMap[bucketId] = mutableMapOf( albumHashMap[bucketId] = hashMapOf(
"id" to bucketId, "id" to bucketId,
"mediumType" to imageType, "mediumType" to imageType,
"name" to folderName, "name" to folderName,
@ -228,25 +224,25 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} }
val albumList = mutableListOf<Map<String, Any>>() val albumLinkedMap = linkedMapOf<String, Map<String, Any>>()
albumList.add( albumLinkedMap.put(
mapOf( allAlbumId,
hashMapOf(
"id" to allAlbumId, "id" to allAlbumId,
"mediumType" to imageType, "mediumType" to imageType,
"name" to allAlbumName, "name" to allAlbumName,
"count" to total "count" to total
) )
) )
albumList.addAll(albumHashMap.values) albumLinkedMap.putAll(albumHashMap)
return albumList return albumLinkedMap
} }
return listOf()
} }
private fun listVideoAlbums(): List<Map<String, Any>> { private fun listVideoAlbums(): Map<String, Map<String, Any>> {
this.context.run { this.context.run {
var total = 0 var total = 0
val albumHashMap = mutableMapOf<String, MutableMap<String, Any>>() val albumHashMap = hashMapOf<String, HashMap<String, Any>>()
val videoProjection = arrayOf( val videoProjection = arrayOf(
MediaStore.Video.Media.BUCKET_DISPLAY_NAME, MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
@ -270,7 +266,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val album = albumHashMap[bucketId] val album = albumHashMap[bucketId]
if (album == null) { if (album == null) {
val folderName = cursor.getString(bucketColumn) val folderName = cursor.getString(bucketColumn)
albumHashMap[bucketId] = mutableMapOf( albumHashMap[bucketId] = hashMapOf(
"id" to bucketId, "id" to bucketId,
"mediumType" to videoType, "mediumType" to videoType,
"name" to folderName, "name" to folderName,
@ -284,16 +280,58 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} }
val albumList = mutableListOf<Map<String, Any>>() val albumLinkedMap = linkedMapOf<String, Map<String, Any>>()
albumList.add(mapOf( albumLinkedMap.put(
allAlbumId,
hashMapOf(
"id" to allAlbumId, "id" to allAlbumId,
"mediumType" to videoType, "mediumType" to videoType,
"name" to allAlbumName, "name" to allAlbumName,
"count" to total)) "count" to total
albumList.addAll(albumHashMap.values) )
return albumList )
albumLinkedMap.putAll(albumHashMap)
return albumLinkedMap
}
}
private fun listAllAlbums(): Map<String, Map<String, Any?>> {
val imageMap = this.listImageAlbums()
val videoMap = this.listVideoAlbums()
val albumMap = (imageMap.keys + videoMap.keys).associateWith {
mapOf(
"id" to it,
"mediumType" to null,
"name" to imageMap[it]?.get("name"),
"count" to (imageMap[it]?.get("count") ?: 0) as Int + (videoMap[it]?.get("count") ?: 0) as Int,
)
}
return albumMap
}
private fun listMedia(mediumType: String?, albumId: String, newest: Boolean, total: Int, skip: Int?, take: Int?): Map<String, Any?> {
return when (mediumType) {
imageType -> {
listImages(albumId, newest, total, skip, take)
}
videoType -> {
listVideos(albumId, newest, total, skip, take)
}
else -> {
val images = listImages(albumId, newest, total, skip, take).get("items") as List<Map<String, Any?>>
val videos = listVideos(albumId, newest, total, skip, take).get("items") as List<Map<String, Any?>>
var items = (images +videos).sortedWith(compareBy<Map<String, Any?>> {it.get("creationDate") as Long}.thenBy { it.get("modifiedDate") as Long })
if (newest) {
items = items.reversed()
}
mapOf(
"newest" to newest,
"start" to (skip ?: 0),
"total" to total,
"items" to items
)
}
} }
return listOf()
} }
private fun listImages(albumId: String, newest: Boolean, total: Int, skip: Int?, take: Int?): Map<String, Any> { private fun listImages(albumId: String, newest: Boolean, total: Int, skip: Int?, take: Int?): Map<String, Any> {

View File

@ -29,8 +29,7 @@ class _MyAppState extends State<MyApp> {
Future<void> initAsync() async { Future<void> initAsync() async {
if (await _promptPermissionSetting()) { if (await _promptPermissionSetting()) {
List<Album> albums = List<Album> albums = await PhotoGallery.listAlbums();
await PhotoGallery.listAlbums(mediumType: MediumType.image);
setState(() { setState(() {
_albums = albums; _albums = albums;
_loading = false; _loading = false;

View File

@ -14,14 +14,14 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
if(call.method == "listAlbums") { if(call.method == "listAlbums") {
let arguments = call.arguments as! Dictionary<String, AnyObject> let arguments = call.arguments as! Dictionary<String, AnyObject>
let mediumType = arguments["mediumType"] as! String let mediumType = arguments["mediumType"] as? String
let hideIfEmpty = arguments["hideIfEmpty"] as? Bool let hideIfEmpty = arguments["hideIfEmpty"] as? Bool
result(listAlbums(mediumType: mediumType, hideIfEmpty: hideIfEmpty)) result(listAlbums(mediumType: mediumType, hideIfEmpty: hideIfEmpty))
} }
else if(call.method == "listMedia") { else if(call.method == "listMedia") {
let arguments = call.arguments as! Dictionary<String, AnyObject> let arguments = call.arguments as! Dictionary<String, AnyObject>
let albumId = arguments["albumId"] as! String let albumId = arguments["albumId"] as! String
let mediumType = arguments["mediumType"] as! String let mediumType = arguments["mediumType"] as? String
let newest = arguments["newest"] as! Bool let newest = arguments["newest"] as! Bool
let skip = arguments["skip"] as? NSNumber let skip = arguments["skip"] as? NSNumber
let take = arguments["take"] as? NSNumber let take = arguments["take"] as? NSNumber
@ -90,11 +90,13 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
private var assetCollections : [PHAssetCollection] = [] private var assetCollections : [PHAssetCollection] = []
private func listAlbums(mediumType: String, hideIfEmpty: Bool? = true) -> [NSDictionary] { private func listAlbums(mediumType: String?, hideIfEmpty: Bool? = true) -> [[String: Any?]] {
self.assetCollections = [] self.assetCollections = []
let fetchOptions = PHFetchOptions() let fetchOptions = PHFetchOptions()
var total = 0 if #available(iOS 9, *) {
var albums = [NSDictionary]() fetchOptions.fetchLimit = 1
}
var albums = [[String: Any?]]()
var albumIds = Set<String>() var albumIds = Set<String>()
func addCollection (collection: PHAssetCollection, hideIfEmpty: Bool) -> Void { func addCollection (collection: PHAssetCollection, hideIfEmpty: Bool) -> Void {
@ -106,14 +108,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
guard !albumIds.contains(albumId) else { return } guard !albumIds.contains(albumId) else { return }
albumIds.insert(albumId) albumIds.insert(albumId)
let options = PHFetchOptions() let count = countMedia(collection: collection, mediumType: mediumType)
options.predicate = self.predicateFromMediumType(mediumType: mediumType)
if #available(iOS 9, *) {
fetchOptions.fetchLimit = 1
}
let count = PHAsset.fetchAssets(in: collection, options: options).count
if(count > 0 || !hideIfEmpty) { if(count > 0 || !hideIfEmpty) {
total+=count
self.assetCollections.append(collection) self.assetCollections.append(collection)
albums.append([ albums.append([
"id": collection.localIdentifier, "id": collection.localIdentifier,
@ -156,15 +152,15 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
"id": "__ALL__", "id": "__ALL__",
"mediumType": mediumType, "mediumType": mediumType,
"name": "All", "name": "All",
"count" : countMedia(collection: nil, mediumTypes: [mediumType]), "count" : countMedia(collection: nil, mediumType: mediumType),
], at: 0) ], at: 0)
return albums return albums
} }
private func countMedia(collection: PHAssetCollection?, mediumTypes: [String]) -> Int { private func countMedia(collection: PHAssetCollection?, mediumType: String?) -> Int {
let options = PHFetchOptions() let options = PHFetchOptions()
options.predicate = self.predicateFromMediumTypes(mediumTypes: mediumTypes) options.predicate = self.predicateFromMediumType(mediumType: mediumType)
if(collection == nil) { if(collection == nil) {
return PHAsset.fetchAssets(with: options).count return PHAsset.fetchAssets(with: options).count
} }
@ -172,13 +168,13 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
return PHAsset.fetchAssets(in: collection ?? PHAssetCollection.init(), options: options).count return PHAsset.fetchAssets(in: collection ?? PHAssetCollection.init(), options: options).count
} }
private func listMedia(albumId: String, mediumType: String, newest: Bool, skip: NSNumber?, take: NSNumber?) -> NSDictionary { private func listMedia(albumId: String, mediumType: String?, newest: Bool, skip: NSNumber?, take: NSNumber?) -> NSDictionary {
let fetchOptions = PHFetchOptions() let fetchOptions = PHFetchOptions()
fetchOptions.predicate = predicateFromMediumType(mediumType: mediumType)
fetchOptions.sortDescriptors = [ fetchOptions.sortDescriptors = [
NSSortDescriptor(key: "creationDate", ascending: newest ? false : true), NSSortDescriptor(key: "creationDate", ascending: newest ? false : true),
NSSortDescriptor(key: "modificationDate", ascending: newest ? false : true) NSSortDescriptor(key: "modificationDate", ascending: newest ? false : true)
] ]
fetchOptions.predicate = predicateFromMediumType(mediumType: mediumType)
let collection = self.assetCollections.first(where: { (collection) -> Bool in let collection = self.assetCollections.first(where: { (collection) -> Bool in
collection.localIdentifier == albumId collection.localIdentifier == albumId
@ -277,9 +273,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
) { ) {
let manager = PHImageManager.default() let manager = PHImageManager.default()
let fetchOptions = PHFetchOptions() let fetchOptions = PHFetchOptions()
if (mediumType != nil) { fetchOptions.predicate = self.predicateFromMediumType(mediumType: mediumType)
fetchOptions.predicate = self.predicateFromMediumType(mediumType: mediumType!)
}
fetchOptions.sortDescriptors = [ fetchOptions.sortDescriptors = [
NSSortDescriptor(key: "creationDate", ascending: false), NSSortDescriptor(key: "creationDate", ascending: false),
NSSortDescriptor(key: "modificationDate", ascending: false) NSSortDescriptor(key: "modificationDate", ascending: false)
@ -509,16 +503,14 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
} }
private func predicateFromMediumTypes(mediumTypes: [String]) -> NSPredicate { private func predicateFromMediumType(mediumType: String?) -> NSPredicate? {
let predicates = mediumTypes.map { (dartValue) -> NSPredicate in guard let type = mediumType else {
return predicateFromMediumType(mediumType: dartValue) return nil
} }
return NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.or, subpredicates: predicates) guard let swiftType = toSwiftMediumType(value: type) else {
return nil
} }
return NSPredicate(format: "mediaType = %d", swiftType.rawValue)
private func predicateFromMediumType(mediumType: String) -> NSPredicate {
let swiftType = toSwiftMediumType(value: mediumType)
return NSPredicate(format: "mediaType = %d", swiftType!.rawValue)
} }
private func extractFileExtensionFromUTI(uti: String?) -> String { private func extractFileExtensionFromUTI(uti: String?) -> String {

View File

@ -22,7 +22,7 @@ class PhotoGallery {
/// List all available gallery albums and counts number of items of [MediumType]. /// List all available gallery albums and counts number of items of [MediumType].
static Future<List<Album>> listAlbums({ static Future<List<Album>> listAlbums({
required MediumType mediumType, MediumType? mediumType,
bool? hideIfEmpty = true, bool? hideIfEmpty = true,
}) async { }) async {
final json = await _channel.invokeMethod('listAlbums', { final json = await _channel.invokeMethod('listAlbums', {