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")
executor.submit {
result.success(
listAlbums(mediumType!!)
listAlbums(mediumType)
)
}
}
@ -111,11 +111,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val take = call.argument<Int>("take")
executor.submit {
result.success(
when (mediumType) {
imageType -> listImages(albumId!!, newest!!, total!!, skip, take)
videoType -> listVideos(albumId!!, newest!!, total!!, skip, take)
else -> null
}
listMedia(mediumType, albumId!!, newest!!, total!!, skip, take)
)
}
}
@ -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) {
imageType -> {
listImageAlbums()
listImageAlbums().values.toList()
}
videoType -> {
listVideoAlbums()
listVideoAlbums().values.toList()
}
else -> {
listOf()
listAllAlbums().values.toList()
}
}
}
private fun listImageAlbums(): List<Map<String, Any>> {
private fun listImageAlbums(): Map<String, Map<String, Any>> {
this.context.run {
var total = 0
val albumHashMap = mutableMapOf<String, MutableMap<String, Any>>()
val albumHashMap = hashMapOf<String, HashMap<String, Any>>()
val imageProjection = arrayOf(
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
@ -214,7 +210,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val album = albumHashMap[bucketId]
if (album == null) {
val folderName = cursor.getString(bucketColumn)
albumHashMap[bucketId] = mutableMapOf(
albumHashMap[bucketId] = hashMapOf(
"id" to bucketId,
"mediumType" to imageType,
"name" to folderName,
@ -228,25 +224,25 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
}
}
val albumList = mutableListOf<Map<String, Any>>()
albumList.add(
mapOf(
val albumLinkedMap = linkedMapOf<String, Map<String, Any>>()
albumLinkedMap.put(
allAlbumId,
hashMapOf(
"id" to allAlbumId,
"mediumType" to imageType,
"name" to allAlbumName,
"count" to total
)
)
albumList.addAll(albumHashMap.values)
return albumList
albumLinkedMap.putAll(albumHashMap)
return albumLinkedMap
}
return listOf()
}
private fun listVideoAlbums(): List<Map<String, Any>> {
private fun listVideoAlbums(): Map<String, Map<String, Any>> {
this.context.run {
var total = 0
val albumHashMap = mutableMapOf<String, MutableMap<String, Any>>()
val albumHashMap = hashMapOf<String, HashMap<String, Any>>()
val videoProjection = arrayOf(
MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
@ -270,7 +266,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val album = albumHashMap[bucketId]
if (album == null) {
val folderName = cursor.getString(bucketColumn)
albumHashMap[bucketId] = mutableMapOf(
albumHashMap[bucketId] = hashMapOf(
"id" to bucketId,
"mediumType" to videoType,
"name" to folderName,
@ -284,16 +280,58 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
}
}
val albumList = mutableListOf<Map<String, Any>>()
albumList.add(mapOf(
"id" to allAlbumId,
"mediumType" to videoType,
"name" to allAlbumName,
"count" to total))
albumList.addAll(albumHashMap.values)
return albumList
val albumLinkedMap = linkedMapOf<String, Map<String, Any>>()
albumLinkedMap.put(
allAlbumId,
hashMapOf(
"id" to allAlbumId,
"mediumType" to videoType,
"name" to allAlbumName,
"count" to total
)
)
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> {

View File

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

View File

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