From 782129861ba4b9a26d62842c4988fc3998b292ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 04:09:31 +0000 Subject: [PATCH 1/2] Initial plan From 9b581be2fb0658a6df67c123047d1bb2d90a4209 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 04:20:34 +0000 Subject: [PATCH 2/2] Add getParentPathList() method for iOS/macOS parent folder navigation - Added AssetPathEntity.getParentPathList() public API method - Implemented getParentPathWithId in PMManager (Objective-C) - Added method handler in PMPlugin - Added plugin method getParentPathEntities - Updated CHANGELOG.md with new feature Co-authored-by: AlexV525 <15884415+AlexV525@users.noreply.github.com> --- CHANGELOG.md | 2 + .../Sources/photo_manager/PMPlugin.m | 11 ++++++ .../Sources/photo_manager/core/PMManager.h | 2 + .../Sources/photo_manager/core/PMManager.m | 39 +++++++++++++++++++ lib/src/internal/constants.dart | 1 + lib/src/internal/plugin.dart | 23 +++++++++++ lib/src/types/entity.dart | 15 +++++++ 7 files changed, 93 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22f15239..9d3f8d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ To know more about breaking changes, see the [Migration Guide][]. ### Features +- Add `AssetPathEntity.getParentPathList()` method for iOS/macOS to retrieve parent folders for user-created albums. + This enables navigation up the folder hierarchy, allowing users to browse nested album structures. - Add `cancelToken` parameter to `AssetEntity.loadFile`. - Add `cancelAllRequest` method to `PhotoManager`. - The `AssetEntity.getFile` and `AssetEntity.getOriginBytes` methods are public. diff --git a/darwin/photo_manager/Sources/photo_manager/PMPlugin.m b/darwin/photo_manager/Sources/photo_manager/PMPlugin.m index 1993bd2a..267cbe25 100644 --- a/darwin/photo_manager/Sources/photo_manager/PMPlugin.m +++ b/darwin/photo_manager/Sources/photo_manager/PMPlugin.m @@ -632,6 +632,17 @@ - (void)handleMethodResultHandler:(PMResultHandler *)handler manager:(PMManager NSArray *array = [manager getSubPathWithId:galleryId type:type albumType:albumType option:option]; NSDictionary *pathData = [PMConvertUtils convertPathToMap:array]; + [handler reply:@{@"list": pathData}]; + } else if ([@"getParentPath" isEqualToString:call.method]) { + NSString *galleryId = call.arguments[@"id"]; + int type = [call.arguments[@"type"] intValue]; + int albumType = [call.arguments[@"albumType"] intValue]; + NSDictionary *optionMap = call.arguments[@"option"]; + NSObject *option = [PMConvertUtils convertMapToOptionContainer:optionMap]; + + NSArray *array = [manager getParentPathWithId:galleryId type:type albumType:albumType option:option]; + NSDictionary *pathData = [PMConvertUtils convertPathToMap:array]; + [handler reply:@{@"list": pathData}]; } else if ([@"copyAsset" isEqualToString:call.method]) { NSString *assetId = call.arguments[@"assetId"]; diff --git a/darwin/photo_manager/Sources/photo_manager/core/PMManager.h b/darwin/photo_manager/Sources/photo_manager/core/PMManager.h index 85ece3d8..4afff011 100644 --- a/darwin/photo_manager/Sources/photo_manager/core/PMManager.h +++ b/darwin/photo_manager/Sources/photo_manager/core/PMManager.h @@ -114,6 +114,8 @@ typedef void (^AssetBlockResult)(PMAssetEntity *, NSObject *); - (NSArray *)getSubPathWithId:(NSString *)id type:(int)type albumType:(int)albumType option:(NSObject *)option; +- (NSArray *)getParentPathWithId:(NSString *)id type:(int)type albumType:(int)albumType option:(NSObject *)option; + - (void)copyAssetWithId:(NSString *)id toGallery:(NSString *)gallery block:(AssetBlockResult)block; - (void)createFolderWithName:(NSString *)name parentId:(NSString *)id block:(void (^)(NSString *newId, NSObject *error))block; diff --git a/darwin/photo_manager/Sources/photo_manager/core/PMManager.m b/darwin/photo_manager/Sources/photo_manager/core/PMManager.m index c8a4e0d4..73cde92e 100644 --- a/darwin/photo_manager/Sources/photo_manager/core/PMManager.m +++ b/darwin/photo_manager/Sources/photo_manager/core/PMManager.m @@ -1593,6 +1593,45 @@ - (void)getMediaUrl:(NSString *)assetId return [self convertPHCollectionToPMAssetPathArray:phCollectionArray option:options]; } +- (NSArray *)getParentPathWithId:(NSString *)id type:(int)type albumType:(int)albumType option:(NSObject *)option { + PHFetchOptions *options = [self getAssetOptions:type filterOption:option]; + + // Recent/All Photos collection has no parent folders + if ([PMFolderUtils isRecentCollection:id]) { + return @[]; + } + + PHCollection *collection = nil; + + // Try to fetch as an album (PHAssetCollection) first + PHFetchResult *assetCollectionResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[id] options:nil]; + if (assetCollectionResult && assetCollectionResult.count > 0) { + collection = assetCollectionResult.firstObject; + } + + // If not found as an album, try to fetch as a folder (PHCollectionList) + if (!collection) { + PHFetchResult *collectionListResult = [PHCollectionList fetchCollectionListsWithLocalIdentifiers:@[id] options:nil]; + if (collectionListResult && collectionListResult.count > 0) { + collection = collectionListResult.firstObject; + } + } + + if (!collection) { + return @[]; + } + + // Fetch parent collection lists containing this collection + PHFetchResult *parentCollectionLists = [PHCollectionList fetchCollectionListsContainingCollection:collection options:nil]; + + NSMutableArray *parentArray = [NSMutableArray new]; + for (PHCollectionList *parentList in parentCollectionLists) { + [parentArray addObject:parentList]; + } + + return [self convertPHCollectionToPMAssetPathArray:parentArray option:options]; +} + - (NSArray *)convertPHCollectionToPMAssetPathArray:(NSArray *)phArray option:(PHFetchOptions *)option { NSMutableArray *result = [NSMutableArray new]; diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index b71eed8c..316fbb31 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -45,6 +45,7 @@ class PMConstants { static const String mGetMimeTypeAsync = 'getMimeTypeAsync'; static const String mGetMediaUrl = 'getMediaUrl'; static const String mGetSubPath = 'getSubPath'; + static const String mGetParentPath = 'getParentPath'; static const String mCopyAsset = 'copyAsset'; static const String mDeleteAlbum = 'deleteAlbum'; static const String mFavoriteAsset = 'favoriteAsset'; diff --git a/lib/src/internal/plugin.dart b/lib/src/internal/plugin.dart index 141181d3..fc51f10b 100644 --- a/lib/src/internal/plugin.dart +++ b/lib/src/internal/plugin.dart @@ -575,6 +575,29 @@ class PhotoManagerPlugin with BasePlugin, IosPlugin, AndroidPlugin, OhosPlugin { ); } + Future> getParentPathEntities( + AssetPathEntity pathEntity, + ) async { + if (PlatformUtils.isOhos) { + return []; + } + final Map result = await _channel.invokeMethod( + PMConstants.mGetParentPath, + { + 'id': pathEntity.id, + 'type': pathEntity.type.value, + 'albumType': pathEntity.albumType, + 'option': pathEntity.filterOption?.toMap(), + }, + ); + final items = result['list'] as Map; + return ConvertUtils.convertToPathList( + items.cast(), + type: pathEntity.type, + filterOption: pathEntity.filterOption, + ); + } + Future copyAssetToGallery( AssetEntity asset, AssetPathEntity pathEntity, diff --git a/lib/src/types/entity.dart b/lib/src/types/entity.dart index 9d2dcb9c..ceefa6a0 100644 --- a/lib/src/types/entity.dart +++ b/lib/src/types/entity.dart @@ -246,6 +246,21 @@ class AssetPathEntity { return []; } + /// Request parent folders for the album. + /// + /// This method returns a list of parent folders (PHCollectionList) that + /// contain the current album or folder. It allows navigation up the + /// folder hierarchy for user-created albums and folders. + /// + /// An empty list will always be returned on Android. + /// An empty list will be returned for system albums like "Recent" or "All Photos". + Future> getParentPathList() async { + if (Platform.isIOS || Platform.isMacOS) { + return plugin.getParentPathEntities(this); + } + return []; + } + /// Obtain a new [AssetPathEntity] from the current one /// with refreshed properties. Future fetchPathProperties({