From e26b3682eca67ecf78bb6b930262f39346b7f952 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 23 Aug 2024 10:23:50 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=F0=9F=9A=80=20Update=20Dart?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/internal/plugin.dart | 249 +++++++++++++++-------------------- 1 file changed, 103 insertions(+), 146 deletions(-) diff --git a/lib/src/internal/plugin.dart b/lib/src/internal/plugin.dart index 2e7107c7..dbc20a5b 100644 --- a/lib/src/internal/plugin.dart +++ b/lib/src/internal/plugin.dart @@ -140,11 +140,11 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { PMFilter? filterOption, required PMPathFilter pathFilterOption, }) async { - if (onlyAll) { - assert(hasAll, 'If only is true, then the hasAll must be not null.'); + if (onlyAll && !hasAll) { + throw ArgumentError('onlyAll = true must follow hasAll = true'); } filterOption ??= FilterOptionGroup(); - final result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mGetAssetPathList, { 'type': type.value, @@ -154,9 +154,6 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { 'pathOption': pathFilterOption.toMap(), }, ); - if (result == null) { - return []; - } return ConvertUtils.convertToPathList( result.cast(), type: type, @@ -167,22 +164,22 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { Future requestPermissionExtend( PermissionRequestOption requestOption, ) async { - final int result = await _channel.invokeMethod( + final int result = await _channel.invokeMethod( PMConstants.mRequestPermissionExtend, requestOption.toMap(), - ) as int; + ); return PermissionState.values[result]; } Future getAssetCountFromPath(AssetPathEntity path) async { - final int result = await _channel.invokeMethod( + final int result = await _channel.invokeMethod( PMConstants.mGetAssetCountFromPath, { 'id': path.id, 'type': path.type.value, 'option': path.filterOption.toMap(), }, - ) as int; + ); return result; } @@ -194,8 +191,7 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { int size = 15, RequestType type = RequestType.common, }) async { - final Map result = - await _channel.invokeMethod>( + final Map result = await _channel.invokeMethod( PMConstants.mGetAssetListPaged, { 'id': id, @@ -204,8 +200,8 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { 'size': size, 'option': optionGroup.toMap(), }, - ) as Map; - return ConvertUtils.convertToAssetList(result.cast()); + ); + return ConvertUtils.convertToAssetList(result.cast()); } /// Asset in the specified range. @@ -216,8 +212,7 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { required int end, required PMFilter optionGroup, }) async { - final Map map = - await _channel.invokeMethod>( + final Map map = await _channel.invokeMethod( PMConstants.mGetAssetListRange, { 'id': id, @@ -226,9 +221,8 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { 'end': end, 'option': optionGroup.toMap(), }, - ) as Map; - - return ConvertUtils.convertToAssetList(map.cast()); + ); + return ConvertUtils.convertToAssetList(map.cast()); } void _injectParams( @@ -276,12 +270,12 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { PMProgressHandler? progressHandler, int subtype = 0, }) async { - final Map params = { + final Map params = { 'id': id, 'isOrigin': isOrigin, 'subtype': subtype, }; - _injectParams(params, progressHandler); + _injectParams(params.cast(), progressHandler); return _channel.invokeMethod(PMConstants.mGetFullFile, params); } @@ -293,14 +287,14 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { return _channel.invokeMethod(PMConstants.mOpenSetting); } - Future?> fetchEntityProperties(String id) { + Future fetchEntityProperties(String id) { return _channel.invokeMethod( PMConstants.mFetchEntityProperties, {'id': id}, ); } - Future?> fetchPathProperties( + Future fetchPathProperties( String id, RequestType type, PMFilter optionGroup, @@ -331,27 +325,28 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { } Future> deleteWithIds(List ids) async { - final List deleted = await _channel.invokeMethod>( + final List deleted = await _channel.invokeMethod( PMConstants.mDeleteWithIds, {'ids': ids}, - ) as List; + ); return deleted.cast(); } - Future> moveToTrash(List list) { - return _channel.invokeMethod( + Future> moveToTrash(List list) async { + final List result = await _channel.invokeMethod( PMConstants.mMoveToTrash, {'ids': list.map((e) => e.id).toList()}, - ).then((value) => value.cast()); + ); + return result.cast(); } - Future saveImage( + Future saveImage( typed_data.Uint8List data, { required String? title, String? desc, String? relativePath, }) async { - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mSaveImage, { 'image': data, @@ -361,72 +356,52 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { ...onlyAddPermission, }, ); - if (result == null) { - return null; - } - return ConvertUtils.convertMapToAsset( - result.cast(), - title: title, - ); + return ConvertUtils.convertMapToAsset(result.cast(), title: title); } - Future saveImageWithPath( - String path, { + Future saveImageWithPath( + String inputFilePath, { required String title, String? desc, String? relativePath, }) async { - final File file = File(path); + final File file = File(inputFilePath); if (!file.existsSync()) { - assert(false, 'File must exists.'); - return null; + throw ArgumentError('The input file does not exists.'); } - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mSaveImageWithPath, { - 'path': path, + 'path': inputFilePath, 'title': title, 'desc': desc ?? '', 'relativePath': relativePath, ...onlyAddPermission, }, ); - if (result == null) { - return null; - } - return ConvertUtils.convertMapToAsset( - result.cast(), - title: title, - ); + return ConvertUtils.convertMapToAsset(result.cast(), title: title); } - Future saveVideo( - File file, { + Future saveVideo( + File inputFile, { required String? title, String? desc, String? relativePath, }) async { - if (!file.existsSync()) { - assert(false, 'File must exists.'); - return null; + if (!inputFile.existsSync()) { + throw ArgumentError('The input file does not exists.'); } - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mSaveVideo, { - 'path': file.absolute.path, + 'path': inputFile.absolute.path, 'title': title, 'desc': desc ?? '', 'relativePath': relativePath, ...onlyAddPermission, }, ); - if (result == null) { - return null; - } - return ConvertUtils.convertMapToAsset( - result.cast(), - title: title, - ); + return ConvertUtils.convertMapToAsset(result.cast(), title: title); } /// Check whether the asset has been deleted. @@ -442,24 +417,24 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { if (PlatformUtils.isOhos) { return ''; } - return await _channel.invokeMethod( + return await _channel.invokeMethod( PMConstants.mSystemVersion, - ) as String; + ); } Future getLatLngAsync(AssetEntity entity) async { if (Platform.isAndroid) { final int version = int.parse(await getSystemVersion()); if (version >= 29) { - final Map? map = await _channel.invokeMethod( + final Map map = await _channel.invokeMethod( PMConstants.mGetLatLngAndroidQ, {'id': entity.id}, ); // 将返回的数据传入map return LatLng( - latitude: map?['lat'] as double?, - longitude: map?['lng'] as double?, + latitude: (map['lat'] as num?)?.toDouble(), + longitude: (map['lng'] as num?)?.toDouble(), ); } } @@ -471,13 +446,13 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { int subtype = 0, }) async { if (Platform.isIOS || Platform.isMacOS) { - return await _channel.invokeMethod( + return await _channel.invokeMethod( PMConstants.mGetTitleAsync, { 'id': entity.id, 'subtype': subtype, }, - ) as String; + ); } return entity.title ?? ''; } @@ -498,8 +473,7 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { if (PlatformUtils.isOhos) { return []; } - final Map result = - await _channel.invokeMethod>( + final Map result = await _channel.invokeMethod( PMConstants.mGetSubPath, { 'id': pathEntity.id, @@ -507,37 +481,29 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { 'albumType': pathEntity.albumType, 'option': pathEntity.filterOption.toMap(), }, - ) as Map; - final Map items = result['list'] as Map; + ); + final items = result['list'] as Map; return ConvertUtils.convertToPathList( - items.cast(), + items.cast(), type: pathEntity.type, filterOption: pathEntity.filterOption, ); } - Future copyAssetToGallery( + Future copyAssetToGallery( AssetEntity asset, AssetPathEntity pathEntity, ) async { if (pathEntity.isAll) { - assert( - pathEntity.isAll, + throw ArgumentError( "You can't copy the asset into the album containing all the pictures.", ); - return null; } - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mCopyAsset, {'assetId': asset.id, 'galleryId': pathEntity.id}, ); - if (result == null) { - return null; - } - return ConvertUtils.convertMapToAsset( - result.cast(), - title: asset.title, - ); + return ConvertUtils.convertMapToAsset(result.cast(), title: asset.title); } Future favoriteAsset(String id, bool favorite) async { @@ -603,7 +569,7 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { return entity.mimeType; } if (Platform.isIOS || Platform.isMacOS) { - return _channel.invokeMethod( + return _channel.invokeMethod( PMConstants.mGetMimeTypeAsync, {'id': entity.id}, ); @@ -614,13 +580,16 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { Future getAssetCount({ PMFilter? filterOption, RequestType type = RequestType.common, - }) { + }) async { final filter = filterOption ?? PMFilter.defaultValue(); - - return _channel.invokeMethod(PMConstants.mGetAssetCount, { - 'type': type.value, - 'option': filter.toMap(), - }).then((v) => v ?? 0); + final count = await _channel.invokeMethod( + PMConstants.mGetAssetCount, + { + 'type': type.value, + 'option': filter.toMap(), + }, + ); + return count; } Future> getAssetListWithRange({ @@ -628,30 +597,26 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { required int end, RequestType type = RequestType.common, PMFilter? filterOption, - }) { + }) async { final filter = filterOption ?? PMFilter.defaultValue(); - return _channel.invokeMethod(PMConstants.mGetAssetsByRange, { - 'type': type.value, - 'start': start, - 'end': end, - 'option': filter.toMap(), - }).then((value) { - if (value == null) { - return []; - } - return ConvertUtils.convertToAssetList( - value.cast(), - ); - }); + final Map result = await _channel.invokeMethod( + PMConstants.mGetAssetsByRange, + { + 'type': type.value, + 'start': start, + 'end': end, + 'option': filter.toMap(), + }, + ); + return ConvertUtils.convertToAssetList(result.cast()); } Future isLocallyAvailable(String id, {bool isOrigin = false}) async { if (Platform.isIOS || Platform.isMacOS) { - final bool result = await _channel.invokeMethod( + return await _channel.invokeMethod( PMConstants.mIsLocallyAvailable, {'id': id, 'isOrigin': isOrigin}, - ) as bool; - return result; + ); } return true; @@ -667,7 +632,7 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { } mixin IosPlugin on BasePlugin { - Future saveLivePhoto({ + Future saveLivePhoto({ required File imageFile, required File videoFile, required String? title, @@ -676,14 +641,12 @@ mixin IosPlugin on BasePlugin { }) async { assert(Platform.isIOS || Platform.isMacOS); if (!imageFile.existsSync()) { - assert(false, 'File of the image must exist.'); - return null; + throw ArgumentError('The image file does not exists.'); } if (!videoFile.existsSync()) { - assert(false, 'videoFile must exists.'); - return null; + throw ArgumentError('The video file does not exists.'); } - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mSaveLivePhoto, { 'imagePath': imageFile.absolute.path, @@ -694,16 +657,10 @@ mixin IosPlugin on BasePlugin { ...onlyAddPermission, }, ); - if (result == null) { - return null; - } - return ConvertUtils.convertMapToAsset( - result.cast(), - title: title, - ); + return ConvertUtils.convertMapToAsset(result.cast(), title: title); } - Future iosCreateAlbum( + Future iosCreateAlbum( String name, bool isRoot, AssetPathEntity? parent, @@ -716,20 +673,20 @@ mixin IosPlugin on BasePlugin { if (!isRoot && parent != null) { map['folderId'] = parent.id; } - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mCreateAlbum, map, ); - if (result == null) { - return null; - } if (result['errorMsg'] != null) { - return null; + throw PlatformException( + code: PMConstants.mCreateAlbum, + message: result['errorMsg'], + ); } return AssetPathEntity.fromId(result['id'] as String); } - Future iosCreateFolder( + Future iosCreateFolder( String name, bool isRoot, AssetPathEntity? parent, @@ -742,15 +699,15 @@ mixin IosPlugin on BasePlugin { if (!isRoot && parent != null) { map['folderId'] = parent.id; } - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mCreateFolder, map, ); - if (result == null) { - return null; - } if (result['errorMsg'] != null) { - return null; + throw PlatformException( + code: PMConstants.mCreateFolder, + message: result['errorMsg'], + ); } return AssetPathEntity.fromId(result['id'] as String, albumType: 2); } @@ -760,26 +717,26 @@ mixin IosPlugin on BasePlugin { AssetPathEntity path, ) async { assert(Platform.isIOS || Platform.isMacOS); - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mRemoveInAlbum, - { + { 'assetId': entities.map((AssetEntity e) => e.id).toList(), 'pathId': path.id, }, ); - return result?['msg'] == null; + return result['msg'] == null; } Future iosDeleteCollection(AssetPathEntity path) async { assert(Platform.isIOS || Platform.isMacOS); - final Map? result = await _channel.invokeMethod( + final Map result = await _channel.invokeMethod( PMConstants.mDeleteAlbum, { 'id': path.id, 'type': path.albumType, }, ); - return result?['errorMsg'] == null; + return result['errorMsg'] == null; } } @@ -795,7 +752,7 @@ mixin AndroidPlugin on BasePlugin { AssetEntity entity, AssetPathEntity target, ) async { - final Map? result = await _channel.invokeMethod( + final result = await _channel.invokeMethod( PMConstants.mMoveAssetToPath, {'assetId': entity.id, 'albumId': target.id}, ); @@ -813,7 +770,7 @@ mixin AndroidPlugin on BasePlugin { final result = await _channel.invokeMethod( PMConstants.mColumnNames, ); - if (result is List) { + if (result is List) { return result.map((e) => e.toString()).toList(); } return result ?? []; @@ -825,7 +782,7 @@ mixin OhosPlugin on BasePlugin { final result = await _channel.invokeMethod( PMConstants.mColumnNames, ); - if (result is List) { + if (result is List) { return result.map((e) => e.toString()).toList(); } return result ?? []; From a2876fd95f069a8362386603bf51f1872039c59b Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 23 Aug 2024 10:24:07 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=9A=80=20Update=20Android?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../photo_manager/core/PhotoManager.kt | 33 +++------- .../core/PhotoManagerDeleteManager.kt | 2 +- .../photo_manager/core/PhotoManagerPlugin.kt | 18 +----- .../photo_manager/core/cache/ScopedCache.kt | 6 +- .../core/entity/filter/CommonFilterOption.kt | 12 ++-- .../core/entity/filter/CustomOption.kt | 2 +- .../core/entity/filter/FilterOption.kt | 2 +- .../core/utils/AndroidQDBUtils.kt | 63 +++++++++---------- .../photo_manager/core/utils/DBUtils.kt | 63 ++++++++++--------- .../photo_manager/core/utils/IDBUtils.kt | 59 +++++++++-------- 10 files changed, 109 insertions(+), 151 deletions(-) diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt index 61620aca..3e1d1fac 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt @@ -92,10 +92,6 @@ class PhotoManager(private val context: Context) { val frame = option.frame try { val asset = dbUtils.getAssetEntity(context, id) - if (asset == null) { - resultHandler.replyError("The asset not found!") - return - } ThumbnailUtil.getThumbnail( context, asset, @@ -115,10 +111,6 @@ class PhotoManager(private val context: Context) { fun getOriginBytes(id: String, resultHandler: ResultHandler, needLocationPermission: Boolean) { val asset = dbUtils.getAssetEntity(context, id) - if (asset == null) { - resultHandler.replyError("The asset not found") - return - } try { val byteArray = dbUtils.getOriginBytes(context, asset, needLocationPermission) resultHandler.reply(byteArray) @@ -154,7 +146,7 @@ class PhotoManager(private val context: Context) { } } val galleryEntity = dbUtils.getAssetPathEntityFromId(context, id, type, option) - if (galleryEntity != null && option.containsPathModified) { + if (option.containsPathModified) { dbUtils.injectModifiedDate(context, galleryEntity) } @@ -171,7 +163,7 @@ class PhotoManager(private val context: Context) { title: String, description: String, relativePath: String? - ): AssetEntity? { + ): AssetEntity { return dbUtils.saveImage(context, image, title, description, relativePath) } @@ -180,14 +172,11 @@ class PhotoManager(private val context: Context) { title: String, description: String, relativePath: String? - ): AssetEntity? { + ): AssetEntity { return dbUtils.saveImage(context, path, title, description, relativePath) } - fun saveVideo(path: String, title: String, desc: String, relativePath: String?): AssetEntity? { - if (!File(path).exists()) { - return null - } + fun saveVideo(path: String, title: String, desc: String, relativePath: String?): AssetEntity { return dbUtils.saveVideo(context, path, title, desc, relativePath) } @@ -213,10 +202,6 @@ class PhotoManager(private val context: Context) { fun copyToGallery(assetId: String, galleryId: String, resultHandler: ResultHandler) { try { val assetEntity = dbUtils.copyToGallery(context, assetId, galleryId) - if (assetEntity == null) { - resultHandler.reply(null) - return - } resultHandler.reply(ConvertUtils.convertAsset(assetEntity)) } catch (e: Exception) { LogUtils.error(e) @@ -227,10 +212,6 @@ class PhotoManager(private val context: Context) { fun moveToGallery(assetId: String, albumId: String, resultHandler: ResultHandler) { try { val assetEntity = dbUtils.moveToGallery(context, assetId, albumId) - if (assetEntity == null) { - resultHandler.reply(null) - return - } resultHandler.reply(ConvertUtils.convertAsset(assetEntity)) } catch (e: Exception) { LogUtils.error(e) @@ -243,13 +224,13 @@ class PhotoManager(private val context: Context) { resultHandler.reply(result) } - fun fetchEntityProperties(id: String): AssetEntity? { + fun fetchEntityProperties(id: String): AssetEntity { return dbUtils.getAssetEntity(context, id) } - fun getUri(id: String): Uri? { + fun getUri(id: String): Uri { val asset = dbUtils.getAssetEntity(context, id) - return asset?.getUri() + return asset.getUri() } private val cacheFutures = ArrayList>() diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerDeleteManager.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerDeleteManager.kt index 5d1a4454..03ca3f4a 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerDeleteManager.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerDeleteManager.kt @@ -80,7 +80,7 @@ class PhotoManagerDeleteManager(val context: Context, private var activity: Acti private fun handleAndroidRDelete(resultCode: Int) { if (resultCode == Activity.RESULT_OK) { androidRHandler?.apply { - val ids = call?.argument>("ids") ?: return@apply + val ids = call.argument>("ids") ?: return@apply androidRHandler?.reply(ids) } } else { diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt index 83814947..8dec3418 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt @@ -423,11 +423,7 @@ class PhotoManagerPlugin( Methods.fetchEntityProperties -> { val id = call.argument("id")!! val asset = photoManager.fetchEntityProperties(id) - val assetResult = if (asset != null) { - ConvertUtils.convertAsset(asset) - } else { - null - } + val assetResult = ConvertUtils.convertAsset(asset) resultHandler.reply(assetResult) } @@ -468,10 +464,6 @@ class PhotoManagerPlugin( val desc = call.argument("desc") ?: "" val relativePath = call.argument("relativePath") ?: "" val entity = photoManager.saveImage(image, title, desc, relativePath) - if (entity == null) { - resultHandler.reply(null) - return - } val map = ConvertUtils.convertAsset(entity) resultHandler.reply(map) } catch (e: Exception) { @@ -488,10 +480,6 @@ class PhotoManagerPlugin( val relativePath = call.argument("relativePath") ?: "" val entity = photoManager.saveImage(imagePath, title, desc, relativePath) - if (entity == null) { - resultHandler.reply(null) - return - } val map = ConvertUtils.convertAsset(entity) resultHandler.reply(map) } catch (e: Exception) { @@ -508,10 +496,6 @@ class PhotoManagerPlugin( val relativePath = call.argument("relativePath") ?: "" val entity = photoManager.saveVideo(videoPath, title, desc, relativePath) - if (entity == null) { - resultHandler.reply(null) - return - } val map = ConvertUtils.convertAsset(entity) resultHandler.reply(map) } catch (e: Exception) { diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt index f97c10eb..a2222119 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt @@ -13,7 +13,7 @@ import java.io.FileOutputStream @RequiresApi(Build.VERSION_CODES.Q) class ScopedCache { companion object { - private const val filenamePrefix = "pm_" + private const val FILENAME_PREFIX = "pm_" } fun getCacheFileFromEntity( @@ -49,14 +49,14 @@ class ScopedCache { private fun getCacheFile(context: Context, assetEntity: AssetEntity, isOrigin: Boolean): File { val originString = if (isOrigin) "_o" else "" - val name = "$filenamePrefix${assetEntity.id}${originString}_${assetEntity.displayName}" + val name = "$FILENAME_PREFIX${assetEntity.id}${originString}_${assetEntity.displayName}" return File(context.cacheDir, name) } fun clearFileCache(context: Context) { val files = context.cacheDir?.listFiles()?.filterNotNull() ?: return for (file in files) { - if (file.name.startsWith(filenamePrefix)) { + if (file.name.startsWith(FILENAME_PREFIX)) { file.delete() } } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CommonFilterOption.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CommonFilterOption.kt index 86128d51..b8744103 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CommonFilterOption.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CommonFilterOption.kt @@ -170,15 +170,15 @@ class FilterCond { lateinit var durationConstraint: DurationConstraint companion object { - private const val widthKey = MediaStore.Files.FileColumns.WIDTH - private const val heightKey = MediaStore.Files.FileColumns.HEIGHT + private const val WIDTH_KEY = MediaStore.Files.FileColumns.WIDTH + private const val HEIGHT_KEY = MediaStore.Files.FileColumns.HEIGHT @SuppressLint("InlinedApi") - private const val durationKey = MediaStore.Video.VideoColumns.DURATION + private const val DURATION_KEY = MediaStore.Video.VideoColumns.DURATION } fun sizeCond(): String = - "$widthKey >= ? AND $widthKey <= ? AND $heightKey >= ? AND $heightKey <=?" + "$WIDTH_KEY >= ? AND $WIDTH_KEY <= ? AND $HEIGHT_KEY >= ? AND $HEIGHT_KEY <=?" fun sizeArgs(): Array { return arrayOf( @@ -192,9 +192,9 @@ class FilterCond { } fun durationCond(): String { - val baseCond = "$durationKey >=? AND $durationKey <=?" + val baseCond = "$DURATION_KEY >=? AND $DURATION_KEY <=?" if (durationConstraint.allowNullable) { - return "( $durationKey IS NULL OR ( $baseCond ) )" + return "( $DURATION_KEY IS NULL OR ( $baseCond ) )" } return baseCond } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CustomOption.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CustomOption.kt index 967b3681..648eb6af 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CustomOption.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/CustomOption.kt @@ -37,4 +37,4 @@ class CustomOption(private val map: Map<*, *>) : FilterOption() { } return "( $where )" } -} \ No newline at end of file +} diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/FilterOption.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/FilterOption.kt index 798bcb52..49a005ab 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/FilterOption.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/entity/filter/FilterOption.kt @@ -10,4 +10,4 @@ abstract class FilterOption { args: ArrayList, needAnd: Boolean = true ): String -} \ No newline at end of file +} diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt index 9b430bc7..b716a719 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt @@ -50,7 +50,7 @@ object AndroidQDBUtils : IDBUtils { selections, args.toTypedArray(), option.orderByCondString() - ) ?: return list + ) val nameMap = HashMap() val countMap = HashMap() cursor.use { @@ -96,7 +96,7 @@ object AndroidQDBUtils : IDBUtils { selections, args.toTypedArray(), option.orderByCondString() - ) ?: return list + ) cursor.use { val assetPathEntity = AssetPathEntity( PhotoManager.ALL_ID, @@ -160,10 +160,10 @@ object AndroidQDBUtils : IDBUtils { selection, args.toTypedArray(), sortOrder - ) ?: return list + ) cursor.use { cursorWithRange(it, page * size, size) { cursor -> - cursor.toAssetEntity(context)?.apply { + cursor.toAssetEntity(context).apply { list.add(this) } } @@ -200,10 +200,10 @@ object AndroidQDBUtils : IDBUtils { selection, args.toTypedArray(), sortOrder - ) ?: return list + ) cursor.use { cursorWithRange(it, start, pageSize) { cursor -> - cursor.toAssetEntity(context)?.apply { + cursor.toAssetEntity(context).apply { list.add(this) } } @@ -223,7 +223,7 @@ object AndroidQDBUtils : IDBUtils { context: Context, id: String, checkIfExists: Boolean - ): AssetEntity? { + ): AssetEntity { val selection = "$_ID = ?" val args = arrayOf(id) val cursor = context.contentResolver.logQuery( @@ -232,10 +232,10 @@ object AndroidQDBUtils : IDBUtils { selection, args, null - ) ?: return null + ) cursor.use { return if (it.moveToNext()) it.toAssetEntity(context, checkIfExists) - else null + else throwMsg("Failed to find asset $id") } } @@ -244,12 +244,10 @@ object AndroidQDBUtils : IDBUtils { pathId: String, type: Int, option: FilterOption - ): AssetPathEntity? { + ): AssetPathEntity { val isAll = pathId == "" val args = ArrayList() - val where = option.makeWhere(type, args) - val idSelection: String if (isAll) { idSelection = "" @@ -257,7 +255,6 @@ object AndroidQDBUtils : IDBUtils { idSelection = "AND $BUCKET_ID = ?" args.add(pathId) } - val selection = "$BUCKET_ID IS NOT NULL $where $idSelection" val cursor = context.contentResolver.logQuery( @@ -265,7 +262,7 @@ object AndroidQDBUtils : IDBUtils { IDBUtils.storeBucketKeys, selection, args.toTypedArray(), null - ) ?: return null + ) val name: String val assetCount: Int cursor.use { @@ -273,7 +270,7 @@ object AndroidQDBUtils : IDBUtils { name = it.getString(1) ?: "" assetCount = it.count } else { - return null + throwMsg("Failed to find the path $pathId") } } return AssetPathEntity(pathId, name, assetCount, type, isAll) @@ -281,25 +278,25 @@ object AndroidQDBUtils : IDBUtils { override fun getExif(context: Context, id: String): ExifInterface? { return try { - val asset = getAssetEntity(context, id) ?: return null + val asset = getAssetEntity(context, id) val uri = getUri(asset) val originalUri = MediaStore.setRequireOriginal(uri) val inputStream = context.contentResolver.openInputStream(originalUri) ?: return null ExifInterface(inputStream) } catch (e: Exception) { + LogUtils.error(e) null } } override fun getFilePath(context: Context, id: String, origin: Boolean): String? { - val assetEntity = getAssetEntity(context, id) ?: return null - val filePath = - if (shouldUseScopedCache) { - val file = scopedCache.getCacheFileFromEntity(context, assetEntity, origin) - file?.absolutePath - } else { - assetEntity.path - } + val assetEntity = getAssetEntity(context, id) + val filePath = if (shouldUseScopedCache) { + val file = scopedCache.getCacheFileFromEntity(context, assetEntity, origin) + file?.absolutePath + } else { + assetEntity.path + } return filePath } @@ -317,22 +314,18 @@ object AndroidQDBUtils : IDBUtils { outputStream.use { os -> inputStream?.use { os.write(it.readBytes()) } val byteArray = os.toByteArray() - if (LogUtils.isLog) { - LogUtils.info("The asset ${asset.id} origin byte length : ${byteArray.count()}") - } + LogUtils.info("The asset ${asset.id} origin byte length : ${byteArray.count()}") return byteArray } } - override fun copyToGallery(context: Context, assetId: String, galleryId: String): AssetEntity? { + override fun copyToGallery(context: Context, assetId: String, galleryId: String): AssetEntity { val (currentGalleryId, _) = getSomeInfo(context, assetId) ?: throwMsg("Cannot get gallery id of $assetId") if (galleryId == currentGalleryId) { throwMsg("No copy required, because the target gallery is the same as the current one.") } val asset = getAssetEntity(context, assetId) - ?: throwMsg("No copy required, because the target gallery is the same as the current one.") - val copyKeys = arrayListOf( DISPLAY_NAME, TITLE, @@ -357,7 +350,7 @@ object AndroidQDBUtils : IDBUtils { idSelection, arrayOf(assetId), null - ) ?: throwMsg("Cannot find asset.") + ) if (!cursor.moveToNext()) { throwMsg("Cannot find asset.") } @@ -390,7 +383,7 @@ object AndroidQDBUtils : IDBUtils { return getAssetEntity(context, insertedId) } - override fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity? { + override fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity { val (currentGalleryId, _) = getSomeInfo(context, assetId) ?: throwMsg("Cannot get gallery id of $assetId") @@ -436,7 +429,7 @@ object AndroidQDBUtils : IDBUtils { ).map { it.toString() } .toTypedArray(), null - ) ?: return false + ) cursor.use { var count = 0 while (it.moveToNext()) { @@ -485,7 +478,7 @@ object AndroidQDBUtils : IDBUtils { "$BUCKET_ID = ?", arrayOf(galleryId), null - ) ?: return null + ) cursor.use { if (!cursor.moveToNext()) { return null @@ -502,7 +495,7 @@ object AndroidQDBUtils : IDBUtils { "$_ID = ?", arrayOf(assetId), null - ) ?: return null + ) cursor.use { if (!cursor.moveToNext()) { return null diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt index 9aac052e..7eb05014 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt @@ -42,7 +42,7 @@ object DBUtils : IDBUtils { selection, args.toTypedArray(), null - ) ?: return list + ) cursor.use { while (it.moveToNext()) { val id = it.getString(0) @@ -77,7 +77,7 @@ object DBUtils : IDBUtils { selections, args.toTypedArray(), null - ) ?: return list + ) cursor.use { if (it.moveToNext()) { val countIndex = projection.indexOf("count(1)") @@ -100,7 +100,7 @@ object DBUtils : IDBUtils { pathId: String, type: Int, option: FilterOption - ): AssetPathEntity? { + ): AssetPathEntity { val args = ArrayList() val where = option.makeWhere(type, args) val idSelection: String @@ -118,7 +118,7 @@ object DBUtils : IDBUtils { selection, args.toTypedArray(), null - ) ?: return null + ) cursor.use { return if (it.moveToNext()) { val id = it.getString(0) @@ -126,7 +126,7 @@ object DBUtils : IDBUtils { val assetCount = it.getInt(2) AssetPathEntity(id, name, assetCount, 0) } else { - null + throwMsg("Failed to find the path $pathId") } } } @@ -159,10 +159,10 @@ object DBUtils : IDBUtils { selection, args.toTypedArray(), sortOrder - ) ?: return list + ) cursor.use { while (it.moveToNext()) { - it.toAssetEntity(context)?.apply { + it.toAssetEntity(context).apply { list.add(this) } } @@ -200,10 +200,10 @@ object DBUtils : IDBUtils { selection, args.toTypedArray(), sortOrder - ) ?: return list + ) cursor.use { while (it.moveToNext()) { - it.toAssetEntity(context)?.apply { + it.toAssetEntity(context).apply { list.add(this) } } @@ -215,7 +215,7 @@ object DBUtils : IDBUtils { context: Context, id: String, checkIfExists: Boolean - ): AssetEntity? { + ): AssetEntity { val keys = (IDBUtils.storeImageKeys + IDBUtils.storeVideoKeys + locationKeys + IDBUtils.typeKeys).distinct() .toTypedArray() @@ -228,12 +228,12 @@ object DBUtils : IDBUtils { selection, args, null - ) ?: return null + ) cursor.use { return if (it.moveToNext()) { it.toAssetEntity(context, checkIfExists) } else { - null + throwMsg("Failed to find asset $id") } } } @@ -247,25 +247,27 @@ object DBUtils : IDBUtils { } override fun getExif(context: Context, id: String): ExifInterface? { - val asset = getAssetEntity(context, id) ?: return null + val asset = getAssetEntity(context, id) val file = File(asset.path) return if (file.exists()) ExifInterface(asset.path) else null } - override fun getFilePath(context: Context, id: String, origin: Boolean): String? { - val assetEntity = getAssetEntity(context, id) ?: return null + override fun getFilePath(context: Context, id: String, origin: Boolean): String { + val assetEntity = getAssetEntity(context, id) return assetEntity.path } - override fun copyToGallery(context: Context, assetId: String, galleryId: String): AssetEntity? { - val (currentGalleryId, _) = getSomeInfo(context, assetId) - ?: throw RuntimeException("Cannot get gallery id of $assetId") + override fun copyToGallery(context: Context, assetId: String, galleryId: String): AssetEntity { + val (currentGalleryId, _) = getSomeInfo(context, assetId) ?: throwMsg( + "Cannot get gallery id of $assetId" + ) if (galleryId == currentGalleryId) { - throw RuntimeException("No copy required, because the target gallery is the same as the current one.") + throwMsg( + "No copy required, because the target gallery is the same as the current one." + ) } val cr = context.contentResolver val asset = getAssetEntity(context, assetId) - ?: throw RuntimeException("No copy required, because the target gallery is the same as the current one.") val copyKeys = arrayListOf( MediaStore.MediaColumns.DISPLAY_NAME, @@ -289,9 +291,9 @@ object DBUtils : IDBUtils { idSelection, arrayOf(assetId), null - ) ?: throw RuntimeException("Cannot find asset .") + ) if (!cursor.moveToNext()) { - throw RuntimeException("Cannot find asset .") + throwMsg("Cannot find asset .") } val insertUri = MediaStoreUtils.getInsertUri(mediaType) val galleryInfo = getGalleryInfo(context, galleryId) ?: throwMsg("Cannot find gallery info") @@ -304,10 +306,9 @@ object DBUtils : IDBUtils { put(MediaStore.MediaColumns.DATA, outputPath) } - val insertedUri = - cr.insert(insertUri, cv) ?: throw RuntimeException("Cannot insert new asset.") + val insertedUri = cr.insert(insertUri, cv) ?: throwMsg("Cannot insert new asset.") val outputStream = cr.openOutputStream(insertedUri) - ?: throw RuntimeException("Cannot open output stream for $insertedUri.") + ?: throwMsg("Cannot open output stream for $insertedUri.") val inputStream = File(asset.path).inputStream() inputStream.use { outputStream.use { @@ -317,11 +318,11 @@ object DBUtils : IDBUtils { cursor.close() val insertedId = insertedUri.lastPathSegment - ?: throw RuntimeException("Cannot open output stream for $insertedUri.") + ?: throwMsg("Cannot open output stream for $insertedUri.") return getAssetEntity(context, insertedId) } - override fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity? { + override fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity { val (currentGalleryId, _) = getSomeInfo(context, assetId) ?: throwMsg("Cannot get gallery id of $assetId") @@ -339,7 +340,7 @@ object DBUtils : IDBUtils { idSelection, arrayOf(assetId), null - ) ?: throwMsg("Cannot find $assetId path") + ) val targetPath = if (cursor.moveToNext()) { val srcPath = cursor.getString(0) @@ -379,7 +380,7 @@ object DBUtils : IDBUtils { null, null, null - ) ?: return false + ) cursor.use { while (it.moveToNext()) { val id = it.getString(_ID) @@ -414,7 +415,7 @@ object DBUtils : IDBUtils { "${MediaStore.MediaColumns._ID} = ?", arrayOf(assetId), null - ) ?: return null + ) cursor.use { if (!it.moveToNext()) { return null @@ -437,7 +438,7 @@ object DBUtils : IDBUtils { "${MediaStore.MediaColumns.BUCKET_ID} = ?", arrayOf(galleryId), null - ) ?: return null + ) cursor.use { if (!it.moveToNext()) { return null diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt index eef4d15f..8ff0d30a 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt @@ -126,7 +126,7 @@ interface IDBUtils { option: FilterOption ): List - fun getAssetEntity(context: Context, id: String, checkIfExists: Boolean = true): AssetEntity? + fun getAssetEntity(context: Context, id: String, checkIfExists: Boolean = true): AssetEntity fun getMediaType(type: Int): Int { return when (type) { @@ -170,13 +170,13 @@ interface IDBUtils { // return getDouble(getColumnIndex(columnName)) // } - fun Cursor.toAssetEntity(context: Context, checkIfExists: Boolean = true): AssetEntity? { + fun Cursor.toAssetEntity(context: Context, checkIfExists: Boolean = true): AssetEntity { + val id = getLong(_ID) val path = getString(DATA) if (checkIfExists && path.isNotBlank() && !File(path).exists()) { - return null + throw RuntimeException("Asset ($id) does not exists at its path ($path).") } - val id = getLong(_ID) val date = if (isAboveAndroidQ) { var tmpTime = getLong(DATE_TAKEN) / 1000 if (tmpTime == 0L) { @@ -244,7 +244,7 @@ interface IDBUtils { pathId: String, type: Int, option: FilterOption - ): AssetPathEntity? + ): AssetPathEntity fun getFilePath(context: Context, id: String, origin: Boolean): String? @@ -254,7 +254,7 @@ interface IDBUtils { title: String, desc: String, relativePath: String? - ): AssetEntity? { + ): AssetEntity { var inputStream = ByteArrayInputStream(bytes) fun refreshInputStream() { inputStream = ByteArrayInputStream(bytes) @@ -323,7 +323,7 @@ interface IDBUtils { title: String, desc: String, relativePath: String? - ): AssetEntity? { + ): AssetEntity { fromPath.checkDirs() val file = File(fromPath) var inputStream = FileInputStream(file) @@ -402,7 +402,7 @@ interface IDBUtils { title: String, desc: String, relativePath: String? - ): AssetEntity? { + ): AssetEntity { fromPath.checkDirs() val file = File(fromPath) var inputStream = FileInputStream(file) @@ -476,7 +476,7 @@ interface IDBUtils { contentUri: Uri, values: ContentValues, shouldKeepPath: Boolean = false, - ): AssetEntity? { + ): AssetEntity { val cr = context.contentResolver val uri = cr.insert(contentUri, values) ?: throw RuntimeException("Cannot insert the new asset.") @@ -493,9 +493,6 @@ interface IDBUtils { fun assetExists(context: Context, id: String): Boolean { val columns = arrayOf(_ID) context.contentResolver.logQuery(allUri, columns, "$_ID = ?", arrayOf(id), null).use { - if (it == null) { - return false - } return it.count >= 1 } } @@ -512,9 +509,14 @@ interface IDBUtils { if (LogUtils.isLog) { val splitter = "".padStart(40, '-') LogUtils.info("log error row $id start $splitter") - val cursor = - context.contentResolver.logQuery(allUri, null, "$_ID = ?", arrayOf(id), null) - cursor?.use { + val cursor = context.contentResolver.logQuery( + allUri, + null, + "$_ID = ?", + arrayOf(id), + null + ) + cursor.use { val names = it.columnNames if (it.moveToNext()) { for (i in 0 until names.count()) { @@ -542,9 +544,9 @@ interface IDBUtils { return "$orderBy LIMIT $pageSize OFFSET $start" } - fun copyToGallery(context: Context, assetId: String, galleryId: String): AssetEntity? + fun copyToGallery(context: Context, assetId: String, galleryId: String): AssetEntity - fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity? + fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity fun getSomeInfo(context: Context, assetId: String): Pair? @@ -601,7 +603,7 @@ interface IDBUtils { selection, ids.toTypedArray(), null - ) ?: return emptyList() + ) val list = ArrayList() val map = HashMap() cursor.use { @@ -638,7 +640,7 @@ interface IDBUtils { arrayOf(pathId), sortOrder ) - } ?: return null + } cursor.use { if (it.moveToNext()) { return it.getLong(DATE_MODIFIED) @@ -649,10 +651,9 @@ interface IDBUtils { fun getColumnNames(context: Context): List { val cr = context.contentResolver - cr.logQuery(allUri, null, null, null, null)?.use { + cr.logQuery(allUri, null, null, null, null).use { return it.columnNames.toList() } - return emptyList() } fun ContentResolver.logQuery( @@ -661,7 +662,7 @@ interface IDBUtils { selection: String?, selectionArgs: Array?, sortOrder: String? - ): Cursor? { + ): Cursor { fun log(logFunc: (log: String) -> Unit, cursor: Cursor?) { if (LogUtils.isLog) { val sb = StringBuilder() @@ -681,7 +682,7 @@ interface IDBUtils { try { val cursor = query(uri, projection, selection, selectionArgs, sortOrder) log(LogUtils::info, cursor) - return cursor + return cursor ?: throw RuntimeException("Failed to obtain the cursor.") } catch (e: Exception) { log(LogUtils::error, null) LogUtils.error("happen query error", e) @@ -695,7 +696,7 @@ interface IDBUtils { val where = option.makeWhere(requestType, args, false) val order = option.orderByCondString() cr.logQuery(allUri, arrayOf(_ID), where, args.toTypedArray(), order).use { - return it?.count ?: 0 + return it.count } } @@ -724,7 +725,7 @@ interface IDBUtils { val order = option.orderByCondString() cr.logQuery(allUri, arrayOf(_ID), where, args.toTypedArray(), order).use { - return it?.count ?: 0 + return it.count } } @@ -740,19 +741,17 @@ interface IDBUtils { val args = ArrayList() val where = option.makeWhere(requestType, args, false) val order = option.orderByCondString() - cr.logQuery(allUri, keys(), where, args.toTypedArray(), order)?.use { + cr.logQuery(allUri, keys(), where, args.toTypedArray(), order).use { val result = ArrayList() it.moveToPosition(start - 1) while (it.moveToNext()) { - val asset = it.toAssetEntity(context, false) ?: continue + val asset = it.toAssetEntity(context, false) result.add(asset) - if (result.count() == end - start) { break } } - return result - } ?: return emptyList() + } } } From d4854c13304b944f95ddc313bc0d3a4d493bd971 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 1 Oct 2024 20:56:23 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=F0=9F=90=9B=20Fix=20return=20values?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fluttercandies/photo_manager/core/utils/IDBUtils.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt index 58f32bd5..d9fb83e7 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt @@ -312,7 +312,7 @@ interface IDBUtils { inputStream, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values, - )?.copy(orientation = orientation ?: rotationDegrees) + ) } fun saveImage( @@ -391,7 +391,7 @@ interface IDBUtils { MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values, shouldKeepPath - )?.copy(orientation = orientation ?: rotationDegrees) + ) } fun saveVideo( @@ -470,7 +470,7 @@ interface IDBUtils { MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values, shouldKeepPath - )?.copy(orientation = orientation ?: rotationDegrees) + ) } private fun insertUri( From 5eed08ccdf4e3345abd57c56ec68da1a315e1ef6 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 1 Oct 2024 21:52:56 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=9A=80=20Improve=20type=20promotions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../photo_manager/core/PhotoManager.kt | 51 +++--- .../photo_manager/core/PhotoManagerPlugin.kt | 6 +- .../photo_manager/core/cache/ScopedCache.kt | 7 +- .../core/utils/AndroidQDBUtils.kt | 22 +-- .../photo_manager/core/utils/DBUtils.kt | 28 ++-- .../photo_manager/core/utils/IDBUtils.kt | 152 +++++++++--------- .../page/copy_to_another_gallery_example.dart | 2 +- .../page/developer/develop_index_page.dart | 14 +- .../page/developer/issues_page/issue_979.dart | 19 +-- example/lib/page/save_image_example.dart | 6 +- lib/src/internal/editor.dart | 24 +-- lib/src/types/entity.dart | 3 +- 12 files changed, 177 insertions(+), 157 deletions(-) diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt index efce14dc..4d12d557 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManager.kt @@ -91,11 +91,15 @@ class PhotoManager(private val context: Context) { val frame = option.frame try { val asset = dbUtils.getAssetEntity(context, id) + if (asset == null) { + resultHandler.replyError("201", "Failed to find the asset $id") + return; + } ThumbnailUtil.getThumbnail( context, asset, - option.width, - option.height, + width, + height, format, quality, frame, @@ -110,6 +114,10 @@ class PhotoManager(private val context: Context) { fun getOriginBytes(id: String, resultHandler: ResultHandler, needLocationPermission: Boolean) { val asset = dbUtils.getAssetEntity(context, id) + if (asset == null) { + resultHandler.replyError("202", "Failed to find the asset $id") + return; + } try { val byteArray = dbUtils.getOriginBytes(context, asset, needLocationPermission) resultHandler.reply(byteArray) @@ -127,28 +135,24 @@ class PhotoManager(private val context: Context) { fun fetchPathProperties(id: String, type: Int, option: FilterOption): AssetPathEntity? { if (id == ALL_ID) { val allGalleryList = dbUtils.getAssetPathList(context, type, option) - return if (allGalleryList.isEmpty()) { - null - } else { - // make is all to the gallery list - allGalleryList.run { - var assetCount = 0 - for (item in this) { - assetCount += item.assetCount - } - AssetPathEntity(ALL_ID, ALL_ALBUM_NAME, assetCount, type, true).apply { - if (option.containsPathModified) { - dbUtils.injectModifiedDate(context, this) - } + return if (allGalleryList.isEmpty()) null + else allGalleryList.run { + var assetCount = 0 + for (item in this) { + assetCount += item.assetCount + } + AssetPathEntity(ALL_ID, ALL_ALBUM_NAME, assetCount, type, true).apply { + if (option.containsPathModified) { + dbUtils.injectModifiedDate(context, this) } } } } - val galleryEntity = dbUtils.getAssetPathEntityFromId(context, id, type, option) + val galleryEntity = + dbUtils.getAssetPathEntityFromId(context, id, type, option) ?: return null if (option.containsPathModified) { dbUtils.injectModifiedDate(context, galleryEntity) } - return galleryEntity } @@ -165,7 +169,15 @@ class PhotoManager(private val context: Context) { relativePath: String, orientation: Int? ): AssetEntity { - return dbUtils.saveImage(context, bytes, filename, title, description, relativePath, orientation) + return dbUtils.saveImage( + context, + bytes, + filename, + title, + description, + relativePath, + orientation + ) } fun saveImage( @@ -232,12 +244,13 @@ class PhotoManager(private val context: Context) { resultHandler.reply(result) } - fun fetchEntityProperties(id: String): AssetEntity { + fun fetchEntityProperties(id: String): AssetEntity? { return dbUtils.getAssetEntity(context, id) } fun getUri(id: String): Uri { val asset = dbUtils.getAssetEntity(context, id) + ?: throw RuntimeException("Failed to find asset $id") return asset.getUri() } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt index 75c81f59..23998203 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/PhotoManagerPlugin.kt @@ -435,7 +435,11 @@ class PhotoManagerPlugin( Methods.fetchEntityProperties -> { val id = call.argument("id")!! val asset = photoManager.fetchEntityProperties(id) - val assetResult = ConvertUtils.convertAsset(asset) + val assetResult = if (asset != null) { + ConvertUtils.convertAsset(asset) + } else { + null + } resultHandler.reply(assetResult) } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt index a2222119..5ff5dd51 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/cache/ScopedCache.kt @@ -6,6 +6,7 @@ import android.os.Build import androidx.annotation.RequiresApi import com.fluttercandies.photo_manager.core.entity.AssetEntity import com.fluttercandies.photo_manager.core.utils.AndroidQDBUtils +import com.fluttercandies.photo_manager.core.utils.AndroidQDBUtils.throwIdNotFound import com.fluttercandies.photo_manager.util.LogUtils import java.io.File import java.io.FileOutputStream @@ -20,7 +21,7 @@ class ScopedCache { context: Context, assetEntity: AssetEntity, isOrigin: Boolean - ): File? { + ): File { val assetId = assetEntity.id val targetFile = getCacheFile(context, assetEntity, isOrigin) if (targetFile.exists()) { @@ -29,7 +30,7 @@ class ScopedCache { val contentResolver = context.contentResolver val uri = AndroidQDBUtils.getUri(assetId, assetEntity.type, isOrigin) if (uri == Uri.EMPTY) { - return null + throwIdNotFound(assetId) } try { LogUtils.info( @@ -42,7 +43,7 @@ class ScopedCache { } } catch (e: Exception) { LogUtils.error("Caching $assetId [origin: $isOrigin] error", e) - return null + throw e } return targetFile } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt index b716a719..5900002d 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/AndroidQDBUtils.kt @@ -223,7 +223,7 @@ object AndroidQDBUtils : IDBUtils { context: Context, id: String, checkIfExists: Boolean - ): AssetEntity { + ): AssetEntity? { val selection = "$_ID = ?" val args = arrayOf(id) val cursor = context.contentResolver.logQuery( @@ -235,7 +235,7 @@ object AndroidQDBUtils : IDBUtils { ) cursor.use { return if (it.moveToNext()) it.toAssetEntity(context, checkIfExists) - else throwMsg("Failed to find asset $id") + else null } } @@ -244,7 +244,7 @@ object AndroidQDBUtils : IDBUtils { pathId: String, type: Int, option: FilterOption - ): AssetPathEntity { + ): AssetPathEntity? { val isAll = pathId == "" val args = ArrayList() val where = option.makeWhere(type, args) @@ -270,7 +270,7 @@ object AndroidQDBUtils : IDBUtils { name = it.getString(1) ?: "" assetCount = it.count } else { - throwMsg("Failed to find the path $pathId") + return null } } return AssetPathEntity(pathId, name, assetCount, type, isAll) @@ -278,7 +278,7 @@ object AndroidQDBUtils : IDBUtils { override fun getExif(context: Context, id: String): ExifInterface? { return try { - val asset = getAssetEntity(context, id) + val asset = getAssetEntity(context, id) ?: return null val uri = getUri(asset) val originalUri = MediaStore.setRequireOriginal(uri) val inputStream = context.contentResolver.openInputStream(originalUri) ?: return null @@ -289,11 +289,11 @@ object AndroidQDBUtils : IDBUtils { } } - override fun getFilePath(context: Context, id: String, origin: Boolean): String? { - val assetEntity = getAssetEntity(context, id) + override fun getFilePath(context: Context, id: String, origin: Boolean): String { + val assetEntity = getAssetEntity(context, id) ?: throwIdNotFound(id) val filePath = if (shouldUseScopedCache) { val file = scopedCache.getCacheFileFromEntity(context, assetEntity, origin) - file?.absolutePath + file.absolutePath } else { assetEntity.path } @@ -325,7 +325,7 @@ object AndroidQDBUtils : IDBUtils { if (galleryId == currentGalleryId) { throwMsg("No copy required, because the target gallery is the same as the current one.") } - val asset = getAssetEntity(context, assetId) + val asset = getAssetEntity(context, assetId) ?: throwIdNotFound(assetId) val copyKeys = arrayListOf( DISPLAY_NAME, TITLE, @@ -380,7 +380,7 @@ object AndroidQDBUtils : IDBUtils { val insertedId = insertedUri.lastPathSegment ?: throwMsg("Cannot open output stream for $insertedUri.") - return getAssetEntity(context, insertedId) + return getAssetEntity(context, insertedId) ?: throwIdNotFound(assetId) } override fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity { @@ -398,7 +398,7 @@ object AndroidQDBUtils : IDBUtils { } val count = cr.update(allUri, contentValues, idSelection, arrayOf(assetId)) if (count > 0) { - return getAssetEntity(context, assetId) + return getAssetEntity(context, assetId) ?: throwIdNotFound(assetId) } throwMsg("Cannot update $assetId relativePath") } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt index 7eb05014..27cb68ad 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/DBUtils.kt @@ -100,7 +100,7 @@ object DBUtils : IDBUtils { pathId: String, type: Int, option: FilterOption - ): AssetPathEntity { + ): AssetPathEntity? { val args = ArrayList() val where = option.makeWhere(type, args) val idSelection: String @@ -125,9 +125,7 @@ object DBUtils : IDBUtils { val name = it.getString(1) ?: "" val assetCount = it.getInt(2) AssetPathEntity(id, name, assetCount, 0) - } else { - throwMsg("Failed to find the path $pathId") - } + } else null } } @@ -215,7 +213,7 @@ object DBUtils : IDBUtils { context: Context, id: String, checkIfExists: Boolean - ): AssetEntity { + ): AssetEntity? { val keys = (IDBUtils.storeImageKeys + IDBUtils.storeVideoKeys + locationKeys + IDBUtils.typeKeys).distinct() .toTypedArray() @@ -230,11 +228,8 @@ object DBUtils : IDBUtils { null ) cursor.use { - return if (it.moveToNext()) { - it.toAssetEntity(context, checkIfExists) - } else { - throwMsg("Failed to find asset $id") - } + return if (it.moveToNext()) it.toAssetEntity(context, checkIfExists) + else null } } @@ -247,13 +242,13 @@ object DBUtils : IDBUtils { } override fun getExif(context: Context, id: String): ExifInterface? { - val asset = getAssetEntity(context, id) + val asset = getAssetEntity(context, id) ?: return null val file = File(asset.path) return if (file.exists()) ExifInterface(asset.path) else null } override fun getFilePath(context: Context, id: String, origin: Boolean): String { - val assetEntity = getAssetEntity(context, id) + val assetEntity = getAssetEntity(context, id) ?: throwIdNotFound(id) return assetEntity.path } @@ -267,7 +262,8 @@ object DBUtils : IDBUtils { ) } val cr = context.contentResolver - val asset = getAssetEntity(context, assetId) + val asset = + getAssetEntity(context, assetId) ?: throwMsg("Failed to find the asset $assetId") val copyKeys = arrayListOf( MediaStore.MediaColumns.DISPLAY_NAME, @@ -293,7 +289,7 @@ object DBUtils : IDBUtils { null ) if (!cursor.moveToNext()) { - throwMsg("Cannot find asset .") + throwIdNotFound(assetId) } val insertUri = MediaStoreUtils.getInsertUri(mediaType) val galleryInfo = getGalleryInfo(context, galleryId) ?: throwMsg("Cannot find gallery info") @@ -319,7 +315,7 @@ object DBUtils : IDBUtils { cursor.close() val insertedId = insertedUri.lastPathSegment ?: throwMsg("Cannot open output stream for $insertedUri.") - return getAssetEntity(context, insertedId) + return getAssetEntity(context, insertedId) ?: throwIdNotFound(assetId) } override fun moveToGallery(context: Context, assetId: String, galleryId: String): AssetEntity { @@ -360,7 +356,7 @@ object DBUtils : IDBUtils { val count = cr.update(allUri, contentValues, idSelection, arrayOf(assetId)) if (count > 0) { - return getAssetEntity(context, assetId) + return getAssetEntity(context, assetId) ?: throwIdNotFound(assetId) } throwMsg("Cannot update $assetId relativePath") } diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt index d9fb83e7..a68a76a7 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt @@ -125,7 +125,7 @@ interface IDBUtils { option: FilterOption ): List - fun getAssetEntity(context: Context, id: String, checkIfExists: Boolean = true): AssetEntity + fun getAssetEntity(context: Context, id: String, checkIfExists: Boolean = true): AssetEntity? fun getMediaType(type: Int): Int { return when (type) { @@ -165,9 +165,9 @@ interface IDBUtils { return getLong(getColumnIndex(columnName)) } -// fun Cursor.getDouble(columnName: String): Double { -// return getDouble(getColumnIndex(columnName)) -// } + fun Cursor.getDouble(columnName: String): Double { + return getDouble(getColumnIndex(columnName)) + } fun Cursor.toAssetEntity(context: Context, checkIfExists: Boolean = true): AssetEntity { val id = getLong(_ID) @@ -243,9 +243,7 @@ interface IDBUtils { pathId: String, type: Int, option: FilterOption - ): AssetPathEntity - - fun getFilePath(context: Context, id: String, origin: Boolean): String? + ): AssetPathEntity? fun saveImage( context: Context, @@ -481,16 +479,15 @@ interface IDBUtils { shouldKeepPath: Boolean = false, ): AssetEntity { val cr = context.contentResolver - val uri = - cr.insert(contentUri, values) ?: throw RuntimeException("Cannot insert the new asset.") + val uri = cr.insert(contentUri, values) ?: throwMsg("Cannot insert new asset.") val id = ContentUris.parseId(uri) if (!shouldKeepPath) { val outputStream = cr.openOutputStream(uri) - ?: throw RuntimeException("Cannot open the output stream for $uri.") + ?: throwMsg("Cannot open the output stream for $uri.") outputStream.use { os -> inputStream.use { it.copyTo(os) } } } cr.notifyChange(uri, null) - return getAssetEntity(context, id.toString()) + return getAssetEntity(context, id.toString()) ?: throwIdNotFound(id) } fun assetExists(context: Context, id: String): Boolean { @@ -500,6 +497,8 @@ interface IDBUtils { } } + fun getFilePath(context: Context, id: String, origin: Boolean): String + fun getExif(context: Context, id: String): ExifInterface? fun getOriginBytes( @@ -508,29 +507,6 @@ interface IDBUtils { needLocationPermission: Boolean ): ByteArray - fun logRowWithId(context: Context, id: String) { - if (LogUtils.isLog) { - val splitter = "".padStart(40, '-') - LogUtils.info("log error row $id start $splitter") - val cursor = context.contentResolver.logQuery( - allUri, - null, - "$_ID = ?", - arrayOf(id), - null - ) - cursor.use { - val names = it.columnNames - if (it.moveToNext()) { - for (i in 0 until names.count()) { - LogUtils.info("${names[i]} : ${it.getString(i)}") - } - } - } - LogUtils.info("log error row $id end $splitter") - } - } - fun getMediaUri(context: Context, id: Long, type: Int): String { val uri = getUri(id, type, false) return uri.toString() @@ -542,6 +518,7 @@ interface IDBUtils { option: FilterOption ): List + // Nullable for implementations. fun getSortOrder(start: Int, pageSize: Int, filterOption: FilterOption): String? { val orderBy = filterOption.orderByCondString() return "$orderBy LIMIT $pageSize OFFSET $start" @@ -558,7 +535,7 @@ interface IDBUtils { 1 -> ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) 2 -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id) 3 -> ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id) - else -> return Uri.EMPTY + else -> throwMsg("Unexpected asset type $type") } if (isOrigin) { @@ -567,10 +544,6 @@ interface IDBUtils { return uri } - fun throwMsg(msg: String): Nothing { - throw RuntimeException(msg) - } - fun removeAllExistsAssets(context: Context): Boolean fun clearFileCache(context: Context) {} @@ -659,40 +632,6 @@ interface IDBUtils { } } - fun ContentResolver.logQuery( - uri: Uri, - projection: Array?, - selection: String?, - selectionArgs: Array?, - sortOrder: String? - ): Cursor { - fun log(logFunc: (log: String) -> Unit, cursor: Cursor?) { - if (LogUtils.isLog) { - val sb = StringBuilder() - sb.appendLine("uri: $uri") - sb.appendLine("projection: ${projection?.joinToString(", ")}") - sb.appendLine("selection: $selection") - sb.appendLine("selectionArgs: ${selectionArgs?.joinToString(", ")}") - sb.appendLine("sortOrder: $sortOrder") - // format ? in selection and selectionArgs to display in log - val sql = selection?.replace("?", "%s")?.format(*selectionArgs ?: emptyArray()) - sb.appendLine("sql: $sql") - sb.appendLine("cursor count: ${cursor?.count}") - logFunc(sb.toString()) - } - } - - try { - val cursor = query(uri, projection, selection, selectionArgs, sortOrder) - log(LogUtils::info, cursor) - return cursor ?: throw RuntimeException("Failed to obtain the cursor.") - } catch (e: Exception) { - log(LogUtils::error, null) - LogUtils.error("happen query error", e) - throw e - } - } - fun getAssetCount(context: Context, option: FilterOption, requestType: Int): Int { val cr = context.contentResolver val args = ArrayList() @@ -757,4 +696,71 @@ interface IDBUtils { return result } } + + fun ContentResolver.logQuery( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor { + fun log(logFunc: (log: String) -> Unit, cursor: Cursor?) { + if (LogUtils.isLog) { + val sb = StringBuilder() + sb.appendLine("uri: $uri") + sb.appendLine("projection: ${projection?.joinToString(", ")}") + sb.appendLine("selection: $selection") + sb.appendLine("selectionArgs: ${selectionArgs?.joinToString(", ")}") + sb.appendLine("sortOrder: $sortOrder") + // format ? in selection and selectionArgs to display in log + val sql = selection?.replace("?", "%s")?.format(*selectionArgs ?: emptyArray()) + sb.appendLine("sql: $sql") + sb.appendLine("cursor count: ${cursor?.count}") + logFunc(sb.toString()) + } + } + + try { + val cursor = query(uri, projection, selection, selectionArgs, sortOrder) + log(LogUtils::info, cursor) + return cursor ?: throwMsg("Failed to obtain the cursor.") + } catch (e: Exception) { + log(LogUtils::error, null) + LogUtils.error("happen query error", e) + throw e + } + } + + fun logRowWithId(context: Context, id: String) { + if (LogUtils.isLog) { + val splitter = "".padStart(40, '-') + LogUtils.info("log error row $id start $splitter") + val cursor = context.contentResolver.logQuery( + allUri, + null, + "$_ID = ?", + arrayOf(id), + null + ) + cursor.use { + val names = it.columnNames + if (it.moveToNext()) { + for (i in 0 until names.count()) { + LogUtils.info("${names[i]} : ${it.getString(i)}") + } + } + } + LogUtils.info("log error row $id end $splitter") + } + } + + @Throws(RuntimeException::class) + fun throwMsg(msg: String): Nothing { + throw RuntimeException(msg) + } + + @Throws(RuntimeException::class) + fun throwIdNotFound(id: Any): Nothing { + throwMsg("Failed to find asset $id") + } } diff --git a/example/lib/page/copy_to_another_gallery_example.dart b/example/lib/page/copy_to_another_gallery_example.dart index 19cc072c..570c22ab 100644 --- a/example/lib/page/copy_to_another_gallery_example.dart +++ b/example/lib/page/copy_to_another_gallery_example.dart @@ -87,7 +87,7 @@ class _CopyToAnotherGalleryPageState extends State { if (targetGallery == null) { return; } - final AssetEntity? result = await PhotoManager.editor.copyAssetToPath( + final AssetEntity result = await PhotoManager.editor.copyAssetToPath( asset: widget.assetEntity, pathEntity: targetGallery!, ); diff --git a/example/lib/page/developer/develop_index_page.dart b/example/lib/page/developer/develop_index_page.dart index 62fe1c20..d1d2e70c 100644 --- a/example/lib/page/developer/develop_index_page.dart +++ b/example/lib/page/developer/develop_index_page.dart @@ -219,13 +219,11 @@ class _DeveloperIndexPageState extends State { onDone: () async { client.close(); Log.d('the video file length = ${f.lengthSync()}'); - final AssetEntity? result = - await PhotoManager.editor.saveVideo(f, title: title); - if (result != null) { - Log.d('result : ${(await result.originFile)?.path}'); - } else { - Log.d('result is null'); - } + final AssetEntity result = await PhotoManager.editor.saveVideo( + f, + title: title, + ); + Log.d('result : ${(await result.originFile)?.path}'); }, ); } @@ -269,7 +267,7 @@ class _DeveloperIndexPageState extends State { videoFile: videoFile, title: 'preview_0', ); - print('save live photo result : ${assets?.id}'); + print('save live photo result : ${assets.id}'); } finally { imgFile?.deleteSync(); videoFile?.deleteSync(); diff --git a/example/lib/page/developer/issues_page/issue_979.dart b/example/lib/page/developer/issues_page/issue_979.dart index 1d92b95b..5e73fde2 100644 --- a/example/lib/page/developer/issues_page/issue_979.dart +++ b/example/lib/page/developer/issues_page/issue_979.dart @@ -38,17 +38,14 @@ class _Issue979State extends State with IssueBase { try { final file = await AssetsUtils.downloadJpeg(); final name = file.path.split('/').last; - final asset = - await PhotoManager.editor.saveImageWithPath(file.path, title: name); - - if (asset != null) { - final id = asset.id; - final width = asset.width; - final height = asset.height; - addLog('The save id = $id, width = $width, height = $height'); - } else { - addLog('The save asset is null'); - } + final asset = await PhotoManager.editor.saveImageWithPath( + file.path, + title: name, + ); + final id = asset.id; + final width = asset.width; + final height = asset.height; + addLog('The save id = $id, width = $width, height = $height'); } catch (e) { addLog('Save error : $e'); } diff --git a/example/lib/page/save_image_example.dart b/example/lib/page/save_image_example.dart index 4900ed46..45351fa0 100644 --- a/example/lib/page/save_image_example.dart +++ b/example/lib/page/save_image_example.dart @@ -161,7 +161,7 @@ class _SaveMediaExampleState extends State { }, onDone: () async { await checkRequest(() async { - final AssetEntity? asset = + final AssetEntity asset = await PhotoManager.editor.saveVideo(file, title: name); showToast('saved asset: $asset'); Log.d('saved asset: $asset'); @@ -193,7 +193,7 @@ class _SaveMediaExampleState extends State { Future saveImage(typed_data.Uint8List uint8List) async { await checkRequest(() async { - final AssetEntity? asset = await PhotoManager.editor.saveImage( + final AssetEntity asset = await PhotoManager.editor.saveImage( uint8List, filename: '${DateTime.now().millisecondsSinceEpoch}.jpg', ); @@ -215,7 +215,7 @@ class _SaveMediaExampleState extends State { onDone: () async { Log.d('write image to file success: $file'); await checkRequest(() async { - final AssetEntity? asset = + final AssetEntity asset = await PhotoManager.editor.saveImageWithPath( file.path, title: '${DateTime.now().millisecondsSinceEpoch}.jpg', diff --git a/lib/src/internal/editor.dart b/lib/src/internal/editor.dart index a972009d..946dcd25 100644 --- a/lib/src/internal/editor.dart +++ b/lib/src/internal/editor.dart @@ -71,7 +71,7 @@ class Editor { /// [orientation] is only available on Android. It could be useful when /// some devices cannot recognizes the asset's size info well. /// {@endtemplate} - Future saveImage( + Future saveImage( typed_data.Uint8List data, { required String filename, String? title, @@ -98,7 +98,7 @@ class Editor { /// {@macro photo_manager.Editor.RelativePathWhenSaving} /// /// {@macro photo_manager.Editor.OrientationWhenSaving} - Future saveImageWithPath( + Future saveImageWithPath( String filePath, { String? title, String? desc, @@ -123,7 +123,7 @@ class Editor { /// {@macro photo_manager.Editor.RelativePathWhenSaving} /// /// {@macro photo_manager.Editor.OrientationWhenSaving} - Future saveVideo( + Future saveVideo( File file, { String? title, String? desc, @@ -143,7 +143,7 @@ class Editor { /// /// - Android: Produce a copy of the original file. /// - iOS/macOS: Make a soft link to the target file. - Future copyAssetToPath({ + Future copyAssetToPath({ required AssetEntity asset, required AssetPathEntity pathEntity, }) { @@ -260,7 +260,7 @@ class DarwinEditor { /// Sets the favorite status of the given [entity]. /// /// Returns the updated [AssetEntity] if the operation was successful; otherwise, `null`. - Future favoriteAsset({ + Future favoriteAsset({ required AssetEntity entity, required bool favorite, }) async { @@ -268,7 +268,10 @@ class DarwinEditor { if (result) { return entity.copyWith(isFavorite: favorite); } - return null; + throw StateError( + 'Failed to favorite the asset ' + '${entity.id} for unknown reason', + ); } /// Save Live Photo to the gallery from the given [imageFile] and [videoFile]. @@ -280,7 +283,7 @@ class DarwinEditor { /// BAD: "my_live_photo_20240123_123456.jpg" /// BAD: "my_live_photo_20240123_123456.mov" /// BAD: "my_live_photo_20240123_123456.heic" - Future saveLivePhoto({ + Future saveLivePhoto({ required File imageFile, required File videoFile, required String title, @@ -339,7 +342,7 @@ class OhosEditor { /// Sets the favorite status of the given [entity]. /// /// Returns the updated [AssetEntity] if the operation was successful; otherwise, `null`. - Future favoriteAsset({ + Future favoriteAsset({ required AssetEntity entity, required bool favorite, }) async { @@ -347,6 +350,9 @@ class OhosEditor { if (result) { return entity.copyWith(isFavorite: favorite); } - return null; + throw StateError( + 'Failed to favorite the asset ' + '${entity.id} for unknown reason', + ); } } diff --git a/lib/src/types/entity.dart b/lib/src/types/entity.dart index 16a8d4c3..f9741816 100644 --- a/lib/src/types/entity.dart +++ b/lib/src/types/entity.dart @@ -377,8 +377,7 @@ class AssetEntity { /// Refresh the property of [AssetPathEntity] from the given ID. static Future _obtainAssetFromId(String id) async { - final Map? result = - await plugin.fetchEntityProperties(id); + final Map? result = await plugin.fetchEntityProperties(id); if (result == null) { return null; } From 439d6dff4a14f9dabfbc032e56eb7a75f63174f1 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 1 Oct 2024 23:24:48 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=94=8A=20Improve=20logs=20in=20Darwin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Classes/PMPlugin.m | 8 ++++++-- ios/Classes/core/PMManager.m | 29 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ios/Classes/PMPlugin.m b/ios/Classes/PMPlugin.m index 8fc0ff95..13568aba 100644 --- a/ios/Classes/PMPlugin.m +++ b/ios/Classes/PMPlugin.m @@ -613,8 +613,12 @@ - (void)handleMethodResultHandler:(ResultHandler *)handler manager:(PMManager *) } else if ([@"favoriteAsset" isEqualToString:call.method]) { NSString *id = call.arguments[@"id"]; BOOL favorite = [call.arguments[@"favorite"] boolValue]; - BOOL favoriteResult = [manager favoriteWithId:id favorite:favorite]; - [handler reply:@(favoriteResult)]; + @try { + BOOL favoriteResult = [manager favoriteWithId:id favorite:favorite]; + [handler reply:@(favoriteResult)]; + } @catch (NSObject *error) { + [handler replyError:error]; + } } else if ([@"requestCacheAssetsThumb" isEqualToString:call.method]) { NSArray *ids = call.arguments[@"ids"]; PMThumbLoadOption *option = [PMThumbLoadOption optionDict:call.arguments[@"option"]]; diff --git a/ios/Classes/core/PMManager.m b/ios/Classes/core/PMManager.m index 504bb34a..4ec77ff2 100644 --- a/ios/Classes/core/PMManager.m +++ b/ios/Classes/core/PMManager.m @@ -1170,9 +1170,9 @@ - (void)saveImage:(NSData *)data filename:(NSString *)filename desc:(NSString *)desc block:(AssetBlockResult)block { - __block NSString *assetId = nil; - [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"save image with data, length: %lu, filename:%@, desc: %@", (unsigned long)data.length, filename, desc]]; + [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"Saving image with data, length: %lu, filename: %@, desc: %@", (unsigned long)data.length, filename, desc]]; + __block NSString *assetId = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ PHAssetCreationRequest *request = @@ -1187,10 +1187,10 @@ - (void)saveImage:(NSData *)data } completionHandler:^(BOOL success, NSError *error) { if (success) { - [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"create asset : id = %@", assetId]]; + [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"Created image %@", assetId]]; block([self getAssetEntity:assetId], nil); } else { - NSLog(@"create fail"); + [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"Save image with data failed %@, reason = %@", assetId, error]]; block(nil, error); } }]; @@ -1200,7 +1200,7 @@ - (void)saveImageWithPath:(NSString *)path filename:(NSString *)filename desc:(NSString *)desc block:(AssetBlockResult)block { - [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"save image with path: %@ filename:%@, desc: %@", path, filename, desc]]; + [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"Saving image with path: %@ filename: %@, desc: %@", path, filename, desc]]; __block NSString *assetId = nil; [[PHPhotoLibrary sharedPhotoLibrary] @@ -1221,6 +1221,7 @@ - (void)saveImageWithPath:(NSString *)path [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"create asset : id = %@", assetId]]; block([self getAssetEntity:assetId], nil); } else { + [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"Save image with path failed %@, reason = %@", assetId, error]]; block(nil, error); } }]; @@ -1230,7 +1231,8 @@ - (void)saveVideo:(NSString *)path filename:(NSString *)filename desc:(NSString *)desc block:(AssetBlockResult)block { - [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"save video with path: %@, filename: %@, desc %@", path, filename, desc]]; + [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"Saving video with path: %@, filename: %@, desc %@", path, filename, desc]]; + NSURL *fileURL = [NSURL fileURLWithPath:path]; __block NSString *assetId = nil; [[PHPhotoLibrary sharedPhotoLibrary] @@ -1246,7 +1248,7 @@ - (void)saveVideo:(NSString *)path [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"create asset : id = %@", assetId]]; block([self getAssetEntity:assetId], nil); } else { - NSLog(@"create fail, error: %@", error); + [PMLogUtils.sharedInstance info: [NSString stringWithFormat:@"Save video with path failed %@, reason = %@", assetId, error]]; block(nil, error); } }]; @@ -1257,10 +1259,10 @@ - (void)saveLivePhoto:(NSString *)imagePath title:(NSString *)title desc:(NSString *)desc block:(AssetBlockResult)block { - [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"save LivePhoto with imagePath: %@, videoPath: %@, filename: %@, desc %@", - imagePath, videoPath, title, desc]]; + [PMLogUtils.sharedInstance info:[NSString stringWithFormat:@"Saving Live Photo with imagePath: %@, videoPath: %@, filename: %@, desc: %@", imagePath, videoPath, title, desc]]; NSURL *imageURL = [NSURL fileURLWithPath:imagePath]; NSURL *videoURL = [NSURL fileURLWithPath:videoPath]; + __block NSString *assetId = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ @@ -1405,8 +1407,8 @@ - (PHAssetCollection *)getCollectionWithId:(NSString *)galleryId { } - (void)copyAssetWithId:(NSString *)id -toGallery:(NSString *)gallery -block:(void (^)(PMAssetEntity *entity, NSObject *error))block { + toGallery:(NSString *)gallery + block:(void (^)(PMAssetEntity *entity, NSObject *error))block { PMAssetEntity *assetEntity = [self getAssetEntity:id]; if (!assetEntity) { @@ -1415,15 +1417,16 @@ - (void)copyAssetWithId:(NSString *)id return; } - __block PHAssetCollection *collection = [self getCollectionWithId:gallery]; + PHAssetCollection *collection = [self getCollectionWithId:gallery]; if (!collection) { block(nil, [NSString stringWithFormat:@"Collection [%@] not found.", gallery]); return; } + NSString *collectionId = collection.localIdentifier; if (![collection canPerformEditOperation:PHCollectionEditOperationAddContent]) { - block(nil, @"The collection cannot perform content adding operation."); + block(nil, [NSString stringWithFormat:@"The collection %@ cannot perform content adding operation.", collectionId]); return; } From 26f72df4d23974fa97468af3d7b77c960e783d3b Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 1 Oct 2024 23:24:56 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=8E=A8=20Format=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/lib/page/save_image_example.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example/lib/page/save_image_example.dart b/example/lib/page/save_image_example.dart index 45351fa0..7b858c43 100644 --- a/example/lib/page/save_image_example.dart +++ b/example/lib/page/save_image_example.dart @@ -215,8 +215,7 @@ class _SaveMediaExampleState extends State { onDone: () async { Log.d('write image to file success: $file'); await checkRequest(() async { - final AssetEntity asset = - await PhotoManager.editor.saveImageWithPath( + final AssetEntity asset = await PhotoManager.editor.saveImageWithPath( file.path, title: '${DateTime.now().millisecondsSinceEpoch}.jpg', ); From 37bc1f766a7cec70a0c7d258d2b1925c27da3427 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Thu, 3 Oct 2024 01:51:57 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=A5=85=20Improve=20exception=20thrown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fluttercandies/photo_manager/core/utils/IDBUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt index a68a76a7..aefd1225 100644 --- a/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt +++ b/android/src/main/kotlin/com/fluttercandies/photo_manager/core/utils/IDBUtils.kt @@ -173,7 +173,7 @@ interface IDBUtils { val id = getLong(_ID) val path = getString(DATA) if (checkIfExists && path.isNotBlank() && !File(path).exists()) { - throw RuntimeException("Asset ($id) does not exists at its path ($path).") + throwMsg("Asset ($id) does not exists at its path ($path).") } val date = if (isAboveAndroidQ) {