From bebceb822dfb68b17d6ae3356422a6ceee098bcb Mon Sep 17 00:00:00 2001 From: yujune Date: Fri, 27 Sep 2024 10:45:35 +0800 Subject: [PATCH 01/19] =?UTF-8?q?=E2=9C=A8=20Support=20multiple=20special?= =?UTF-8?q?=20items.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-ZH.md | 3 +- README.md | 3 +- example/lib/constants/picker_method.dart | 233 +++++++++++------- .../pickers/directory_file_asset_picker.dart | 17 +- .../customs/pickers/insta_asset_picker.dart | 1 - example/lib/l10n/app_en.arb | 2 + example/lib/l10n/app_zh.arb | 2 + example/lib/l10n/gen/app_localizations.dart | 12 + .../lib/l10n/gen/app_localizations_en.dart | 7 + .../lib/l10n/gen/app_localizations_zh.dart | 7 + example/lib/pages/multi_assets_page.dart | 1 + example/lib/pages/single_assets_page.dart | 1 + lib/src/constants/config.dart | 23 +- lib/src/constants/enums.dart | 4 - lib/src/constants/typedefs.dart | 8 + .../asset_picker_builder_delegate.dart | 134 +++++----- lib/src/delegates/asset_picker_delegate.dart | 3 +- lib/src/models/special_item.dart | 20 ++ lib/wechat_assets_picker.dart | 2 +- test/test_utils.dart | 3 +- 20 files changed, 302 insertions(+), 184 deletions(-) create mode 100644 lib/src/models/special_item.dart diff --git a/README-ZH.md b/README-ZH.md index fa053f0c..072c6177 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -295,8 +295,7 @@ final List? result = await AssetPicker.pickAssets( | themeColor | `Color?` | 选择器的主题色 | `Color(0xff00bc56)` | | pickerTheme | `ThemeData?` | 选择器的主题提供,包括查看器 | `null` | | textDelegate | `AssetPickerTextDelegate?` | 选择器的文本代理构建,用于自定义文本 | `AssetPickerTextDelegate()` | -| specialItemPosition | `SpecialItemPosition` | 允许用户在选择器中添加一个自定义item,并指定位置。 | `SpecialPosition.none` | -| specialItemBuilder | `SpecialItemBuilder?` | 自定义item的构造方法 | `null` | +| specialItems | `List` | 自定义item列表 | `const []` | | loadingIndicatorBuilder | `IndicatorBuilder?` | 加载器的实现 | `null` | | selectPredicate | `AssetSelectPredicate` | 判断资源可否被选择 | `null` | | shouldRevertGrid | `bool?` | 判断资源网格是否需要倒序排列 | `null` | diff --git a/README.md b/README.md index 10a4bb1e..242e8757 100644 --- a/README.md +++ b/README.md @@ -304,8 +304,7 @@ Fields in `AssetPickerConfig`: | themeColor | `Color?` | Main theme color for the picker. | `Color(0xff00bc56)` | | pickerTheme | `ThemeData?` | Theme data provider for the picker and the viewer. | `null` | | textDelegate | `AssetPickerTextDelegate?` | Text delegate for the picker, for customize the texts. | `AssetPickerTextDelegate()` | -| specialItemPosition | `SpecialItemPosition` | Allow users set a special item in the picker with several positions. | `SpecialItemPosition.none` | -| specialItemBuilder | `SpecialItemBuilder?` | The widget builder for the special item. | `null` | +| specialItems | `List` | List of special items. | `const []` | | loadingIndicatorBuilder | `IndicatorBuilder?` | Indicates the loading status for the builder. | `null` | | selectPredicate | `AssetSelectPredicate` | Predicate whether an asset can be selected or unselected. | `null` | | shouldRevertGrid | `bool?` | Whether the assets grid should revert. | `null` | diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index 00857410..a9e77197 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -135,39 +135,45 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, - specialItemPosition: SpecialItemPosition.prepend, - specialItemBuilder: ( - BuildContext context, - AssetPathEntity? path, - int length, - ) { - if (path?.isAll != true) { - return null; - } - return Semantics( - label: textDelegate.sActionUseCameraHint, - button: true, - onTapHint: textDelegate.sActionUseCameraHint, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () async { - Feedback.forTap(context); - final AssetEntity? result = await _pickFromCamera(context); - if (result != null) { - handleResult(context, result); - } - }, - child: Container( - padding: const EdgeInsets.all(28.0), - color: Theme.of(context).dividerColor, - child: const FittedBox( - fit: BoxFit.fill, - child: Icon(Icons.camera_enhance), + specialItems: [ + SpecialItem( + position: SpecialItemPosition.prepend, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + bool isPermissionLimited, + ) { + if (path?.isAll != true) { + return null; + } + return Semantics( + label: textDelegate.sActionUseCameraHint, + button: true, + onTapHint: textDelegate.sActionUseCameraHint, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () async { + Feedback.forTap(context); + final AssetEntity? result = + await _pickFromCamera(context); + if (result != null) { + handleResult(context, result); + } + }, + child: Container( + padding: const EdgeInsets.all(28.0), + color: Theme.of(context).dividerColor, + child: const FittedBox( + fit: BoxFit.fill, + child: Icon(Icons.camera_enhance), + ), + ), ), - ), - ), - ); - }, + ); + }, + ), + ], ), ); }, @@ -186,50 +192,56 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, - specialItemPosition: SpecialItemPosition.prepend, - specialItemBuilder: ( - BuildContext context, - AssetPathEntity? path, - int length, - ) { - if (path?.isAll != true) { - return null; - } - return Semantics( - label: textDelegate.sActionUseCameraHint, - button: true, - onTapHint: textDelegate.sActionUseCameraHint, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () async { - final AssetEntity? result = await _pickFromCamera(context); - if (result == null) { - return; - } - final picker = context.findAncestorWidgetOfExactType< - AssetPicker>()!; - final builder = - picker.builder as DefaultAssetPickerBuilderDelegate; - final p = builder.provider; - await p.switchPath( - PathWrapper( - path: - await p.currentPath!.path.obtainForNewProperties(), + specialItems: [ + SpecialItem( + position: SpecialItemPosition.prepend, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + bool isPermissionLimited, + ) { + if (path?.isAll != true) { + return null; + } + return Semantics( + label: textDelegate.sActionUseCameraHint, + button: true, + onTapHint: textDelegate.sActionUseCameraHint, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () async { + final AssetEntity? result = + await _pickFromCamera(context); + if (result == null) { + return; + } + final picker = context.findAncestorWidgetOfExactType< + AssetPicker>()!; + final builder = + picker.builder as DefaultAssetPickerBuilderDelegate; + final p = builder.provider; + await p.switchPath( + PathWrapper( + path: await p.currentPath!.path + .obtainForNewProperties(), + ), + ); + p.selectAsset(result); + }, + child: Container( + padding: const EdgeInsets.all(28.0), + color: Theme.of(context).dividerColor, + child: const FittedBox( + fit: BoxFit.fill, + child: Icon(Icons.camera_enhance), + ), ), - ); - p.selectAsset(result); - }, - child: Container( - padding: const EdgeInsets.all(28.0), - color: Theme.of(context).dividerColor, - child: const FittedBox( - fit: BoxFit.fill, - child: Icon(Icons.camera_enhance), ), - ), - ), - ); - }, + ); + }, + ), + ], ), ); }, @@ -295,16 +307,69 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, - specialItemPosition: SpecialItemPosition.prepend, - specialItemBuilder: ( - BuildContext context, - AssetPathEntity? path, - int length, - ) { - return const Center( - child: Text('Custom Widget', textAlign: TextAlign.center), - ); - }, + specialItems: [ + SpecialItem( + position: SpecialItemPosition.prepend, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + bool isPermissionLimited, + ) { + return const Center( + child: Text('Custom Widget', textAlign: TextAlign.center), + ); + }, + ), + ], + ), + ); + }, + ); + } + + factory PickMethod.multiSpecialItems( + BuildContext context, + int maxAssetsCount, + ) { + return PickMethod( + icon: '💡', + name: context.l10n.pickMethodMultiSpecialItemsName, + description: context.l10n.pickMethodMultiSpecialItemsDescription, + method: (BuildContext context, List assets) { + return AssetPicker.pickAssets( + context, + pickerConfig: AssetPickerConfig( + maxAssets: maxAssetsCount, + selectedAssets: assets, + specialItems: [ + SpecialItem( + position: SpecialItemPosition.prepend, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + bool isPermissionLimited, + ) { + return const Center( + child: Text('Prepand Widget', textAlign: TextAlign.center), + ); + }, + ), + SpecialItem( + position: SpecialItemPosition.append, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + bool isPermissionLimited, + ) { + return const Center( + child: Text('Append Widget', textAlign: TextAlign.center), + ); + }, + ), + ], ), ); }, diff --git a/example/lib/customs/pickers/directory_file_asset_picker.dart b/example/lib/customs/pickers/directory_file_asset_picker.dart index 535cb316..d04826bf 100644 --- a/example/lib/customs/pickers/directory_file_asset_picker.dart +++ b/example/lib/customs/pickers/directory_file_asset_picker.dart @@ -584,7 +584,7 @@ class FileAssetPickerBuilder Widget assetsGridBuilder(BuildContext context) { appBarPreferredSize ??= appBar(context).preferredSize; int totalCount = provider.currentAssets.length; - if (specialItemPosition != SpecialItemPosition.none) { + if (specialItems.isNotEmpty) { totalCount += 1; } final int placeholderCount; @@ -701,10 +701,10 @@ class FileAssetPickerBuilder int index, List currentAssets, ) { - final int currentIndex = switch (specialItemPosition) { - SpecialItemPosition.none || SpecialItemPosition.append => index, - SpecialItemPosition.prepend => index - 1, - }; + int currentIndex = index; + + currentIndex = index - prependSpecialItems.length; + final File asset = currentAssets.elementAt(currentIndex); final Widget builder = imageAndVideoItemBuilder( context, @@ -737,12 +737,7 @@ class FileAssetPickerBuilder required List assets, int placeholderCount = 0, }) { - final int length = switch (specialItemPosition) { - SpecialItemPosition.none => assets.length, - SpecialItemPosition.prepend || - SpecialItemPosition.append => - assets.length + 1, - }; + final int length = assets.length + specialItems.length; return length + placeholderCount; } diff --git a/example/lib/customs/pickers/insta_asset_picker.dart b/example/lib/customs/pickers/insta_asset_picker.dart index 879fd87d..c0ed62f3 100644 --- a/example/lib/customs/pickers/insta_asset_picker.dart +++ b/example/lib/customs/pickers/insta_asset_picker.dart @@ -297,7 +297,6 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate { super.keepScrollOffset, }) : super( shouldRevertGrid: false, - specialItemPosition: SpecialItemPosition.none, ); /// Save last position of the grid view scroll controller diff --git a/example/lib/l10n/app_en.arb b/example/lib/l10n/app_en.arb index d40489ed..029e46a9 100644 --- a/example/lib/l10n/app_en.arb +++ b/example/lib/l10n/app_en.arb @@ -28,6 +28,8 @@ "pickMethodCustomFilterOptionsDescription": "Add filter options for the picker.", "pickMethodPrependItemName": "Prepend special item", "pickMethodPrependItemDescription": "A special item will prepend to the assets grid.", + "pickMethodMultiSpecialItemsName": "Multiple special items", + "pickMethodMultiSpecialItemsDescription": "Multiple special items will prepend or append to the assets grid", "pickMethodNoPreviewName": "No preview", "pickMethodNoPreviewDescription": "You cannot preview assets during the picking, the behavior is like the WhatsApp/MegaTok pattern.", "pickMethodKeepScrollOffsetName": "Keep scroll offset", diff --git a/example/lib/l10n/app_zh.arb b/example/lib/l10n/app_zh.arb index 79df1bd6..151514b2 100644 --- a/example/lib/l10n/app_zh.arb +++ b/example/lib/l10n/app_zh.arb @@ -28,6 +28,8 @@ "pickMethodCustomFilterOptionsDescription": "为选择器添加自定义过滤条件。", "pickMethodPrependItemName": "往网格前插入 widget", "pickMethodPrependItemDescription": "网格的靠前位置会添加一个自定义的 widget。", + "pickMethodMultiSpecialItemsName": "多个特殊 widget", + "pickMethodMultiSpecialItemsDescription": "网格的靠前或靠后位置会可以多个自定义的 widget。", "pickMethodNoPreviewName": "禁止预览", "pickMethodNoPreviewDescription": "无法预览选择的资源,与 WhatsApp/MegaTok 的行为类似。", "pickMethodKeepScrollOffsetName": "保持滚动位置", diff --git a/example/lib/l10n/gen/app_localizations.dart b/example/lib/l10n/gen/app_localizations.dart index 9cf300a3..fbdf6b06 100644 --- a/example/lib/l10n/gen/app_localizations.dart +++ b/example/lib/l10n/gen/app_localizations.dart @@ -266,6 +266,18 @@ abstract class AppLocalizations { /// **'A special item will prepend to the assets grid.'** String get pickMethodPrependItemDescription; + /// No description provided for @pickMethodMultiSpecialItemsName. + /// + /// In en, this message translates to: + /// **'Multiple special items'** + String get pickMethodMultiSpecialItemsName; + + /// No description provided for @pickMethodMultiSpecialItemsDescription. + /// + /// In en, this message translates to: + /// **'Multiple special items will prepend or append to the assets grid'** + String get pickMethodMultiSpecialItemsDescription; + /// No description provided for @pickMethodNoPreviewName. /// /// In en, this message translates to: diff --git a/example/lib/l10n/gen/app_localizations_en.dart b/example/lib/l10n/gen/app_localizations_en.dart index 6419ff94..9d0bfce7 100644 --- a/example/lib/l10n/gen/app_localizations_en.dart +++ b/example/lib/l10n/gen/app_localizations_en.dart @@ -101,6 +101,13 @@ class AppLocalizationsEn extends AppLocalizations { String get pickMethodPrependItemDescription => 'A special item will prepend to the assets grid.'; + @override + String get pickMethodMultiSpecialItemsName => 'Multiple special items'; + + @override + String get pickMethodMultiSpecialItemsDescription => + 'Multiple special items will prepend or append to the assets grid'; + @override String get pickMethodNoPreviewName => 'No preview'; diff --git a/example/lib/l10n/gen/app_localizations_zh.dart b/example/lib/l10n/gen/app_localizations_zh.dart index 3306b449..e5147914 100644 --- a/example/lib/l10n/gen/app_localizations_zh.dart +++ b/example/lib/l10n/gen/app_localizations_zh.dart @@ -95,6 +95,13 @@ class AppLocalizationsZh extends AppLocalizations { @override String get pickMethodPrependItemDescription => '网格的靠前位置会添加一个自定义的 widget。'; + @override + String get pickMethodMultiSpecialItemsName => '多个特殊 widget'; + + @override + String get pickMethodMultiSpecialItemsDescription => + '网格的靠前或靠后位置会可以多个自定义的 widget。'; + @override String get pickMethodNoPreviewName => '禁止预览'; diff --git a/example/lib/pages/multi_assets_page.dart b/example/lib/pages/multi_assets_page.dart index 016486da..4d0b30cc 100644 --- a/example/lib/pages/multi_assets_page.dart +++ b/example/lib/pages/multi_assets_page.dart @@ -46,6 +46,7 @@ class _MultiAssetsPageState extends State PickMethod.changeLanguages(context, maxAssetsCount), PickMethod.threeItemsGrid(context, maxAssetsCount), PickMethod.prependItem(context, maxAssetsCount), + PickMethod.multiSpecialItems(context, maxAssetsCount), PickMethod( icon: '🎭', name: context.l10n.pickMethodWeChatMomentName, diff --git a/example/lib/pages/single_assets_page.dart b/example/lib/pages/single_assets_page.dart index 612277dd..ff5a39fb 100644 --- a/example/lib/pages/single_assets_page.dart +++ b/example/lib/pages/single_assets_page.dart @@ -46,6 +46,7 @@ class _SingleAssetPageState extends State PickMethod.changeLanguages(context, maxAssetsCount), PickMethod.threeItemsGrid(context, maxAssetsCount), PickMethod.prependItem(context, maxAssetsCount), + PickMethod.multiSpecialItems(context, maxAssetsCount), PickMethod.customFilterOptions(context, maxAssetsCount), PickMethod.preventGIFPicked(context, maxAssetsCount), PickMethod.noPreview(context, maxAssetsCount), diff --git a/lib/src/constants/config.dart b/lib/src/constants/config.dart index 939f5fa8..b22bfd2d 100644 --- a/lib/src/constants/config.dart +++ b/lib/src/constants/config.dart @@ -8,6 +8,7 @@ import 'package:photo_manager/photo_manager.dart'; import '../constants/typedefs.dart'; import '../delegates/asset_picker_text_delegate.dart'; import '../delegates/sort_path_delegate.dart'; +import '../models/special_item.dart'; import 'constants.dart'; import 'enums.dart'; @@ -29,8 +30,6 @@ class AssetPickerConfig { this.themeColor, this.pickerTheme, this.textDelegate, - this.specialItemPosition = SpecialItemPosition.none, - this.specialItemBuilder, this.loadingIndicatorBuilder, this.selectPredicate, this.shouldRevertGrid, @@ -39,6 +38,7 @@ class AssetPickerConfig { this.assetsChangeCallback, this.assetsChangeRefreshPredicate, this.shouldAutoplayPreview = false, + this.specialItems = const [], }) : assert( pickerTheme == null || themeColor == null, 'pickerTheme and themeColor cannot be set at the same time.', @@ -55,13 +55,6 @@ class AssetPickerConfig { requestType == RequestType.common, 'SpecialPickerType.wechatMoment and requestType ' 'cannot be set at the same time.', - ), - assert( - (specialItemBuilder == null && - identical(specialItemPosition, SpecialItemPosition.none)) || - (specialItemBuilder != null && - !identical(specialItemPosition, SpecialItemPosition.none)), - 'Custom item did not set properly.', ); /// Selected assets. @@ -167,14 +160,6 @@ class AssetPickerConfig { final AssetPickerTextDelegate? textDelegate; - /// Allow users set a special item in the picker with several positions. - /// 允许用户在选择器中添加一个自定义item,并指定位置 - final SpecialItemPosition specialItemPosition; - - /// The widget builder for the the special item. - /// 自定义item的构造方法 - final SpecialItemBuilder? specialItemBuilder; - /// Indicates the loading status for the builder. /// 指示目前加载的状态 final LoadingIndicatorBuilder? loadingIndicatorBuilder; @@ -205,4 +190,8 @@ class AssetPickerConfig { /// Whether the preview should auto play. /// 预览是否自动播放 final bool shouldAutoplayPreview; + + /// List of special items. + /// 自定义item列表 + final List> specialItems; } diff --git a/lib/src/constants/enums.dart b/lib/src/constants/enums.dart index 686c563d..ba3bdff9 100644 --- a/lib/src/constants/enums.dart +++ b/lib/src/constants/enums.dart @@ -30,10 +30,6 @@ enum SpecialPickerType { /// Provide an item slot for custom widget insertion. /// 提供一个自定义位置供特殊item放入资源列表中。 enum SpecialItemPosition { - /// Not insert to the list. - /// 不放入列表 - none, - /// Add as leading of the list. /// 在列表前放入 prepend, diff --git a/lib/src/constants/typedefs.dart b/lib/src/constants/typedefs.dart index e8e5c689..8fc40470 100644 --- a/lib/src/constants/typedefs.dart +++ b/lib/src/constants/typedefs.dart @@ -9,6 +9,8 @@ import 'package:flutter/widgets.dart'; import 'package:photo_manager/photo_manager.dart' show PermissionState; import 'package:provider/provider.dart'; +import './enums.dart'; + /// Mirroring [ChangeNotifierProvider]. typedef CNP = ChangeNotifierProvider; @@ -29,6 +31,7 @@ typedef SpecialItemBuilder = Widget? Function( BuildContext context, Path? path, int length, + bool isPermissionLimited, ); /// {@template wechat_assets_picker.AssetSelectPredicate} @@ -75,3 +78,8 @@ typedef AssetsChangeRefreshPredicate = bool Function( MethodCall call, Path? path, ); + +typedef SpecialItemModel = ({ + SpecialItemPosition position, + Widget item, +}); diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index aa85ec03..982a8e39 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -21,6 +21,7 @@ import '../constants/typedefs.dart'; import '../delegates/asset_picker_text_delegate.dart'; import '../internals/singleton.dart'; import '../models/path_wrapper.dart'; +import '../models/special_item.dart'; import '../provider/asset_picker_provider.dart'; import '../widget/asset_picker.dart'; import '../widget/asset_picker_app_bar.dart'; @@ -38,8 +39,7 @@ abstract class AssetPickerBuilderDelegate { required this.initialPermission, this.gridCount = 4, this.pickerTheme, - this.specialItemPosition = SpecialItemPosition.none, - this.specialItemBuilder, + this.specialItems = const [], this.loadingIndicatorBuilder, this.selectPredicate, this.shouldRevertGrid, @@ -57,7 +57,12 @@ abstract class AssetPickerBuilderDelegate { ), themeColor = pickerTheme?.colorScheme.secondary ?? themeColor ?? - defaultThemeColorWeChat { + defaultThemeColorWeChat, + prependSpecialItems = specialItems + .where( + (item) => item.position == SpecialItemPosition.prepend, + ) + .toList() { Singleton.textDelegate = textDelegate ?? assetPickerTextDelegateFromLocale(locale); } @@ -84,13 +89,9 @@ abstract class AssetPickerBuilderDelegate { /// 但某些情况下开发者需要亮色或自定义主题。 final ThemeData? pickerTheme; - /// Allow users set a special item in the picker with several positions. - /// 允许用户在选择器中添加一个自定义 item,并指定位置 - final SpecialItemPosition specialItemPosition; - - /// The widget builder for the the special item. - /// 自定义 item 的构造方法 - final SpecialItemBuilder? specialItemBuilder; + /// List of special items. + /// 自定义item列表 + final List> specialItems; /// Indicates the loading status for the builder. /// 指示目前加载的状态 @@ -130,6 +131,10 @@ abstract class AssetPickerBuilderDelegate { final AssetsChangeRefreshPredicate? assetsChangeRefreshPredicate; + /// List of prepend special items. + /// 前置自定义item列表 + final List> prependSpecialItems; + /// [ThemeData] for the picker. /// 选择器使用的主题 ThemeData get theme => pickerTheme ?? AssetPicker.themeData(themeColor); @@ -170,9 +175,7 @@ abstract class AssetPickerBuilderDelegate { /// Whether the delegate should build the special item. /// 是否需要构建自定义 item - bool get shouldBuildSpecialItem => - specialItemPosition != SpecialItemPosition.none && - specialItemBuilder != null; + bool get shouldBuildSpecialItem => specialItems.isNotEmpty; /// Space between assets item widget. /// 资源部件之间的间隔 @@ -743,8 +746,6 @@ class DefaultAssetPickerBuilderDelegate required super.initialPermission, super.gridCount, super.pickerTheme, - super.specialItemPosition, - super.specialItemBuilder, super.loadingIndicatorBuilder, super.selectPredicate, super.shouldRevertGrid, @@ -760,6 +761,7 @@ class DefaultAssetPickerBuilderDelegate this.specialPickerType, this.keepScrollOffset = false, this.shouldAutoplayPreview = false, + super.specialItems = const [], }) { // Add the listener if [keepScrollOffset] is true. if (keepScrollOffset) { @@ -1231,21 +1233,25 @@ class DefaultAssetPickerBuilderDelegate builder: (context, wrapper, _) { // First, we need the count of the assets. int totalCount = wrapper?.assetCount ?? 0; - final Widget? specialItem; - // If user chose a special item's position, add 1 count. - if (specialItemPosition != SpecialItemPosition.none) { - specialItem = specialItemBuilder?.call( - context, - wrapper?.path, - totalCount, - ); - if (specialItem != null) { - totalCount += 1; - } - } else { - specialItem = null; - } - if (totalCount == 0 && specialItem == null) { + + final List specialItemModels = specialItems + .map((item) { + return ( + position: item.position, + item: item.builder?.call( + context, + wrapper?.path, + totalCount, + isPermissionLimited, + ) + ); + }) + .whereType() + .toList(); + + totalCount += specialItemModels.length; + + if (totalCount == 0 && specialItemModels.isEmpty) { return loadingIndicator(context); } // Then we use the [totalCount] to calculate placeholders we need. @@ -1285,7 +1291,7 @@ class DefaultAssetPickerBuilderDelegate context, index, assets, - specialItem: specialItem, + specialItemModels: specialItemModels, ), ), ); @@ -1294,7 +1300,7 @@ class DefaultAssetPickerBuilderDelegate context: context, assets: assets, placeholderCount: placeholderCount, - specialItem: specialItem, + specialItemModels: specialItemModels, ), findChildIndexCallback: (Key? key) { if (key is ValueKey) { @@ -1404,7 +1410,7 @@ class DefaultAssetPickerBuilderDelegate BuildContext context, int index, List currentAssets, { - Widget? specialItem, + List specialItemModels = const [], }) { final DefaultAssetPickerProvider p = context.read(); @@ -1412,21 +1418,30 @@ class DefaultAssetPickerBuilderDelegate final PathWrapper? currentWrapper = p.currentPath; final AssetPathEntity? currentPathEntity = currentWrapper?.path; - if (specialItem != null) { - if ((index == 0 && specialItemPosition == SpecialItemPosition.prepend) || - (index == length && - specialItemPosition == SpecialItemPosition.append)) { - return specialItem; + final prepandSpecialItemModels = specialItemModels.where( + (model) => model.position == SpecialItemPosition.prepend, + ); + final appendSpecialItemModels = specialItemModels.where( + (model) => model.position == SpecialItemPosition.append, + ); + + if (specialItemModels.isNotEmpty) { + if (prepandSpecialItemModels.isNotEmpty) { + if (index < prepandSpecialItemModels.length) { + return specialItemModels[index].item; + } + } + + if (appendSpecialItemModels.isNotEmpty) { + if (index >= length + prepandSpecialItemModels.length) { + return specialItemModels[index - length].item; + } } } - final int currentIndex; - if (specialItem != null && - specialItemPosition == SpecialItemPosition.prepend) { - currentIndex = index - 1; - } else { - currentIndex = index; - } + int currentIndex = index; + + currentIndex = index - prepandSpecialItemModels.length; if (currentPathEntity == null) { return const SizedBox.shrink(); @@ -1461,9 +1476,10 @@ class DefaultAssetPickerBuilderDelegate } int semanticIndex(int index) { - if (specialItemPosition != SpecialItemPosition.prepend) { - return index + 1; + if (prependSpecialItems.isNotEmpty) { + return index - prependSpecialItems.length + 1; } + return index; } @@ -1556,9 +1572,9 @@ class DefaultAssetPickerBuilderDelegate int placeholderCount = 0, }) { int index = assets.indexWhere((AssetEntity e) => e.id == id); - if (specialItemPosition == SpecialItemPosition.prepend) { - index += 1; - } + + index += prependSpecialItems.length; + index += placeholderCount; return index; } @@ -1568,7 +1584,7 @@ class DefaultAssetPickerBuilderDelegate required BuildContext context, required List assets, int placeholderCount = 0, - Widget? specialItem, + List specialItemModels = const [], }) { final PathWrapper? currentWrapper = context .select?>( @@ -1578,19 +1594,21 @@ class DefaultAssetPickerBuilderDelegate final int length = assets.length + placeholderCount; // Return 1 if the [specialItem] build something. - if (currentPathEntity == null && specialItem != null) { - return placeholderCount + 1; + if (currentPathEntity == null && specialItemModels.isNotEmpty) { + return placeholderCount + specialItemModels.length; } // Return actual length if the current path is all. // 如果当前目录是全部内容,则返回实际的内容数量。 - if (currentPathEntity?.isAll != true && specialItem == null) { + if (currentPathEntity?.isAll != true && specialItemModels.isEmpty) { return length; } - return switch (specialItemPosition) { - SpecialItemPosition.none => length, - SpecialItemPosition.prepend || SpecialItemPosition.append => length + 1, - }; + + if (specialItemModels.isEmpty) { + return length; + } + + return length + specialItemModels.length; } @override diff --git a/lib/src/delegates/asset_picker_delegate.dart b/lib/src/delegates/asset_picker_delegate.dart index 3f788b3d..c6943fe4 100644 --- a/lib/src/delegates/asset_picker_delegate.dart +++ b/lib/src/delegates/asset_picker_delegate.dart @@ -105,8 +105,6 @@ class AssetPickerDelegate { gridThumbnailSize: pickerConfig.gridThumbnailSize, previewThumbnailSize: pickerConfig.previewThumbnailSize, specialPickerType: pickerConfig.specialPickerType, - specialItemPosition: pickerConfig.specialItemPosition, - specialItemBuilder: pickerConfig.specialItemBuilder, loadingIndicatorBuilder: pickerConfig.loadingIndicatorBuilder, selectPredicate: pickerConfig.selectPredicate, shouldRevertGrid: pickerConfig.shouldRevertGrid, @@ -119,6 +117,7 @@ class AssetPickerDelegate { themeColor: pickerConfig.themeColor, locale: Localizations.maybeLocaleOf(context), shouldAutoplayPreview: pickerConfig.shouldAutoplayPreview, + specialItems: pickerConfig.specialItems, ), ); final List? result = await Navigator.maybeOf( diff --git a/lib/src/models/special_item.dart b/lib/src/models/special_item.dart new file mode 100644 index 00000000..10b9c169 --- /dev/null +++ b/lib/src/models/special_item.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +/// Allow users to set a special item in the picker grid with specified [position]. +/// 允许用户在选择器中添加一个自定义item,并指定其位置。 +@immutable +class SpecialItem { + const SpecialItem({ + required this.builder, + required this.position, + }); + + /// The widget builder for the the special item. + /// 自定义item构建。 + final SpecialItemBuilder? builder; + + /// Define how the item will be positioned. + /// 定义如何摆放item。 + final SpecialItemPosition position; +} diff --git a/lib/wechat_assets_picker.dart b/lib/wechat_assets_picker.dart index ca03acff..dd2afb69 100644 --- a/lib/wechat_assets_picker.dart +++ b/lib/wechat_assets_picker.dart @@ -12,7 +12,6 @@ export 'src/constants/config.dart'; export 'src/constants/constants.dart' hide packageName; export 'src/constants/enums.dart'; export 'src/constants/typedefs.dart'; - export 'src/delegates/asset_picker_builder_delegate.dart'; export 'src/delegates/asset_picker_delegate.dart'; export 'src/delegates/asset_picker_text_delegate.dart'; @@ -20,6 +19,7 @@ export 'src/delegates/asset_picker_viewer_builder_delegate.dart'; export 'src/delegates/sort_path_delegate.dart'; export 'src/models/path_wrapper.dart'; +export 'src/models/special_item.dart'; export 'src/provider/asset_picker_provider.dart'; export 'src/provider/asset_picker_viewer_provider.dart'; diff --git a/test/test_utils.dart b/test/test_utils.dart index c5d0a670..91eb9fdd 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -131,8 +131,7 @@ class TestAssetPickerDelegate extends AssetPickerDelegate { gridThumbnailSize: pickerConfig.gridThumbnailSize, previewThumbnailSize: pickerConfig.previewThumbnailSize, specialPickerType: pickerConfig.specialPickerType, - specialItemPosition: pickerConfig.specialItemPosition, - specialItemBuilder: pickerConfig.specialItemBuilder, + specialItems: pickerConfig.specialItems, loadingIndicatorBuilder: pickerConfig.loadingIndicatorBuilder, selectPredicate: pickerConfig.selectPredicate, shouldRevertGrid: pickerConfig.shouldRevertGrid, From bab2c0d7041e940e2ebd069e7d7d0ce25de96300 Mon Sep 17 00:00:00 2001 From: yujune Date: Thu, 10 Oct 2024 21:34:01 +0800 Subject: [PATCH 02/19] Add permission state in special item builder. --- example/lib/constants/picker_method.dart | 10 +++++----- lib/src/constants/typedefs.dart | 2 +- lib/src/delegates/asset_picker_builder_delegate.dart | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index a9e77197..e990a4dd 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -142,7 +142,7 @@ class PickMethod { BuildContext context, AssetPathEntity? path, int length, - bool isPermissionLimited, + PermissionState permissionState, ) { if (path?.isAll != true) { return null; @@ -199,7 +199,7 @@ class PickMethod { BuildContext context, AssetPathEntity? path, int length, - bool isPermissionLimited, + PermissionState permissionState, ) { if (path?.isAll != true) { return null; @@ -314,7 +314,7 @@ class PickMethod { BuildContext context, AssetPathEntity? path, int length, - bool isPermissionLimited, + PermissionState permissionState, ) { return const Center( child: Text('Custom Widget', textAlign: TextAlign.center), @@ -349,7 +349,7 @@ class PickMethod { BuildContext context, AssetPathEntity? path, int length, - bool isPermissionLimited, + PermissionState permissionState, ) { return const Center( child: Text('Prepand Widget', textAlign: TextAlign.center), @@ -362,7 +362,7 @@ class PickMethod { BuildContext context, AssetPathEntity? path, int length, - bool isPermissionLimited, + PermissionState permissionState, ) { return const Center( child: Text('Append Widget', textAlign: TextAlign.center), diff --git a/lib/src/constants/typedefs.dart b/lib/src/constants/typedefs.dart index 8fc40470..129514fb 100644 --- a/lib/src/constants/typedefs.dart +++ b/lib/src/constants/typedefs.dart @@ -31,7 +31,7 @@ typedef SpecialItemBuilder = Widget? Function( BuildContext context, Path? path, int length, - bool isPermissionLimited, + PermissionState permissionState, ); /// {@template wechat_assets_picker.AssetSelectPredicate} diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 982a8e39..6fc4d212 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1242,7 +1242,7 @@ class DefaultAssetPickerBuilderDelegate context, wrapper?.path, totalCount, - isPermissionLimited, + permissionNotifier.value, ) ); }) From eee1d580699e2e40684ad35c8b082eee6af49bb6 Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 16:19:43 +0800 Subject: [PATCH 03/19] Add specialItem count instead of hardcoded 1. --- example/lib/customs/pickers/directory_file_asset_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/customs/pickers/directory_file_asset_picker.dart b/example/lib/customs/pickers/directory_file_asset_picker.dart index d04826bf..a59a77a2 100644 --- a/example/lib/customs/pickers/directory_file_asset_picker.dart +++ b/example/lib/customs/pickers/directory_file_asset_picker.dart @@ -585,7 +585,7 @@ class FileAssetPickerBuilder appBarPreferredSize ??= appBar(context).preferredSize; int totalCount = provider.currentAssets.length; if (specialItems.isNotEmpty) { - totalCount += 1; + totalCount += specialItems.length; } final int placeholderCount; if (isAppleOS(context) && totalCount % gridCount != 0) { From 2575aa39bf342ad643998e103de3ad3d369250d5 Mon Sep 17 00:00:00 2001 From: Tee Yu June <56582497+yujune@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:20:34 +0800 Subject: [PATCH 04/19] Update example/lib/customs/pickers/directory_file_asset_picker.dart Co-authored-by: Alex Li --- example/lib/customs/pickers/directory_file_asset_picker.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/example/lib/customs/pickers/directory_file_asset_picker.dart b/example/lib/customs/pickers/directory_file_asset_picker.dart index a59a77a2..9312c333 100644 --- a/example/lib/customs/pickers/directory_file_asset_picker.dart +++ b/example/lib/customs/pickers/directory_file_asset_picker.dart @@ -701,10 +701,7 @@ class FileAssetPickerBuilder int index, List currentAssets, ) { - int currentIndex = index; - - currentIndex = index - prependSpecialItems.length; - + final currentIndex = index - prependSpecialItems.length; final File asset = currentAssets.elementAt(currentIndex); final Widget builder = imageAndVideoItemBuilder( context, From 84fee2a43c4c7bd51c47a42f39635c1a70f248d5 Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 16:22:10 +0800 Subject: [PATCH 05/19] Move out SpecialItemModel from typedefs. --- lib/src/constants/typedefs.dart | 7 ------- lib/src/delegates/asset_picker_builder_delegate.dart | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/src/constants/typedefs.dart b/lib/src/constants/typedefs.dart index 129514fb..601b86e6 100644 --- a/lib/src/constants/typedefs.dart +++ b/lib/src/constants/typedefs.dart @@ -9,8 +9,6 @@ import 'package:flutter/widgets.dart'; import 'package:photo_manager/photo_manager.dart' show PermissionState; import 'package:provider/provider.dart'; -import './enums.dart'; - /// Mirroring [ChangeNotifierProvider]. typedef CNP = ChangeNotifierProvider; @@ -78,8 +76,3 @@ typedef AssetsChangeRefreshPredicate = bool Function( MethodCall call, Path? path, ); - -typedef SpecialItemModel = ({ - SpecialItemPosition position, - Widget item, -}); diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 6fc4d212..b2f212c6 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -2476,3 +2476,8 @@ class DefaultAssetPickerBuilderDelegate ); } } + +typedef SpecialItemModel = ({ + SpecialItemPosition position, + Widget item, +}); From 1732cfe470409ed00cbe96484b39582329b0aebf Mon Sep 17 00:00:00 2001 From: Tee Yu June <56582497+yujune@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:23:29 +0800 Subject: [PATCH 06/19] Update lib/src/delegates/asset_picker_builder_delegate.dart Co-authored-by: Alex Li --- lib/src/delegates/asset_picker_builder_delegate.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index b2f212c6..733a7659 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1439,9 +1439,7 @@ class DefaultAssetPickerBuilderDelegate } } - int currentIndex = index; - - currentIndex = index - prepandSpecialItemModels.length; + final currentIndex = index - prepandSpecialItemModels.length; if (currentPathEntity == null) { return const SizedBox.shrink(); From 105abcf2b10978b40172d40ce1910313d4247d9e Mon Sep 17 00:00:00 2001 From: Tee Yu June <56582497+yujune@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:24:13 +0800 Subject: [PATCH 07/19] Update lib/src/delegates/asset_picker_builder_delegate.dart Co-authored-by: Alex Li --- .../delegates/asset_picker_builder_delegate.dart | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 733a7659..5b057719 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1418,12 +1418,16 @@ class DefaultAssetPickerBuilderDelegate final PathWrapper? currentWrapper = p.currentPath; final AssetPathEntity? currentPathEntity = currentWrapper?.path; - final prepandSpecialItemModels = specialItemModels.where( - (model) => model.position == SpecialItemPosition.prepend, - ); - final appendSpecialItemModels = specialItemModels.where( - (model) => model.position == SpecialItemPosition.append, - ); + final prependItems = []; + final appendItems = []; + for (final model in specialItemModels) { + switch (model.position) { + case SpecialItemPosition.prepend: + prependItems.add(model); + case SpecialItemPosition.append: + appendItems.add(model); + } + } if (specialItemModels.isNotEmpty) { if (prepandSpecialItemModels.isNotEmpty) { From 368afc6e11451e6269ec288ba032b54b1584cb65 Mon Sep 17 00:00:00 2001 From: Tee Yu June <56582497+yujune@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:24:31 +0800 Subject: [PATCH 08/19] Update lib/src/delegates/asset_picker_builder_delegate.dart Co-authored-by: Alex Li --- lib/src/delegates/asset_picker_builder_delegate.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 5b057719..8277fc64 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1606,10 +1606,6 @@ class DefaultAssetPickerBuilderDelegate return length; } - if (specialItemModels.isEmpty) { - return length; - } - return length + specialItemModels.length; } From 223e0daa18a2249ac5873aaaf6ed1c93fdd7256b Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 16:28:00 +0800 Subject: [PATCH 09/19] Remove redundant codes. --- .../asset_picker_builder_delegate.dart | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 8277fc64..a2a83f95 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1429,21 +1429,19 @@ class DefaultAssetPickerBuilderDelegate } } - if (specialItemModels.isNotEmpty) { - if (prepandSpecialItemModels.isNotEmpty) { - if (index < prepandSpecialItemModels.length) { - return specialItemModels[index].item; - } + if (prependItems.isNotEmpty) { + if (index < prependItems.length) { + return specialItemModels[index].item; } + } - if (appendSpecialItemModels.isNotEmpty) { - if (index >= length + prepandSpecialItemModels.length) { - return specialItemModels[index - length].item; - } + if (appendItems.isNotEmpty) { + if (index >= length + prependItems.length) { + return specialItemModels[index - length].item; } } - final currentIndex = index - prepandSpecialItemModels.length; + final currentIndex = index - prependItems.length; if (currentPathEntity == null) { return const SizedBox.shrink(); From 929fae5bb01d2663574a218521c54d859f3f24de Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 16:35:16 +0800 Subject: [PATCH 10/19] Remove incorrect -1 logic. --- lib/src/delegates/asset_picker_builder_delegate.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index a2a83f95..1f3b0793 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1477,7 +1477,7 @@ class DefaultAssetPickerBuilderDelegate int semanticIndex(int index) { if (prependSpecialItems.isNotEmpty) { - return index - prependSpecialItems.length + 1; + return index - prependSpecialItems.length; } return index; From 412ad3b441f8c82b45744ce3526ed88f5d8c89d6 Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 16:38:42 +0800 Subject: [PATCH 11/19] Remove redundant checking. --- lib/src/delegates/asset_picker_builder_delegate.dart | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 1f3b0793..5fa18644 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1476,11 +1476,7 @@ class DefaultAssetPickerBuilderDelegate } int semanticIndex(int index) { - if (prependSpecialItems.isNotEmpty) { - return index - prependSpecialItems.length; - } - - return index; + return index - prependSpecialItems.length; } @override From 357e94ccf1d3f8170f3d86e11747ff8d7b3ec31c Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 20:48:10 +0800 Subject: [PATCH 12/19] Add appendSpecialItems. --- lib/src/delegates/asset_picker_builder_delegate.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 5fa18644..bd980138 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -62,6 +62,11 @@ abstract class AssetPickerBuilderDelegate { .where( (item) => item.position == SpecialItemPosition.prepend, ) + .toList(), + appendSpecialItems = specialItems + .where( + (item) => item.position == SpecialItemPosition.append, + ) .toList() { Singleton.textDelegate = textDelegate ?? assetPickerTextDelegateFromLocale(locale); @@ -135,6 +140,10 @@ abstract class AssetPickerBuilderDelegate { /// 前置自定义item列表 final List> prependSpecialItems; + /// List of append special items. + /// 附加自定义item列表 + final List> appendSpecialItems; + /// [ThemeData] for the picker. /// 选择器使用的主题 ThemeData get theme => pickerTheme ?? AssetPicker.themeData(themeColor); From 10ea0352293cd8d211b0db91628d4ed1f04673ae Mon Sep 17 00:00:00 2001 From: Tee Yu June <56582497+yujune@users.noreply.github.com> Date: Wed, 16 Oct 2024 20:49:35 +0800 Subject: [PATCH 13/19] Update lib/src/delegates/asset_picker_builder_delegate.dart Co-authored-by: Alex Li --- lib/src/delegates/asset_picker_builder_delegate.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index bd980138..aa610e37 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1577,9 +1577,7 @@ class DefaultAssetPickerBuilderDelegate int placeholderCount = 0, }) { int index = assets.indexWhere((AssetEntity e) => e.id == id); - index += prependSpecialItems.length; - index += placeholderCount; return index; } From df3a176b06c3a175b334b032ec01f72ce9a4ed25 Mon Sep 17 00:00:00 2001 From: yujune Date: Wed, 16 Oct 2024 20:51:25 +0800 Subject: [PATCH 14/19] Move _SpecialItemModel to top. --- .../asset_picker_builder_delegate.dart | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index aa610e37..a69151c8 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -28,6 +28,11 @@ import '../widget/asset_picker_app_bar.dart'; import '../widget/asset_picker_viewer.dart'; import '../widget/builder/asset_entity_grid_item_builder.dart'; +typedef _SpecialItemModel = ({ + SpecialItemPosition position, + Widget item, +}); + /// The delegate to build the whole picker's components. /// /// By extending the delegate, you can customize every components on you own. @@ -1243,7 +1248,7 @@ class DefaultAssetPickerBuilderDelegate // First, we need the count of the assets. int totalCount = wrapper?.assetCount ?? 0; - final List specialItemModels = specialItems + final List<_SpecialItemModel> specialItemModels = specialItems .map((item) { return ( position: item.position, @@ -1255,7 +1260,7 @@ class DefaultAssetPickerBuilderDelegate ) ); }) - .whereType() + .whereType<_SpecialItemModel>() .toList(); totalCount += specialItemModels.length; @@ -1419,7 +1424,7 @@ class DefaultAssetPickerBuilderDelegate BuildContext context, int index, List currentAssets, { - List specialItemModels = const [], + List<_SpecialItemModel> specialItemModels = const [], }) { final DefaultAssetPickerProvider p = context.read(); @@ -1427,8 +1432,8 @@ class DefaultAssetPickerBuilderDelegate final PathWrapper? currentWrapper = p.currentPath; final AssetPathEntity? currentPathEntity = currentWrapper?.path; - final prependItems = []; - final appendItems = []; + final prependItems = <_SpecialItemModel>[]; + final appendItems = <_SpecialItemModel>[]; for (final model in specialItemModels) { switch (model.position) { case SpecialItemPosition.prepend: @@ -1587,7 +1592,7 @@ class DefaultAssetPickerBuilderDelegate required BuildContext context, required List assets, int placeholderCount = 0, - List specialItemModels = const [], + List<_SpecialItemModel> specialItemModels = const [], }) { final PathWrapper? currentWrapper = context .select?>( @@ -2475,8 +2480,3 @@ class DefaultAssetPickerBuilderDelegate ); } } - -typedef SpecialItemModel = ({ - SpecialItemPosition position, - Widget item, -}); From c3175991a54275c336ccb01a996226af31f855c0 Mon Sep 17 00:00:00 2001 From: yujune Date: Thu, 17 Oct 2024 13:42:13 +0800 Subject: [PATCH 15/19] Fix wrong special item calculation and naming. --- .../pickers/directory_file_asset_picker.dart | 65 +++++++++- .../asset_picker_builder_delegate.dart | 122 ++++++++++-------- 2 files changed, 126 insertions(+), 61 deletions(-) diff --git a/example/lib/customs/pickers/directory_file_asset_picker.dart b/example/lib/customs/pickers/directory_file_asset_picker.dart index 9312c333..b6a82f3b 100644 --- a/example/lib/customs/pickers/directory_file_asset_picker.dart +++ b/example/lib/customs/pickers/directory_file_asset_picker.dart @@ -584,9 +584,28 @@ class FileAssetPickerBuilder Widget assetsGridBuilder(BuildContext context) { appBarPreferredSize ??= appBar(context).preferredSize; int totalCount = provider.currentAssets.length; - if (specialItems.isNotEmpty) { - totalCount += specialItems.length; - } + + final List specialItemResults = specialItems + .map((item) { + final specialItem = item.builder?.call( + context, + provider.currentPath?.path, + totalCount, + permissionNotifier.value, + ); + if (specialItem != null) { + return SpecialItemResult( + position: item.position, + item: specialItem, + ); + } + return null; + }) + .whereType() + .toList(); + + totalCount += specialItemResults.length; + final int placeholderCount; if (isAppleOS(context) && totalCount % gridCount != 0) { placeholderCount = gridCount - totalCount % gridCount; @@ -626,6 +645,11 @@ class FileAssetPickerBuilder id: key.value, assets: assets, placeholderCount: placeholderCount, + prependSpecialItemResults: specialItemResults + .where( + (item) => item.position == SpecialItemPosition.prepend, + ) + .toList(), ); } return null; @@ -699,9 +723,36 @@ class FileAssetPickerBuilder Widget assetGridItemBuilder( BuildContext context, int index, - List currentAssets, - ) { - final currentIndex = index - prependSpecialItems.length; + List currentAssets, { + List specialItemResults = const [], + }) { + final int length = currentAssets.length; + + final prependItems = []; + final appendItems = []; + for (final model in specialItemResults) { + switch (model.position) { + case SpecialItemPosition.prepend: + prependItems.add(model); + case SpecialItemPosition.append: + appendItems.add(model); + } + } + + if (prependItems.isNotEmpty) { + if (index < prependItems.length) { + return specialItemResults[index].item; + } + } + + if (appendItems.isNotEmpty) { + if (index >= length + prependItems.length) { + return specialItemResults[index - length].item; + } + } + + final currentIndex = index - prependItems.length; + final File asset = currentAssets.elementAt(currentIndex); final Widget builder = imageAndVideoItemBuilder( context, @@ -724,6 +775,7 @@ class FileAssetPickerBuilder int index, File asset, Widget child, + List prependSpecialItemResults, ) { return Semantics(child: child); } @@ -1161,6 +1213,7 @@ class FileAssetPickerBuilder int findChildIndexBuilder({ required String id, required List assets, + required List prependSpecialItemResults, int placeholderCount = 0, }) { return assets.indexWhere((File file) => file.path == id); diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index a69151c8..fe85bdb9 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -28,10 +28,17 @@ import '../widget/asset_picker_app_bar.dart'; import '../widget/asset_picker_viewer.dart'; import '../widget/builder/asset_entity_grid_item_builder.dart'; -typedef _SpecialItemModel = ({ - SpecialItemPosition position, - Widget item, -}); +/// Class which contains non-null special item widget and its position which derived from the [SpecialItem] +/// 包含非空自定义item,并指定其位置。 +class SpecialItemResult { + SpecialItemResult({ + required this.position, + required this.item, + }); + + SpecialItemPosition position; + Widget item; +} /// The delegate to build the whole picker's components. /// @@ -62,17 +69,7 @@ abstract class AssetPickerBuilderDelegate { ), themeColor = pickerTheme?.colorScheme.secondary ?? themeColor ?? - defaultThemeColorWeChat, - prependSpecialItems = specialItems - .where( - (item) => item.position == SpecialItemPosition.prepend, - ) - .toList(), - appendSpecialItems = specialItems - .where( - (item) => item.position == SpecialItemPosition.append, - ) - .toList() { + defaultThemeColorWeChat { Singleton.textDelegate = textDelegate ?? assetPickerTextDelegateFromLocale(locale); } @@ -141,14 +138,6 @@ abstract class AssetPickerBuilderDelegate { final AssetsChangeRefreshPredicate? assetsChangeRefreshPredicate; - /// List of prepend special items. - /// 前置自定义item列表 - final List> prependSpecialItems; - - /// List of append special items. - /// 附加自定义item列表 - final List> appendSpecialItems; - /// [ThemeData] for the picker. /// 选择器使用的主题 ThemeData get theme => pickerTheme ?? AssetPicker.themeData(themeColor); @@ -341,6 +330,7 @@ abstract class AssetPickerBuilderDelegate { int? findChildIndexBuilder({ required String id, required List assets, + required List prependSpecialItemResults, int placeholderCount = 0, }) => null; @@ -368,6 +358,7 @@ abstract class AssetPickerBuilderDelegate { int index, Asset asset, Widget child, + List prependSpecialItemResults, ); /// The item builder for audio type of asset. @@ -1248,24 +1239,28 @@ class DefaultAssetPickerBuilderDelegate // First, we need the count of the assets. int totalCount = wrapper?.assetCount ?? 0; - final List<_SpecialItemModel> specialItemModels = specialItems + final List specialItemResults = specialItems .map((item) { - return ( - position: item.position, - item: item.builder?.call( - context, - wrapper?.path, - totalCount, - permissionNotifier.value, - ) + final specialItem = item.builder?.call( + context, + wrapper?.path, + totalCount, + permissionNotifier.value, ); + if (specialItem != null) { + return SpecialItemResult( + position: item.position, + item: specialItem, + ); + } + return null; }) - .whereType<_SpecialItemModel>() + .whereType() .toList(); - totalCount += specialItemModels.length; + totalCount += specialItemResults.length; - if (totalCount == 0 && specialItemModels.isEmpty) { + if (totalCount == 0 && specialItemResults.isEmpty) { return loadingIndicator(context); } // Then we use the [totalCount] to calculate placeholders we need. @@ -1305,7 +1300,7 @@ class DefaultAssetPickerBuilderDelegate context, index, assets, - specialItemModels: specialItemModels, + specialItemResults: specialItemResults, ), ), ); @@ -1314,7 +1309,7 @@ class DefaultAssetPickerBuilderDelegate context: context, assets: assets, placeholderCount: placeholderCount, - specialItemModels: specialItemModels, + specialItemResults: specialItemResults, ), findChildIndexCallback: (Key? key) { if (key is ValueKey) { @@ -1322,6 +1317,12 @@ class DefaultAssetPickerBuilderDelegate id: key.value, assets: assets, placeholderCount: placeholderCount, + prependSpecialItemResults: specialItemResults + .where( + (item) => + item.position == SpecialItemPosition.prepend, + ) + .toList(), ); } return null; @@ -1424,7 +1425,7 @@ class DefaultAssetPickerBuilderDelegate BuildContext context, int index, List currentAssets, { - List<_SpecialItemModel> specialItemModels = const [], + List specialItemResults = const [], }) { final DefaultAssetPickerProvider p = context.read(); @@ -1432,9 +1433,9 @@ class DefaultAssetPickerBuilderDelegate final PathWrapper? currentWrapper = p.currentPath; final AssetPathEntity? currentPathEntity = currentWrapper?.path; - final prependItems = <_SpecialItemModel>[]; - final appendItems = <_SpecialItemModel>[]; - for (final model in specialItemModels) { + final prependItems = []; + final appendItems = []; + for (final model in specialItemResults) { switch (model.position) { case SpecialItemPosition.prepend: prependItems.add(model); @@ -1445,13 +1446,13 @@ class DefaultAssetPickerBuilderDelegate if (prependItems.isNotEmpty) { if (index < prependItems.length) { - return specialItemModels[index].item; + return specialItemResults[index].item; } } if (appendItems.isNotEmpty) { if (index >= length + prependItems.length) { - return specialItemModels[index - length].item; + return specialItemResults[index - length].item; } } @@ -1486,11 +1487,20 @@ class DefaultAssetPickerBuilderDelegate itemBannedIndicator(context, asset), ], ); - return assetGridItemSemanticsBuilder(context, index, asset, content); + return assetGridItemSemanticsBuilder( + context, + index, + asset, + content, + prependItems, + ); } - int semanticIndex(int index) { - return index - prependSpecialItems.length; + int semanticIndex( + int index, + List prependSpecialItemResults, + ) { + return index - prependSpecialItemResults.length; } @override @@ -1499,6 +1509,7 @@ class DefaultAssetPickerBuilderDelegate int index, AssetEntity asset, Widget child, + List prependSpecialItemResults, ) { return ValueListenableBuilder( valueListenable: isSwitchingPath, @@ -1532,7 +1543,7 @@ class DefaultAssetPickerBuilderDelegate excludeSemantics: true, focusable: !isSwitchingPath, label: '${semanticsTextDelegate.semanticTypeLabel(asset.type)}' - '${semanticIndex(index)}, ' + '${semanticIndex(index, prependSpecialItemResults)}, ' '${asset.createDateTime.toString().replaceAll('.000', '')}', hidden: isSwitchingPath, hint: hint, @@ -1550,7 +1561,7 @@ class DefaultAssetPickerBuilderDelegate onLongPressHint: semanticsTextDelegate.sActionPreviewHint, selected: isSelected, sortKey: OrdinalSortKey( - semanticIndex(index).toDouble(), + semanticIndex(index, prependSpecialItemResults).toDouble(), name: 'GridItem', ), value: selectedIndex > 0 ? '$selectedIndex' : null, @@ -1563,7 +1574,7 @@ class DefaultAssetPickerBuilderDelegate } : null, child: IndexedSemantics( - index: semanticIndex(index), + index: semanticIndex(index, prependSpecialItemResults), child: child, ), ), @@ -1579,10 +1590,11 @@ class DefaultAssetPickerBuilderDelegate int findChildIndexBuilder({ required String id, required List assets, + required List prependSpecialItemResults, int placeholderCount = 0, }) { int index = assets.indexWhere((AssetEntity e) => e.id == id); - index += prependSpecialItems.length; + index += prependSpecialItemResults.length; index += placeholderCount; return index; } @@ -1592,7 +1604,7 @@ class DefaultAssetPickerBuilderDelegate required BuildContext context, required List assets, int placeholderCount = 0, - List<_SpecialItemModel> specialItemModels = const [], + List specialItemResults = const [], }) { final PathWrapper? currentWrapper = context .select?>( @@ -1602,17 +1614,17 @@ class DefaultAssetPickerBuilderDelegate final int length = assets.length + placeholderCount; // Return 1 if the [specialItem] build something. - if (currentPathEntity == null && specialItemModels.isNotEmpty) { - return placeholderCount + specialItemModels.length; + if (currentPathEntity == null && specialItemResults.isNotEmpty) { + return placeholderCount + specialItemResults.length; } // Return actual length if the current path is all. // 如果当前目录是全部内容,则返回实际的内容数量。 - if (currentPathEntity?.isAll != true && specialItemModels.isEmpty) { + if (currentPathEntity?.isAll != true && specialItemResults.isEmpty) { return length; } - return length + specialItemModels.length; + return length + specialItemResults.length; } @override From 6bb5118c7e4d84b21d5626860fe8a32fb7a6f016 Mon Sep 17 00:00:00 2001 From: yujune Date: Thu, 17 Oct 2024 13:56:35 +0800 Subject: [PATCH 16/19] Add null builder in example. --- example/lib/constants/picker_method.dart | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index e990a4dd..97b84f6c 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -369,6 +369,29 @@ class PickMethod { ); }, ), + //builder which return null will not be shown. + SpecialItem( + position: SpecialItemPosition.append, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + PermissionState permissionState, + ) { + return null; + }, + ), + SpecialItem( + position: SpecialItemPosition.prepend, + builder: ( + BuildContext context, + AssetPathEntity? path, + int length, + PermissionState permissionState, + ) { + return null; + }, + ), ], ), ); From eba27105aca34e9e7dd3696a1bec87542fa5af7a Mon Sep 17 00:00:00 2001 From: yujune Date: Sun, 20 Oct 2024 21:09:27 +0800 Subject: [PATCH 17/19] Rename SpecialItemResult ot SpecialItemModel. --- .../pickers/directory_file_asset_picker.dart | 26 ++++----- .../asset_picker_builder_delegate.dart | 56 +++++++++---------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/example/lib/customs/pickers/directory_file_asset_picker.dart b/example/lib/customs/pickers/directory_file_asset_picker.dart index b6a82f3b..ef487b64 100644 --- a/example/lib/customs/pickers/directory_file_asset_picker.dart +++ b/example/lib/customs/pickers/directory_file_asset_picker.dart @@ -585,7 +585,7 @@ class FileAssetPickerBuilder appBarPreferredSize ??= appBar(context).preferredSize; int totalCount = provider.currentAssets.length; - final List specialItemResults = specialItems + final List specialItemModels = specialItems .map((item) { final specialItem = item.builder?.call( context, @@ -594,17 +594,17 @@ class FileAssetPickerBuilder permissionNotifier.value, ); if (specialItem != null) { - return SpecialItemResult( + return SpecialItemModel( position: item.position, item: specialItem, ); } return null; }) - .whereType() + .whereType() .toList(); - totalCount += specialItemResults.length; + totalCount += specialItemModels.length; final int placeholderCount; if (isAppleOS(context) && totalCount % gridCount != 0) { @@ -645,7 +645,7 @@ class FileAssetPickerBuilder id: key.value, assets: assets, placeholderCount: placeholderCount, - prependSpecialItemResults: specialItemResults + prependSpecialItemResults: specialItemModels .where( (item) => item.position == SpecialItemPosition.prepend, ) @@ -724,13 +724,13 @@ class FileAssetPickerBuilder BuildContext context, int index, List currentAssets, { - List specialItemResults = const [], + List specialItemModels = const [], }) { final int length = currentAssets.length; - final prependItems = []; - final appendItems = []; - for (final model in specialItemResults) { + final prependItems = []; + final appendItems = []; + for (final model in specialItemModels) { switch (model.position) { case SpecialItemPosition.prepend: prependItems.add(model); @@ -741,13 +741,13 @@ class FileAssetPickerBuilder if (prependItems.isNotEmpty) { if (index < prependItems.length) { - return specialItemResults[index].item; + return specialItemModels[index].item; } } if (appendItems.isNotEmpty) { if (index >= length + prependItems.length) { - return specialItemResults[index - length].item; + return specialItemModels[index - length].item; } } @@ -775,7 +775,7 @@ class FileAssetPickerBuilder int index, File asset, Widget child, - List prependSpecialItemResults, + List prependSpecialItemResults, ) { return Semantics(child: child); } @@ -1213,7 +1213,7 @@ class FileAssetPickerBuilder int findChildIndexBuilder({ required String id, required List assets, - required List prependSpecialItemResults, + required List prependSpecialItemResults, int placeholderCount = 0, }) { return assets.indexWhere((File file) => file.path == id); diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index fe85bdb9..c1bcec3c 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -30,14 +30,14 @@ import '../widget/builder/asset_entity_grid_item_builder.dart'; /// Class which contains non-null special item widget and its position which derived from the [SpecialItem] /// 包含非空自定义item,并指定其位置。 -class SpecialItemResult { - SpecialItemResult({ +class SpecialItemModel { + const SpecialItemModel({ required this.position, required this.item, }); - SpecialItemPosition position; - Widget item; + final SpecialItemPosition position; + final Widget item; } /// The delegate to build the whole picker's components. @@ -330,7 +330,7 @@ abstract class AssetPickerBuilderDelegate { int? findChildIndexBuilder({ required String id, required List assets, - required List prependSpecialItemResults, + required List prependSpecialItemResults, int placeholderCount = 0, }) => null; @@ -358,7 +358,7 @@ abstract class AssetPickerBuilderDelegate { int index, Asset asset, Widget child, - List prependSpecialItemResults, + List prependSpecialItemResults, ); /// The item builder for audio type of asset. @@ -1239,7 +1239,7 @@ class DefaultAssetPickerBuilderDelegate // First, we need the count of the assets. int totalCount = wrapper?.assetCount ?? 0; - final List specialItemResults = specialItems + final List specialItemModels = specialItems .map((item) { final specialItem = item.builder?.call( context, @@ -1248,19 +1248,19 @@ class DefaultAssetPickerBuilderDelegate permissionNotifier.value, ); if (specialItem != null) { - return SpecialItemResult( + return SpecialItemModel( position: item.position, item: specialItem, ); } return null; }) - .whereType() + .whereType() .toList(); - totalCount += specialItemResults.length; + totalCount += specialItemModels.length; - if (totalCount == 0 && specialItemResults.isEmpty) { + if (totalCount == 0 && specialItemModels.isEmpty) { return loadingIndicator(context); } // Then we use the [totalCount] to calculate placeholders we need. @@ -1300,7 +1300,7 @@ class DefaultAssetPickerBuilderDelegate context, index, assets, - specialItemResults: specialItemResults, + specialItemModels: specialItemModels, ), ), ); @@ -1309,7 +1309,7 @@ class DefaultAssetPickerBuilderDelegate context: context, assets: assets, placeholderCount: placeholderCount, - specialItemResults: specialItemResults, + specialItemModels: specialItemModels, ), findChildIndexCallback: (Key? key) { if (key is ValueKey) { @@ -1317,7 +1317,7 @@ class DefaultAssetPickerBuilderDelegate id: key.value, assets: assets, placeholderCount: placeholderCount, - prependSpecialItemResults: specialItemResults + prependSpecialItemResults: specialItemModels .where( (item) => item.position == SpecialItemPosition.prepend, @@ -1425,7 +1425,7 @@ class DefaultAssetPickerBuilderDelegate BuildContext context, int index, List currentAssets, { - List specialItemResults = const [], + List specialItemModels = const [], }) { final DefaultAssetPickerProvider p = context.read(); @@ -1433,9 +1433,9 @@ class DefaultAssetPickerBuilderDelegate final PathWrapper? currentWrapper = p.currentPath; final AssetPathEntity? currentPathEntity = currentWrapper?.path; - final prependItems = []; - final appendItems = []; - for (final model in specialItemResults) { + final prependItems = []; + final appendItems = []; + for (final model in specialItemModels) { switch (model.position) { case SpecialItemPosition.prepend: prependItems.add(model); @@ -1446,13 +1446,13 @@ class DefaultAssetPickerBuilderDelegate if (prependItems.isNotEmpty) { if (index < prependItems.length) { - return specialItemResults[index].item; + return specialItemModels[index].item; } } if (appendItems.isNotEmpty) { if (index >= length + prependItems.length) { - return specialItemResults[index - length].item; + return specialItemModels[index - length].item; } } @@ -1498,7 +1498,7 @@ class DefaultAssetPickerBuilderDelegate int semanticIndex( int index, - List prependSpecialItemResults, + List prependSpecialItemResults, ) { return index - prependSpecialItemResults.length; } @@ -1509,7 +1509,7 @@ class DefaultAssetPickerBuilderDelegate int index, AssetEntity asset, Widget child, - List prependSpecialItemResults, + List prependSpecialItemResults, ) { return ValueListenableBuilder( valueListenable: isSwitchingPath, @@ -1590,7 +1590,7 @@ class DefaultAssetPickerBuilderDelegate int findChildIndexBuilder({ required String id, required List assets, - required List prependSpecialItemResults, + required List prependSpecialItemResults, int placeholderCount = 0, }) { int index = assets.indexWhere((AssetEntity e) => e.id == id); @@ -1604,7 +1604,7 @@ class DefaultAssetPickerBuilderDelegate required BuildContext context, required List assets, int placeholderCount = 0, - List specialItemResults = const [], + List specialItemModels = const [], }) { final PathWrapper? currentWrapper = context .select?>( @@ -1614,17 +1614,17 @@ class DefaultAssetPickerBuilderDelegate final int length = assets.length + placeholderCount; // Return 1 if the [specialItem] build something. - if (currentPathEntity == null && specialItemResults.isNotEmpty) { - return placeholderCount + specialItemResults.length; + if (currentPathEntity == null && specialItemModels.isNotEmpty) { + return placeholderCount + specialItemModels.length; } // Return actual length if the current path is all. // 如果当前目录是全部内容,则返回实际的内容数量。 - if (currentPathEntity?.isAll != true && specialItemResults.isEmpty) { + if (currentPathEntity?.isAll != true && specialItemModels.isEmpty) { return length; } - return length + specialItemResults.length; + return length + specialItemModels.length; } @override From b1db75230955a123887328d66b45781ea09278d4 Mon Sep 17 00:00:00 2001 From: yujune Date: Sun, 20 Oct 2024 21:19:04 +0800 Subject: [PATCH 18/19] Use specialItemModels as args. --- .../pickers/directory_file_asset_picker.dart | 6 ++-- .../asset_picker_builder_delegate.dart | 35 ++++++++++--------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/example/lib/customs/pickers/directory_file_asset_picker.dart b/example/lib/customs/pickers/directory_file_asset_picker.dart index ef487b64..0fc2d2ef 100644 --- a/example/lib/customs/pickers/directory_file_asset_picker.dart +++ b/example/lib/customs/pickers/directory_file_asset_picker.dart @@ -645,7 +645,7 @@ class FileAssetPickerBuilder id: key.value, assets: assets, placeholderCount: placeholderCount, - prependSpecialItemResults: specialItemModels + specialItemModels: specialItemModels .where( (item) => item.position == SpecialItemPosition.prepend, ) @@ -775,7 +775,7 @@ class FileAssetPickerBuilder int index, File asset, Widget child, - List prependSpecialItemResults, + List specialItemModels, ) { return Semantics(child: child); } @@ -1213,7 +1213,7 @@ class FileAssetPickerBuilder int findChildIndexBuilder({ required String id, required List assets, - required List prependSpecialItemResults, + required List specialItemModels, int placeholderCount = 0, }) { return assets.indexWhere((File file) => file.path == id); diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index c1bcec3c..41333b7a 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -330,7 +330,7 @@ abstract class AssetPickerBuilderDelegate { int? findChildIndexBuilder({ required String id, required List assets, - required List prependSpecialItemResults, + required List specialItemModels, int placeholderCount = 0, }) => null; @@ -358,7 +358,7 @@ abstract class AssetPickerBuilderDelegate { int index, Asset asset, Widget child, - List prependSpecialItemResults, + List specialItemModels, ); /// The item builder for audio type of asset. @@ -1317,12 +1317,7 @@ class DefaultAssetPickerBuilderDelegate id: key.value, assets: assets, placeholderCount: placeholderCount, - prependSpecialItemResults: specialItemModels - .where( - (item) => - item.position == SpecialItemPosition.prepend, - ) - .toList(), + specialItemModels: specialItemModels, ); } return null; @@ -1492,15 +1487,18 @@ class DefaultAssetPickerBuilderDelegate index, asset, content, - prependItems, + specialItemModels, ); } int semanticIndex( int index, - List prependSpecialItemResults, + List specialItemModels, ) { - return index - prependSpecialItemResults.length; + final prependSpecialItemModels = specialItemModels.where( + (SpecialItemModel model) => model.position == SpecialItemPosition.prepend, + ); + return index - prependSpecialItemModels.length; } @override @@ -1509,7 +1507,7 @@ class DefaultAssetPickerBuilderDelegate int index, AssetEntity asset, Widget child, - List prependSpecialItemResults, + List specialItemModels, ) { return ValueListenableBuilder( valueListenable: isSwitchingPath, @@ -1543,7 +1541,7 @@ class DefaultAssetPickerBuilderDelegate excludeSemantics: true, focusable: !isSwitchingPath, label: '${semanticsTextDelegate.semanticTypeLabel(asset.type)}' - '${semanticIndex(index, prependSpecialItemResults)}, ' + '${semanticIndex(index, specialItemModels)}, ' '${asset.createDateTime.toString().replaceAll('.000', '')}', hidden: isSwitchingPath, hint: hint, @@ -1561,7 +1559,7 @@ class DefaultAssetPickerBuilderDelegate onLongPressHint: semanticsTextDelegate.sActionPreviewHint, selected: isSelected, sortKey: OrdinalSortKey( - semanticIndex(index, prependSpecialItemResults).toDouble(), + semanticIndex(index, specialItemModels).toDouble(), name: 'GridItem', ), value: selectedIndex > 0 ? '$selectedIndex' : null, @@ -1574,7 +1572,7 @@ class DefaultAssetPickerBuilderDelegate } : null, child: IndexedSemantics( - index: semanticIndex(index, prependSpecialItemResults), + index: semanticIndex(index, specialItemModels), child: child, ), ), @@ -1590,11 +1588,14 @@ class DefaultAssetPickerBuilderDelegate int findChildIndexBuilder({ required String id, required List assets, - required List prependSpecialItemResults, + required List specialItemModels, int placeholderCount = 0, }) { + final prependSpecialItemModels = specialItemModels.where( + (SpecialItemModel model) => model.position == SpecialItemPosition.prepend, + ); int index = assets.indexWhere((AssetEntity e) => e.id == id); - index += prependSpecialItemResults.length; + index += prependSpecialItemModels.length; index += placeholderCount; return index; } From 054752ce0ed0a5063cfbb3efba144c850f80afc6 Mon Sep 17 00:00:00 2001 From: yujune Date: Mon, 11 Nov 2024 10:18:34 +0800 Subject: [PATCH 19/19] Remove shouldBuildSpecialItem. --- .../customs/pickers/insta_asset_picker.dart | 3 +- .../pickers/multi_tabs_assets_picker.dart | 37 ++++------ .../asset_picker_builder_delegate.dart | 68 ++++++------------- 3 files changed, 33 insertions(+), 75 deletions(-) diff --git a/example/lib/customs/pickers/insta_asset_picker.dart b/example/lib/customs/pickers/insta_asset_picker.dart index c0ed62f3..36efc88b 100644 --- a/example/lib/customs/pickers/insta_asset_picker.dart +++ b/example/lib/customs/pickers/insta_asset_picker.dart @@ -673,8 +673,7 @@ class InstaAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate { appBarPreferredSize ??= appBar(context).preferredSize; return Consumer( builder: (BuildContext context, DefaultAssetPickerProvider p, __) { - final bool shouldDisplayAssets = - p.hasAssetsToDisplay || shouldBuildSpecialItem; + final bool shouldDisplayAssets = p.hasAssetsToDisplay; _initializePreviewAsset(p, shouldDisplayAssets); return AnimatedSwitcher( diff --git a/example/lib/customs/pickers/multi_tabs_assets_picker.dart b/example/lib/customs/pickers/multi_tabs_assets_picker.dart index f60689e6..31b638c3 100644 --- a/example/lib/customs/pickers/multi_tabs_assets_picker.dart +++ b/example/lib/customs/pickers/multi_tabs_assets_picker.dart @@ -518,30 +518,19 @@ class MultiTabAssetPickerBuilder extends DefaultAssetPickerBuilderDelegate { } Widget _buildGrid(BuildContext context) { - return Consumer( - builder: (BuildContext context, DefaultAssetPickerProvider p, __) { - final bool shouldDisplayAssets = - p.hasAssetsToDisplay || shouldBuildSpecialItem; - return AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: shouldDisplayAssets - ? Stack( - children: [ - RepaintBoundary( - child: Column( - children: [ - Expanded(child: assetsGridBuilder(context)), - bottomActionBar(context), - ], - ), - ), - pathEntityListBackdrop(context), - pathEntityListWidget(context), - ], - ) - : loadingIndicator(context), - ); - }, + return Stack( + children: [ + RepaintBoundary( + child: Column( + children: [ + Expanded(child: assetsGridBuilder(context)), + bottomActionBar(context), + ], + ), + ), + pathEntityListBackdrop(context), + pathEntityListWidget(context), + ], ); } diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 41333b7a..f5a371a8 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -176,10 +176,6 @@ abstract class AssetPickerBuilderDelegate { /// 选择器是否为单选模式 bool get isSingleAssetMode; - /// Whether the delegate should build the special item. - /// 是否需要构建自定义 item - bool get shouldBuildSpecialItem => specialItems.isNotEmpty; - /// Space between assets item widget. /// 资源部件之间的间隔 double get itemSpacing => 2; @@ -1121,30 +1117,19 @@ class DefaultAssetPickerBuilderDelegate Widget androidLayout(BuildContext context) { return AssetPickerAppBarWrapper( appBar: appBar(context), - body: Consumer( - builder: (BuildContext context, DefaultAssetPickerProvider p, _) { - final bool shouldDisplayAssets = - p.hasAssetsToDisplay || shouldBuildSpecialItem; - return AnimatedSwitcher( - duration: switchingPathDuration, - child: shouldDisplayAssets - ? Stack( - children: [ - RepaintBoundary( - child: Column( - children: [ - Expanded(child: assetsGridBuilder(context)), - bottomActionBar(context), - ], - ), - ), - pathEntityListBackdrop(context), - pathEntityListWidget(context), - ], - ) - : loadingIndicator(context), - ); - }, + body: Stack( + children: [ + RepaintBoundary( + child: Column( + children: [ + Expanded(child: assetsGridBuilder(context)), + bottomActionBar(context), + ], + ), + ), + pathEntityListBackdrop(context), + pathEntityListWidget(context), + ], ), ); } @@ -1172,27 +1157,12 @@ class DefaultAssetPickerBuilderDelegate return Stack( children: [ Positioned.fill( - child: Consumer( - builder: (_, DefaultAssetPickerProvider p, __) { - final Widget child; - final bool shouldDisplayAssets = - p.hasAssetsToDisplay || shouldBuildSpecialItem; - if (shouldDisplayAssets) { - child = Stack( - children: [ - gridLayout(context), - pathEntityListBackdrop(context), - pathEntityListWidget(context), - ], - ); - } else { - child = loadingIndicator(context); - } - return AnimatedSwitcher( - duration: switchingPathDuration, - child: child, - ); - }, + child: Stack( + children: [ + gridLayout(context), + pathEntityListBackdrop(context), + pathEntityListWidget(context), + ], ), ), appBar(context),