Skip to content

Commit eeb49b8

Browse files
authored
🚀 Support predictable special item display (#264)
1 parent 7faa9b5 commit eeb49b8

File tree

8 files changed

+113
-75
lines changed

8 files changed

+113
-75
lines changed

example/lib/constants/picker_method.dart

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,14 @@ class PickMethod {
8686
selectedAssets: assets,
8787
requestType: RequestType.common,
8888
specialItemPosition: SpecialItemPosition.prepend,
89-
specialItemBuilder: (BuildContext context) {
89+
specialItemBuilder: (
90+
BuildContext context,
91+
AssetPathEntity? path,
92+
int length,
93+
) {
94+
if (path?.isAll != true) {
95+
return null;
96+
}
9097
return Semantics(
9198
label: AssetPickerTextDelegate().sActionUseCameraHint,
9299
button: true,
@@ -130,7 +137,14 @@ class PickMethod {
130137
selectedAssets: assets,
131138
requestType: RequestType.common,
132139
specialItemPosition: SpecialItemPosition.prepend,
133-
specialItemBuilder: (BuildContext context) {
140+
specialItemBuilder: (
141+
BuildContext context,
142+
AssetPathEntity? path,
143+
int length,
144+
) {
145+
if (path?.isAll != true) {
146+
return null;
147+
}
134148
return Semantics(
135149
label: AssetPickerTextDelegate().sActionUseCameraHint,
136150
button: true,
@@ -247,7 +261,11 @@ class PickMethod {
247261
selectedAssets: assets,
248262
requestType: RequestType.common,
249263
specialItemPosition: SpecialItemPosition.prepend,
250-
specialItemBuilder: (BuildContext context) {
264+
specialItemBuilder: (
265+
BuildContext context,
266+
AssetPathEntity? path,
267+
int length,
268+
) {
251269
return const Center(
252270
child: Text('Custom Widget', textAlign: TextAlign.center),
253271
);

lib/src/constants/config.dart

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
///
55
import 'package:flutter/material.dart';
66
import 'package:photo_manager/photo_manager.dart';
7-
import 'package:wechat_assets_picker/src/delegates/asset_picker_text_delegate.dart';
87

9-
import '../delegates/asset_picker_builder_delegate.dart';
8+
import '../constants/typedefs.dart';
9+
import '../delegates/asset_picker_text_delegate.dart';
1010
import '../delegates/sort_path_delegate.dart';
1111
import 'constants.dart';
1212
import 'enums.dart';
@@ -31,7 +31,6 @@ class AssetPickerConfig {
3131
this.specialItemPosition = SpecialItemPosition.none,
3232
this.specialItemBuilder,
3333
this.loadingIndicatorBuilder,
34-
this.allowSpecialItemWhenEmpty = false,
3534
this.selectPredicate,
3635
this.shouldRevertGrid,
3736
}) : assert(maxAssets >= 1, 'maxAssets must be greater than 1.'),
@@ -159,15 +158,11 @@ class AssetPickerConfig {
159158

160159
/// The widget builder for the the special item.
161160
/// 自定义item的构造方法
162-
final WidgetBuilder? specialItemBuilder;
161+
final SpecialItemBuilder<AssetPathEntity>? specialItemBuilder;
163162

164163
/// Indicates the loading status for the builder.
165164
/// 指示目前加载的状态
166-
final IndicatorBuilder? loadingIndicatorBuilder;
167-
168-
/// Whether the special item will display or not when assets is empty.
169-
/// 当没有资源时是否显示自定义item
170-
final bool allowSpecialItemWhenEmpty;
165+
final LoadingIndicatorBuilder? loadingIndicatorBuilder;
171166

172167
/// {@macro wechat_assets_picker.AssetSelectPredicate}
173168
final AssetSelectPredicate<AssetEntity>? selectPredicate;

lib/src/constants/typedefs.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
///
2+
/// [Author] Alex (https://github.com/AlexV525)
3+
/// [Date] 2022/3/3 09:55
4+
///
5+
import 'dart:async';
6+
7+
import 'package:flutter/widgets.dart';
8+
9+
typedef LoadingIndicatorBuilder = Widget Function(
10+
BuildContext context,
11+
bool isAssetsEmpty,
12+
);
13+
14+
/// {@template wechat_assets_picker.AssetSelectPredicate}
15+
/// Predicate whether an asset can be selected or unselected.
16+
/// 判断资源可否被选择
17+
/// {@endtemplate}
18+
typedef AssetSelectPredicate<Asset> = FutureOr<bool> Function(
19+
BuildContext context,
20+
Asset asset,
21+
bool isSelected,
22+
);
23+
24+
/// {@template wechat_asset_picker.SpecialItemBuilder}
25+
/// Build the special item according the given path and assets length.
26+
/// 根据给定的目录和资源数量构建特殊 item
27+
/// {@endtemplate}
28+
typedef SpecialItemBuilder<Path> = Widget? Function(
29+
BuildContext context,
30+
Path? path,
31+
int length,
32+
);

lib/src/delegates/asset_picker_builder_delegate.dart

Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'package:provider/provider.dart';
1919
import '../constants/constants.dart';
2020
import '../constants/enums.dart';
2121
import '../constants/extensions.dart';
22+
import '../constants/typedefs.dart';
2223
import '../delegates/asset_picker_text_delegate.dart';
2324
import '../internal/singleton.dart';
2425
import '../provider/asset_picker_provider.dart';
@@ -33,21 +34,6 @@ import '../widget/scale_text.dart';
3334

3435
const String _ordinalNamePermissionOverlay = 'permissionOverlay';
3536

36-
typedef IndicatorBuilder = Widget Function(
37-
BuildContext context,
38-
bool isAssetsEmpty,
39-
);
40-
41-
/// {@template wechat_assets_picker.AssetSelectPredicate}
42-
/// Predicate whether an asset can be selected or unselected.
43-
/// 判断资源可否被选择
44-
/// {@endtemplate}
45-
typedef AssetSelectPredicate<Asset> = FutureOr<bool> Function(
46-
BuildContext context,
47-
Asset asset,
48-
bool isSelected,
49-
);
50-
5137
/// The delegate to build the whole picker's components.
5238
///
5339
/// By extending the delegate, you can customize every components on you own.
@@ -62,7 +48,6 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
6248
this.specialItemPosition = SpecialItemPosition.none,
6349
this.specialItemBuilder,
6450
this.loadingIndicatorBuilder,
65-
this.allowSpecialItemWhenEmpty = false,
6651
this.selectPredicate,
6752
this.shouldRevertGrid,
6853
Color? themeColor,
@@ -107,15 +92,11 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
10792

10893
/// The widget builder for the the special item.
10994
/// 自定义item的构造方法
110-
final WidgetBuilder? specialItemBuilder;
95+
final SpecialItemBuilder<Path>? specialItemBuilder;
11196

11297
/// Indicates the loading status for the builder.
11398
/// 指示目前加载的状态
114-
final IndicatorBuilder? loadingIndicatorBuilder;
115-
116-
/// Whether the special item will display or not when assets is empty.
117-
/// 当没有资源时是否显示自定义item
118-
final bool allowSpecialItemWhenEmpty;
99+
final LoadingIndicatorBuilder? loadingIndicatorBuilder;
119100

120101
/// {@macro wechat_assets_picker.AssetSelectPredicate}
121102
final AssetSelectPredicate<Asset>? selectPredicate;
@@ -668,9 +649,8 @@ class DefaultAssetPickerBuilderDelegate
668649
int gridCount = 4,
669650
ThemeData? pickerTheme,
670651
SpecialItemPosition specialItemPosition = SpecialItemPosition.none,
671-
WidgetBuilder? specialItemBuilder,
672-
IndicatorBuilder? loadingIndicatorBuilder,
673-
bool allowSpecialItemWhenEmpty = false,
652+
SpecialItemBuilder<AssetPathEntity>? specialItemBuilder,
653+
LoadingIndicatorBuilder? loadingIndicatorBuilder,
674654
AssetSelectPredicate<AssetEntity>? selectPredicate,
675655
bool? shouldRevertGrid,
676656
this.gridThumbnailSize = defaultAssetGridPreviewSize,
@@ -691,7 +671,6 @@ class DefaultAssetPickerBuilderDelegate
691671
specialItemPosition: specialItemPosition,
692672
specialItemBuilder: specialItemBuilder,
693673
loadingIndicatorBuilder: loadingIndicatorBuilder,
694-
allowSpecialItemWhenEmpty: allowSpecialItemWhenEmpty,
695674
selectPredicate: selectPredicate,
696675
shouldRevertGrid: shouldRevertGrid,
697676
themeColor: themeColor,
@@ -922,11 +901,15 @@ class DefaultAssetPickerBuilderDelegate
922901
Widget androidLayout(BuildContext context) {
923902
return AssetPickerAppBarWrapper(
924903
appBar: appBar(context),
925-
body: Selector<DefaultAssetPickerProvider, bool>(
926-
selector: (_, DefaultAssetPickerProvider p) => p.hasAssetsToDisplay,
927-
builder: (_, bool hasAssetsToDisplay, __) {
928-
final bool shouldDisplayAssets = hasAssetsToDisplay ||
929-
(allowSpecialItemWhenEmpty &&
904+
body: Consumer<DefaultAssetPickerProvider>(
905+
builder: (BuildContext context, DefaultAssetPickerProvider p, __) {
906+
final Widget? _specialItem = specialItemBuilder?.call(
907+
context,
908+
p.currentPath,
909+
p.currentAssets.length,
910+
);
911+
final bool shouldDisplayAssets = p.hasAssetsToDisplay ||
912+
(_specialItem != null &&
930913
specialItemPosition != SpecialItemPosition.none);
931914
return AnimatedSwitcher(
932915
duration: switchingPathDuration,
@@ -980,13 +963,16 @@ class DefaultAssetPickerBuilderDelegate
980963
return Stack(
981964
children: <Widget>[
982965
Positioned.fill(
983-
child: Selector<DefaultAssetPickerProvider, bool>(
984-
selector: (_, DefaultAssetPickerProvider p) =>
985-
p.hasAssetsToDisplay,
986-
builder: (_, bool hasAssetsToDisplay, __) {
966+
child: Consumer<DefaultAssetPickerProvider>(
967+
builder: (_, DefaultAssetPickerProvider p, __) {
987968
final Widget _child;
988-
final bool shouldDisplayAssets = hasAssetsToDisplay ||
989-
(allowSpecialItemWhenEmpty &&
969+
final Widget? _specialItem = specialItemBuilder?.call(
970+
context,
971+
p.currentPath,
972+
p.currentAssets.length,
973+
);
974+
final bool shouldDisplayAssets = p.hasAssetsToDisplay ||
975+
(_specialItem != null &&
990976
specialItemPosition != SpecialItemPosition.none);
991977
if (shouldDisplayAssets) {
992978
_child = Stack(
@@ -1192,45 +1178,52 @@ class DefaultAssetPickerBuilderDelegate
11921178
int index,
11931179
List<AssetEntity> currentAssets,
11941180
) {
1181+
final int _length = currentAssets.length;
11951182
final AssetPathEntity? currentPathEntity =
11961183
context.select<DefaultAssetPickerProvider, AssetPathEntity?>(
11971184
(DefaultAssetPickerProvider p) => p.currentPath,
11981185
);
11991186

1200-
int currentIndex;
1201-
switch (specialItemPosition) {
1202-
case SpecialItemPosition.none:
1203-
case SpecialItemPosition.append:
1204-
currentIndex = index;
1205-
break;
1206-
case SpecialItemPosition.prepend:
1207-
currentIndex = index - 1;
1208-
break;
1209-
}
1210-
1211-
// Directly return the special item when it's empty.
1212-
if (currentPathEntity == null) {
1213-
if (allowSpecialItemWhenEmpty &&
1214-
specialItemPosition != SpecialItemPosition.none) {
1215-
return specialItemBuilder!(context);
1216-
}
1217-
return const SizedBox.shrink();
1187+
final Widget? specialItem;
1188+
if (specialItemPosition == SpecialItemPosition.none) {
1189+
specialItem = null;
1190+
} else {
1191+
specialItem = specialItemBuilder?.call(
1192+
context,
1193+
currentPathEntity,
1194+
_length,
1195+
);
12181196
}
12191197

1220-
final int _length = currentAssets.length;
1221-
if (currentPathEntity.isAll &&
1222-
specialItemPosition != SpecialItemPosition.none) {
1198+
if (specialItem != null) {
12231199
if ((index == 0 && specialItemPosition == SpecialItemPosition.prepend) ||
12241200
(index == _length &&
12251201
specialItemPosition == SpecialItemPosition.append)) {
1226-
return specialItemBuilder!(context);
1202+
return specialItem;
12271203
}
12281204
}
12291205

1230-
if (!currentPathEntity.isAll) {
1206+
final int currentIndex;
1207+
if (specialItem != null &&
1208+
specialItemPosition == SpecialItemPosition.prepend) {
1209+
currentIndex = index - 1;
1210+
} else {
12311211
currentIndex = index;
12321212
}
12331213

1214+
if (specialItemPosition != SpecialItemPosition.none) {
1215+
final Widget? specialItem = specialItemBuilder?.call(
1216+
context,
1217+
currentPathEntity,
1218+
_length,
1219+
);
1220+
if (specialItem != null) {}
1221+
}
1222+
1223+
if (currentPathEntity == null) {
1224+
return const SizedBox.shrink();
1225+
}
1226+
12341227
if (index == _length - gridCount * 3 &&
12351228
context.select<DefaultAssetPickerProvider, bool>(
12361229
(DefaultAssetPickerProvider p) => p.hasMoreToLoad,

lib/src/delegates/asset_picker_viewer_builder_delegate.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import 'package:provider/provider.dart';
1616
import '../constants/custom_scroll_physics.dart';
1717
import '../constants/enums.dart';
1818
import '../constants/extensions.dart';
19-
import '../delegates/asset_picker_builder_delegate.dart';
19+
import '../constants/typedefs.dart';
2020
import '../delegates/asset_picker_text_delegate.dart';
2121
import '../internal/singleton.dart';
2222
import '../provider/asset_picker_provider.dart';

lib/src/widget/asset_picker.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class AssetPicker<Asset, Path> extends StatefulWidget {
5959
specialItemPosition: pickerConfig.specialItemPosition,
6060
specialItemBuilder: pickerConfig.specialItemBuilder,
6161
loadingIndicatorBuilder: pickerConfig.loadingIndicatorBuilder,
62-
allowSpecialItemWhenEmpty: pickerConfig.allowSpecialItemWhenEmpty,
6362
selectPredicate: pickerConfig.selectPredicate,
6463
shouldRevertGrid: pickerConfig.shouldRevertGrid,
6564
textDelegate: pickerConfig.textDelegate,

lib/src/widget/asset_picker_viewer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
88
import 'package:photo_manager/photo_manager.dart';
99

1010
import '../constants/enums.dart';
11-
import '../delegates/asset_picker_builder_delegate.dart';
11+
import '../constants/typedefs.dart';
1212
import '../delegates/asset_picker_viewer_builder_delegate.dart';
1313
import '../provider/asset_picker_provider.dart';
1414
import '../provider/asset_picker_viewer_provider.dart';

lib/wechat_assets_picker.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export 'package:photo_manager/photo_manager.dart';
55
export 'src/constants/config.dart';
66
export 'src/constants/constants.dart';
77
export 'src/constants/enums.dart';
8+
export 'src/constants/typedefs.dart';
89
export 'src/delegates/asset_picker_builder_delegate.dart';
910
export 'src/delegates/asset_picker_text_delegate.dart';
1011
export 'src/delegates/asset_picker_viewer_builder_delegate.dart';

0 commit comments

Comments
 (0)