optimize code

This commit is contained in:
Wenqi Li 2023-05-14 02:23:53 +08:00
parent eafedcb225
commit 4a2b9dcf1c
3 changed files with 180 additions and 106 deletions

View File

@ -10,7 +10,6 @@ import android.graphics.ImageDecoder
import android.os.Build import android.os.Build
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Size import android.util.Size
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
@ -81,18 +80,18 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
private val executor: ExecutorService = Executors.newSingleThreadExecutor() private val executor: ExecutorService = Executors.newSingleThreadExecutor()
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "photo_gallery") channel = MethodChannel(flutterPluginBinding.binaryMessenger, "photo_gallery")
val plugin = PhotoGalleryPlugin() val plugin = PhotoGalleryPlugin()
plugin.context = flutterPluginBinding.applicationContext plugin.context = flutterPluginBinding.applicationContext
channel.setMethodCallHandler(plugin) channel.setMethodCallHandler(plugin)
} }
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null) channel.setMethodCallHandler(null)
} }
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) { when (call.method) {
"listAlbums" -> { "listAlbums" -> {
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
@ -102,6 +101,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
"listMedia" -> { "listMedia" -> {
val albumId = call.argument<String>("albumId") val albumId = call.argument<String>("albumId")
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
@ -114,6 +114,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
"getMedium" -> { "getMedium" -> {
val mediumId = call.argument<String>("mediumId") val mediumId = call.argument<String>("mediumId")
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
@ -123,6 +124,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
"getThumbnail" -> { "getThumbnail" -> {
val mediumId = call.argument<String>("mediumId") val mediumId = call.argument<String>("mediumId")
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
@ -135,6 +137,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
"getAlbumThumbnail" -> { "getAlbumThumbnail" -> {
val albumId = call.argument<String>("albumId") val albumId = call.argument<String>("albumId")
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
@ -148,6 +151,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
"getFile" -> { "getFile" -> {
val mediumId = call.argument<String>("mediumId") val mediumId = call.argument<String>("mediumId")
val mediumType = call.argument<String>("mediumType") val mediumType = call.argument<String>("mediumType")
@ -158,6 +162,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
"cleanCache" -> { "cleanCache" -> {
executor.submit { executor.submit {
result.success( result.success(
@ -165,6 +170,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
) )
} }
} }
else -> result.notImplemented() else -> result.notImplemented()
} }
} }
@ -174,9 +180,11 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
imageType -> { imageType -> {
listImageAlbums().values.toList() listImageAlbums().values.toList()
} }
videoType -> { videoType -> {
listVideoAlbums().values.toList() listVideoAlbums().values.toList()
} }
else -> { else -> {
listAllAlbums().values.toList() listAllAlbums().values.toList()
} }
@ -224,13 +232,10 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
val albumLinkedMap = linkedMapOf<String, Map<String, Any>>() val albumLinkedMap = linkedMapOf<String, Map<String, Any>>()
albumLinkedMap.put( albumLinkedMap[allAlbumId] = hashMapOf(
allAlbumId, "id" to allAlbumId,
hashMapOf( "name" to allAlbumName,
"id" to allAlbumId, "count" to total
"name" to allAlbumName,
"count" to total
)
) )
albumLinkedMap.putAll(albumHashMap) albumLinkedMap.putAll(albumHashMap)
return albumLinkedMap return albumLinkedMap
@ -278,13 +283,10 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
val albumLinkedMap = linkedMapOf<String, Map<String, Any>>() val albumLinkedMap = linkedMapOf<String, Map<String, Any>>()
albumLinkedMap.put( albumLinkedMap[allAlbumId] = hashMapOf(
allAlbumId, "id" to allAlbumId,
hashMapOf( "name" to allAlbumName,
"id" to allAlbumId, "count" to total
"name" to allAlbumName,
"count" to total
)
) )
albumLinkedMap.putAll(albumHashMap) albumLinkedMap.putAll(albumHashMap)
return albumLinkedMap return albumLinkedMap
@ -304,18 +306,28 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
return albumMap return albumMap
} }
private fun listMedia(mediumType: String?, albumId: String, newest: Boolean, skip: Int?, take: Int?): Map<String, Any?> { private fun listMedia(
mediumType: String?,
albumId: String,
newest: Boolean,
skip: Int?,
take: Int?
): Map<String, Any?> {
return when (mediumType) { return when (mediumType) {
imageType -> { imageType -> {
listImages(albumId, newest, skip, take) listImages(albumId, newest, skip, take)
} }
videoType -> { videoType -> {
listVideos(albumId, newest, skip, take) listVideos(albumId, newest, skip, take)
} }
else -> { else -> {
val images = listImages(albumId, newest, null, null)["items"] as List<Map<String, Any?>> val images = listImages(albumId, newest, null, null)["items"] as List<Map<String, Any?>>
val videos = listVideos(albumId, newest, null, null)["items"] as List<Map<String, Any?>> val videos = listVideos(albumId, newest, null, null)["items"] as List<Map<String, Any?>>
var items = (images + videos).sortedWith(compareBy<Map<String, Any?>> { it["creationDate"] as Long }.thenBy { it["modifiedDate"] as Long }) val comparator = compareBy<Map<String, Any?>> { it["creationDate"] as Long }
.thenBy { it["modifiedDate"] as Long }
var items = (images + videos).sortedWith(comparator)
if (newest) { if (newest) {
items = items.reversed() items = items.reversed()
} }
@ -452,9 +464,11 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
imageType -> { imageType -> {
getImageMedia(mediumId) getImageMedia(mediumId)
} }
videoType -> { videoType -> {
getVideoMedia(mediumId) getVideoMedia(mediumId)
} }
else -> { else -> {
getImageMedia(mediumId) ?: getVideoMedia(mediumId) getImageMedia(mediumId) ?: getVideoMedia(mediumId)
} }
@ -505,14 +519,22 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
return videoMetadata return videoMetadata
} }
private fun getThumbnail(mediumId: String, mediumType: String?, width: Int?, height: Int?, highQuality: Boolean?): ByteArray? { private fun getThumbnail(
mediumId: String,
mediumType: String?,
width: Int?,
height: Int?,
highQuality: Boolean?
): ByteArray? {
return when (mediumType) { return when (mediumType) {
imageType -> { imageType -> {
getImageThumbnail(mediumId, width, height, highQuality) getImageThumbnail(mediumId, width, height, highQuality)
} }
videoType -> { videoType -> {
getVideoThumbnail(mediumId, width, height, highQuality) getVideoThumbnail(mediumId, width, height, highQuality)
} }
else -> { else -> {
getImageThumbnail(mediumId, width, height, highQuality) getImageThumbnail(mediumId, width, height, highQuality)
?: getVideoThumbnail(mediumId, width, height, highQuality) ?: getVideoThumbnail(mediumId, width, height, highQuality)
@ -537,7 +559,9 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
null null
} }
} else { } else {
val kind = if (highQuality == true) MediaStore.Images.Thumbnails.MINI_KIND else MediaStore.Images.Thumbnails.MICRO_KIND val kind =
if (highQuality == true) MediaStore.Images.Thumbnails.MINI_KIND
else MediaStore.Images.Thumbnails.MICRO_KIND
MediaStore.Images.Thumbnails.getThumbnail( MediaStore.Images.Thumbnails.getThumbnail(
this.contentResolver, mediumId.toLong(), this.contentResolver, mediumId.toLong(),
kind, null kind, null
@ -572,7 +596,8 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} else { } else {
val kind = val kind =
if (highQuality == true) MediaStore.Video.Thumbnails.MINI_KIND else MediaStore.Video.Thumbnails.MICRO_KIND if (highQuality == true) MediaStore.Video.Thumbnails.MINI_KIND
else MediaStore.Video.Thumbnails.MICRO_KIND
MediaStore.Video.Thumbnails.getThumbnail( MediaStore.Video.Thumbnails.getThumbnail(
this.contentResolver, mediumId.toLong(), this.contentResolver, mediumId.toLong(),
kind, null kind, null
@ -589,21 +614,36 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
return byteArray return byteArray
} }
private fun getAlbumThumbnail(albumId: String, mediumType: String?, newest: Boolean, width: Int?, height: Int?, highQuality: Boolean?): ByteArray? { private fun getAlbumThumbnail(
albumId: String,
mediumType: String?,
newest: Boolean,
width: Int?,
height: Int?,
highQuality: Boolean?
): ByteArray? {
return when (mediumType) { return when (mediumType) {
imageType -> { imageType -> {
getImageAlbumThumbnail(albumId, newest, width, height, highQuality) getImageAlbumThumbnail(albumId, newest, width, height, highQuality)
} }
videoType -> { videoType -> {
getVideoAlbumThumbnail(albumId, newest, width, height, highQuality) getVideoAlbumThumbnail(albumId, newest, width, height, highQuality)
} }
else -> { else -> {
getAllAlbumThumbnail(albumId, newest, width, height, highQuality) getAllAlbumThumbnail(albumId, newest, width, height, highQuality)
} }
} }
} }
private fun getImageAlbumThumbnail(albumId: String, newest: Boolean, width: Int?, height: Int?, highQuality: Boolean?): ByteArray? { private fun getImageAlbumThumbnail(
albumId: String,
newest: Boolean,
width: Int?,
height: Int?,
highQuality: Boolean?
): ByteArray? {
return this.context.run { return this.context.run {
val projection = arrayOf(MediaStore.Images.Media._ID) val projection = arrayOf(MediaStore.Images.Media._ID)
@ -621,7 +661,13 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} }
private fun getVideoAlbumThumbnail(albumId: String, newest: Boolean, width: Int?, height: Int?, highQuality: Boolean?): ByteArray? { private fun getVideoAlbumThumbnail(
albumId: String,
newest: Boolean,
width: Int?,
height: Int?,
highQuality: Boolean?
): ByteArray? {
return this.context.run { return this.context.run {
val projection = arrayOf(MediaStore.Video.Media._ID) val projection = arrayOf(MediaStore.Video.Media._ID)
@ -639,7 +685,13 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} }
private fun getAllAlbumThumbnail(albumId: String, newest: Boolean, width: Int?, height: Int?, highQuality: Boolean?): ByteArray? { private fun getAllAlbumThumbnail(
albumId: String,
newest: Boolean,
width: Int?,
height: Int?,
highQuality: Boolean?
): ByteArray? {
return this.context.run { return this.context.run {
val imageProjection = arrayOf( val imageProjection = arrayOf(
MediaStore.Images.Media._ID, MediaStore.Images.Media._ID,
@ -688,20 +740,16 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
if (imageId != null && videoId != null) { if (imageId != null && videoId != null) {
if (imageDateAdded != null && videoDateAdded != null) { if (newest && imageDateAdded!! > videoDateAdded!! || !newest && imageDateAdded!! < videoDateAdded!!) {
if (newest && imageDateAdded!! < videoDateAdded!! || !newest && imageDateAdded!! > videoDateAdded!!) { return@run getImageThumbnail(imageId.toString(), width, height, highQuality)
return@run getVideoThumbnail(videoId.toString(), width, height, highQuality)
} else {
return@run getImageThumbnail(imageId.toString(), width, height, highQuality)
}
} }
if (imageDateModified != null && videoDateModified != null) { if (newest && imageDateAdded!! < videoDateAdded!! || !newest && imageDateAdded!! > videoDateAdded!!) {
if (newest && imageDateModified!! < videoDateModified!! || !newest && imageDateModified!! > videoDateModified!!) { return@run getVideoThumbnail(videoId.toString(), width, height, highQuality)
return@run getVideoThumbnail(videoId.toString(), width, height, highQuality)
} else {
return@run getImageThumbnail(imageId.toString(), width, height, highQuality)
}
} }
if (newest && imageDateModified!! >= videoDateModified!! || !newest && imageDateModified!! <= videoDateModified!!) {
return@run getImageThumbnail(imageId.toString(), width, height, highQuality)
}
return@run getVideoThumbnail(videoId.toString(), width, height, highQuality)
} }
if (imageId != null) { if (imageId != null) {
@ -805,9 +853,11 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
imageType -> { imageType -> {
getImageFile(mediumId, mimeType = mimeType) getImageFile(mediumId, mimeType = mimeType)
} }
videoType -> { videoType -> {
getVideoFile(mediumId) getVideoFile(mediumId)
} }
else -> { else -> {
getImageFile(mediumId, mimeType = mimeType) ?: getVideoFile(mediumId) getImageFile(mediumId, mimeType = mimeType) ?: getVideoFile(mediumId)
} }
@ -874,10 +924,12 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
val bitmap: Bitmap? = this.context.run { val bitmap: Bitmap? = this.context.run {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try { try {
ImageDecoder.decodeBitmap(ImageDecoder.createSource( ImageDecoder.decodeBitmap(
this.contentResolver, ImageDecoder.createSource(
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediumId.toLong()) this.contentResolver,
)) ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediumId.toLong())
)
)
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
@ -891,24 +943,39 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
bitmap?.let { bitmap?.let {
val compressFormat: Bitmap.CompressFormat val compressFormat: Bitmap.CompressFormat
if (mimeType == "image/jpeg") { when (mimeType) {
val path = File(getCachePath(), "$mediumId.jpeg") "image/jpeg" -> {
val out = FileOutputStream(path) val path = File(getCachePath(), "$mediumId.jpeg")
compressFormat = Bitmap.CompressFormat.JPEG val out = FileOutputStream(path)
it.compress(compressFormat, 100, out) compressFormat = Bitmap.CompressFormat.JPEG
return path.absolutePath it.compress(compressFormat, 100, out)
} else if (mimeType == "image/png") { return path.absolutePath
val path = File(getCachePath(), "$mediumId.png") }
val out = FileOutputStream(path)
compressFormat = Bitmap.CompressFormat.PNG "image/png" -> {
it.compress(compressFormat, 100, out) val path = File(getCachePath(), "$mediumId.png")
return path.absolutePath val out = FileOutputStream(path)
} else if (mimeType == "image/webp") { compressFormat = Bitmap.CompressFormat.PNG
val path = File(getCachePath(), "$mediumId.webp") it.compress(compressFormat, 100, out)
val out = FileOutputStream(path) return path.absolutePath
compressFormat = Bitmap.CompressFormat.WEBP_LOSSLESS }
it.compress(compressFormat, 100, out)
return path.absolutePath "image/webp" -> {
val path = File(getCachePath(), "$mediumId.webp")
val out = FileOutputStream(path)
compressFormat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Bitmap.CompressFormat.WEBP_LOSSLESS
}
else {
Bitmap.CompressFormat.WEBP
}
it.compress(compressFormat, 100, out)
return path.absolutePath
}
else -> {
return null
}
} }
} }
@ -1013,7 +1080,7 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
} }
} }
private fun getCachePath(): File? { private fun getCachePath(): File {
return this.context.run { return this.context.run {
val cachePath = File(this.cacheDir, "photo_gallery") val cachePath = File(this.cacheDir, "photo_gallery")
if (!cachePath.exists()) { if (!cachePath.exists()) {
@ -1025,6 +1092,6 @@ class PhotoGalleryPlugin : FlutterPlugin, MethodCallHandler {
private fun cleanCache() { private fun cleanCache() {
val cachePath = getCachePath() val cachePath = getCachePath()
cachePath?.deleteRecursively() cachePath.deleteRecursively()
} }
} }

View File

@ -83,8 +83,8 @@ class _MyAppState extends State<MyApp> {
...?_albums?.map( ...?_albums?.map(
(album) => GestureDetector( (album) => GestureDetector(
onTap: () => Navigator.of(context).push( onTap: () => Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(builder: (context) => AlbumPage(album)),
builder: (context) => AlbumPage(album))), ),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
ClipRRect( ClipRRect(
@ -95,8 +95,7 @@ class _MyAppState extends State<MyApp> {
width: gridWidth, width: gridWidth,
child: FadeInImage( child: FadeInImage(
fit: BoxFit.cover, fit: BoxFit.cover,
placeholder: placeholder: MemoryImage(kTransparentImage),
MemoryImage(kTransparentImage),
image: AlbumThumbnailProvider( image: AlbumThumbnailProvider(
album: album, album: album,
highQuality: true, highQuality: true,
@ -186,8 +185,9 @@ class AlbumPageState extends State<AlbumPage> {
children: <Widget>[ children: <Widget>[
...?_media?.map( ...?_media?.map(
(medium) => GestureDetector( (medium) => GestureDetector(
onTap: () => Navigator.of(context).push(MaterialPageRoute( onTap: () => Navigator.of(context).push(
builder: (context) => ViewerPage(medium))), MaterialPageRoute(builder: (context) => ViewerPage(medium)),
),
child: Container( child: Container(
color: Colors.grey[300], color: Colors.grey[300],
child: FadeInImage( child: FadeInImage(
@ -293,9 +293,7 @@ class _VideoProviderState extends State<VideoProvider> {
TextButton( TextButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
_controller!.value.isPlaying _controller!.value.isPlaying ? _controller!.pause() : _controller!.play();
? _controller!.pause()
: _controller!.play();
}); });
}, },
child: Icon( child: Icon(

View File

@ -34,7 +34,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
mediumId: mediumId, mediumId: mediumId,
completion: { (data: [String: Any?]?, error: Error?) -> Void in completion: { (data: [String: Any?]?, error: Error?) -> Void in
result(data) result(data)
}) }
)
} }
else if(call.method == "getThumbnail") { else if(call.method == "getThumbnail") {
let arguments = call.arguments as! Dictionary<String, AnyObject> let arguments = call.arguments as! Dictionary<String, AnyObject>
@ -49,7 +50,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
highQuality: highQuality, highQuality: highQuality,
completion: { (data: Data?, error: Error?) -> Void in completion: { (data: Data?, error: Error?) -> Void in
result(data) result(data)
}) }
)
} }
else if(call.method == "getAlbumThumbnail") { else if(call.method == "getAlbumThumbnail") {
let arguments = call.arguments as! Dictionary<String, AnyObject> let arguments = call.arguments as! Dictionary<String, AnyObject>
@ -68,7 +70,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
highQuality: highQuality, highQuality: highQuality,
completion: { (data: Data?, error: Error?) -> Void in completion: { (data: Data?, error: Error?) -> Void in
result(data) result(data)
}) }
)
} }
else if(call.method == "getFile") { else if(call.method == "getFile") {
let arguments = call.arguments as! Dictionary<String, AnyObject> let arguments = call.arguments as! Dictionary<String, AnyObject>
@ -79,7 +82,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
mimeType: mimeType, mimeType: mimeType,
completion: { (filepath: String?, error: Error?) -> Void in completion: { (filepath: String?, error: Error?) -> Void in
result(filepath?.replacingOccurrences(of: "file://", with: "")) result(filepath?.replacingOccurrences(of: "file://", with: ""))
}) }
)
} }
else if(call.method == "cleanCache") { else if(call.method == "cleanCache") {
cleanCache() cleanCache()
@ -254,7 +258,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
let bytes = image.jpegData(compressionQuality: CGFloat(70)) let bytes = image.jpegData(compressionQuality: CGFloat(70))
completion(bytes, nil) completion(bytes, nil)
}) }
)
return return
} }
@ -312,7 +317,8 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
let bytes = image.jpegData(compressionQuality: CGFloat(80)) let bytes = image.jpegData(compressionQuality: CGFloat(80))
completion(bytes, nil) completion(bytes, nil)
}) }
)
return return
} }
@ -366,25 +372,28 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
) )
} else if(asset.mediaType == PHAssetMediaType.video } else if(asset.mediaType == PHAssetMediaType.video
|| asset.mediaType == PHAssetMediaType.audio) { || asset.mediaType == PHAssetMediaType.audio) {
let options = PHVideoRequestOptions() let options = PHVideoRequestOptions()
options.version = .current options.version = .current
options.deliveryMode = .highQualityFormat options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true options.isNetworkAccessAllowed = true
manager.requestAVAsset(forVideo: asset, options: options, resultHandler: { (avAsset, avAudioMix, info) in manager.requestAVAsset(
DispatchQueue.main.async(execute: { forVideo: asset,
do { options: options,
let avAsset = avAsset as? AVURLAsset resultHandler: { (avAsset, avAudioMix, info) in
let data = try Data(contentsOf: avAsset!.url) DispatchQueue.main.async(execute: {
let fileExt = self.extractFileExtensionFromAsset(asset: asset) do {
let filepath = self.exportPathForAsset(asset: asset, ext: fileExt) let avAsset = avAsset as? AVURLAsset
try! data.write(to: filepath, options: .atomic) let data = try Data(contentsOf: avAsset!.url)
completion(filepath.absoluteString, nil) let fileExt = self.extractFileExtensionFromAsset(asset: asset)
} catch { let filepath = self.exportPathForAsset(asset: asset, ext: fileExt)
completion(nil, NSError(domain: "photo_gallery", code: 500, userInfo: nil)) try! data.write(to: filepath, options: .atomic)
} completion(filepath.absoluteString, nil)
}) } catch {
completion(nil, NSError(domain: "photo_gallery", code: 500, userInfo: nil))
}
})
} }
) )
} }
@ -406,11 +415,11 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
return nil return nil
} }
} }
private func getMediumFromAsset(asset: PHAsset) -> [String: Any?] { private func getMediumFromAsset(asset: PHAsset) -> [String: Any?] {
let mimeType = self.extractMimeTypeFromAsset(asset: asset) let mimeType = self.extractMimeTypeFromAsset(asset: asset)
let filename = self.extractFilenameFromAsset(asset: asset) let filename = self.extractFilenameFromAsset(asset: asset)
let size = self.extractSizeFromAsset(asset: asset) let size = self.extractSizeFromAsset(asset: asset)
return [ return [
"id": asset.localIdentifier, "id": asset.localIdentifier,
"filename": filename, "filename": filename,
@ -419,7 +428,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
"mimeType": mimeType, "mimeType": mimeType,
"height": asset.pixelHeight, "height": asset.pixelHeight,
"width": asset.pixelWidth, "width": asset.pixelWidth,
"size": size, "size": size,
"duration": NSInteger(asset.duration * 1000), "duration": NSInteger(asset.duration * 1000),
"creationDate": (asset.creationDate != nil) ? NSInteger(asset.creationDate!.timeIntervalSince1970 * 1000) : nil, "creationDate": (asset.creationDate != nil) ? NSInteger(asset.creationDate!.timeIntervalSince1970 * 1000) : nil,
"modifiedDate": (asset.modificationDate != nil) ? NSInteger(asset.modificationDate!.timeIntervalSince1970 * 1000) : nil "modifiedDate": (asset.modificationDate != nil) ? NSInteger(asset.modificationDate!.timeIntervalSince1970 * 1000) : nil
@ -429,7 +438,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
private func getMediumFromAssetAsync(asset: PHAsset, completion: @escaping ([String : Any?]?, Error?) -> Void) -> Void { private func getMediumFromAssetAsync(asset: PHAsset, completion: @escaping ([String : Any?]?, Error?) -> Void) -> Void {
let mimeType = self.extractMimeTypeFromAsset(asset: asset) let mimeType = self.extractMimeTypeFromAsset(asset: asset)
let filename = self.extractFilenameFromAsset(asset: asset) let filename = self.extractFilenameFromAsset(asset: asset)
let size = self.extractSizeFromAsset(asset: asset) let size = self.extractSizeFromAsset(asset: asset)
let manager = PHImageManager.default() let manager = PHImageManager.default()
manager.requestImageData( manager.requestImageData(
for: asset, for: asset,
@ -443,7 +452,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
"mimeType": mimeType, "mimeType": mimeType,
"height": asset.pixelHeight, "height": asset.pixelHeight,
"width": asset.pixelWidth, "width": asset.pixelWidth,
"size": size, "size": size,
"orientation": self.toOrientationValue(orientation: orientation), "orientation": self.toOrientationValue(orientation: orientation),
"duration": NSInteger(asset.duration * 1000), "duration": NSInteger(asset.duration * 1000),
"creationDate": (asset.creationDate != nil) ? NSInteger(asset.creationDate!.timeIntervalSince1970 * 1000) : nil, "creationDate": (asset.creationDate != nil) ? NSInteger(asset.creationDate!.timeIntervalSince1970 * 1000) : nil,
@ -452,7 +461,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
) )
} }
private func exportPathForAsset(asset: PHAsset, ext: String) -> URL { private func exportPathForAsset(asset: PHAsset, ext: String) -> URL {
let mediumId = asset.localIdentifier let mediumId = asset.localIdentifier
.replacingOccurrences(of: "/", with: "__") .replacingOccurrences(of: "/", with: "__")
@ -511,7 +520,7 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
return NSPredicate(format: "mediaType = %d", swiftType.rawValue) return NSPredicate(format: "mediaType = %d", swiftType.rawValue)
} }
private func extractFileExtensionFromUTI(uti: String?) -> String { private func extractFileExtensionFromUTI(uti: String?) -> String {
guard let assetUTI = uti else { guard let assetUTI = uti else {
return "" return ""
@ -561,14 +570,14 @@ public class SwiftPhotoGalleryPlugin: NSObject, FlutterPlugin {
} }
return asset.value(forKey: "filename") as? String return asset.value(forKey: "filename") as? String
} }
private func extractSizeFromAsset(asset: PHAsset) -> Int64? { private func extractSizeFromAsset(asset: PHAsset) -> Int64? {
let resources = PHAssetResource.assetResources(for: asset) let resources = PHAssetResource.assetResources(for: asset)
guard let resource = resources.first, guard let resource = resources.first,
let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong else { let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong else {
return nil return nil
} }
return Int64(bitPattern: UInt64(unsignedInt64)) return Int64(bitPattern: UInt64(unsignedInt64))
} }
private func extractTitleFromFilename(filename: String?) -> String? { private func extractTitleFromFilename(filename: String?) -> String? {