@@ -87,11 +87,11 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
87
87
final ThemeData ? pickerTheme;
88
88
89
89
/// Allow users set a special item in the picker with several positions.
90
- /// 允许用户在选择器中添加一个自定义item ,并指定位置
90
+ /// 允许用户在选择器中添加一个自定义 item ,并指定位置
91
91
final SpecialItemPosition specialItemPosition;
92
92
93
93
/// The widget builder for the the special item.
94
- /// 自定义item的构造方法
94
+ /// 自定义 item 的构造方法
95
95
final SpecialItemBuilder <Path >? specialItemBuilder;
96
96
97
97
/// Indicates the loading status for the builder.
@@ -154,6 +154,12 @@ abstract class AssetPickerBuilderDelegate<Asset, Path> {
154
154
/// 选择器是否为单选模式
155
155
bool get isSingleAssetMode;
156
156
157
+ /// Whether the delegate should build the special item.
158
+ /// 是否需要构建自定义 item
159
+ bool get shouldBuildSpecialItem =>
160
+ specialItemPosition != SpecialItemPosition .none &&
161
+ specialItemBuilder != null ;
162
+
157
163
/// Space between assets item widget.
158
164
/// 资源部件之间的间隔
159
165
double get itemSpacing => 2 ;
@@ -931,15 +937,9 @@ class DefaultAssetPickerBuilderDelegate
931
937
return AssetPickerAppBarWrapper (
932
938
appBar: appBar (context),
933
939
body: Consumer <DefaultAssetPickerProvider >(
934
- builder: (BuildContext context, DefaultAssetPickerProvider p, __) {
935
- final Widget ? _specialItem = specialItemBuilder? .call (
936
- context,
937
- p.currentPath,
938
- p.currentAssets.length,
939
- );
940
- final bool shouldDisplayAssets = p.hasAssetsToDisplay ||
941
- (_specialItem != null &&
942
- specialItemPosition != SpecialItemPosition .none);
940
+ builder: (BuildContext context, DefaultAssetPickerProvider p, _) {
941
+ final bool shouldDisplayAssets =
942
+ p.hasAssetsToDisplay || shouldBuildSpecialItem;
943
943
return AnimatedSwitcher (
944
944
duration: switchingPathDuration,
945
945
child: shouldDisplayAssets
@@ -995,14 +995,8 @@ class DefaultAssetPickerBuilderDelegate
995
995
child: Consumer <DefaultAssetPickerProvider >(
996
996
builder: (_, DefaultAssetPickerProvider p, __) {
997
997
final Widget _child;
998
- final Widget ? _specialItem = specialItemBuilder? .call (
999
- context,
1000
- p.currentPath,
1001
- p.currentAssets.length,
1002
- );
1003
- final bool shouldDisplayAssets = p.hasAssetsToDisplay ||
1004
- (_specialItem != null &&
1005
- specialItemPosition != SpecialItemPosition .none);
998
+ final bool shouldDisplayAssets =
999
+ p.hasAssetsToDisplay || shouldBuildSpecialItem;
1006
1000
if (shouldDisplayAssets) {
1007
1001
_child = Stack (
1008
1002
children: < Widget > [
@@ -1042,13 +1036,26 @@ class DefaultAssetPickerBuilderDelegate
1042
1036
Widget assetsGridBuilder (BuildContext context) {
1043
1037
return Selector <DefaultAssetPickerProvider , AssetPathEntity ?>(
1044
1038
selector: (_, DefaultAssetPickerProvider p) => p.currentPath,
1045
- builder: (_ , AssetPathEntity ? path, __) {
1039
+ builder: (BuildContext context , AssetPathEntity ? path, __) {
1046
1040
// First, we need the count of the assets.
1047
1041
int totalCount = path? .assetCount ?? 0 ;
1042
+ final Widget ? _specialItem;
1048
1043
// If user chose a special item's position, add 1 count.
1049
- if (specialItemPosition != SpecialItemPosition .none &&
1050
- path? .isAll == true ) {
1051
- totalCount += 1 ;
1044
+ if (specialItemPosition != SpecialItemPosition .none) {
1045
+ _specialItem = specialItemBuilder? .call (
1046
+ context,
1047
+ path,
1048
+ totalCount,
1049
+ );
1050
+ if (_specialItem != null ) {
1051
+ totalCount += 1 ;
1052
+ }
1053
+ } else {
1054
+ _specialItem = null ;
1055
+ }
1056
+ if (totalCount == 0 && _specialItem == null ) {
1057
+ return loadingIndicatorBuilder? .call (context, true ) ??
1058
+ Center (child: emptyIndicator (context));
1052
1059
}
1053
1060
// Then we use the [totalCount] to calculate placeholders we need.
1054
1061
final int placeholderCount;
@@ -1068,11 +1075,11 @@ class DefaultAssetPickerBuilderDelegate
1068
1075
final double dividedSpacing = itemSpacing / gridCount;
1069
1076
final double topPadding = context.topPadding + kToolbarHeight;
1070
1077
1071
- Widget _sliverGrid (BuildContext ctx , List <AssetEntity > assets) {
1078
+ Widget _sliverGrid (BuildContext context , List <AssetEntity > assets) {
1072
1079
return SliverGrid (
1073
1080
delegate: SliverChildBuilderDelegate (
1074
1081
(_, int index) => Builder (
1075
- builder: (BuildContext c ) {
1082
+ builder: (BuildContext context ) {
1076
1083
if (effectiveShouldRevertGrid) {
1077
1084
if (index < placeholderCount) {
1078
1085
return const SizedBox .shrink ();
@@ -1082,15 +1089,21 @@ class DefaultAssetPickerBuilderDelegate
1082
1089
return MergeSemantics (
1083
1090
child: Directionality (
1084
1091
textDirection: Directionality .of (context),
1085
- child: assetGridItemBuilder (c, index, assets),
1092
+ child: assetGridItemBuilder (
1093
+ context,
1094
+ index,
1095
+ assets,
1096
+ specialItem: _specialItem,
1097
+ ),
1086
1098
),
1087
1099
);
1088
1100
},
1089
1101
),
1090
1102
childCount: assetsGridItemCount (
1091
- context: ctx ,
1103
+ context: context ,
1092
1104
assets: assets,
1093
1105
placeholderCount: placeholderCount,
1106
+ specialItem: _specialItem,
1094
1107
),
1095
1108
findChildIndexCallback: (Key ? key) {
1096
1109
if (key is ValueKey <String >) {
@@ -1181,17 +1194,13 @@ class DefaultAssetPickerBuilderDelegate
1181
1194
}
1182
1195
1183
1196
/// There are several conditions within this builder:
1184
- /// * Return [specialItemBuilder] while the current path is all and
1185
- /// [specialItemPosition] is not equal to [SpecialItemPosition.none].
1186
1197
/// * Return item builder according to the asset's type.
1187
1198
/// * [AssetType.audio] -> [audioItemBuilder]
1188
1199
/// * [AssetType.image], [AssetType.video] -> [imageAndVideoItemBuilder]
1189
1200
/// * Load more assets when the index reached at third line counting
1190
1201
/// backwards.
1191
1202
///
1192
1203
/// 资源构建有几个条件:
1193
- /// * 当前路径是全部资源且 [specialItemPosition] 不等于
1194
- /// [SpecialItemPosition.none] 时,将会通过 [specialItemBuilder] 构建内容。
1195
1204
/// * 根据资源类型返回对应类型的构建:
1196
1205
/// * [AssetType.audio] -> [audioItemBuilder] 音频类型
1197
1206
/// * [AssetType.image], [AssetType.video] -> [imageAndVideoItemBuilder]
@@ -1201,25 +1210,15 @@ class DefaultAssetPickerBuilderDelegate
1201
1210
Widget assetGridItemBuilder (
1202
1211
BuildContext context,
1203
1212
int index,
1204
- List <AssetEntity > currentAssets,
1205
- ) {
1213
+ List <AssetEntity > currentAssets, {
1214
+ Widget ? specialItem,
1215
+ }) {
1206
1216
final int _length = currentAssets.length;
1207
1217
final AssetPathEntity ? currentPathEntity =
1208
1218
context.select <DefaultAssetPickerProvider , AssetPathEntity ?>(
1209
1219
(DefaultAssetPickerProvider p) => p.currentPath,
1210
1220
);
1211
1221
1212
- final Widget ? specialItem;
1213
- if (specialItemPosition == SpecialItemPosition .none) {
1214
- specialItem = null ;
1215
- } else {
1216
- specialItem = specialItemBuilder? .call (
1217
- context,
1218
- currentPathEntity,
1219
- _length,
1220
- );
1221
- }
1222
-
1223
1222
if (specialItem != null ) {
1224
1223
if ((index == 0 && specialItemPosition == SpecialItemPosition .prepend) ||
1225
1224
(index == _length &&
@@ -1236,23 +1235,14 @@ class DefaultAssetPickerBuilderDelegate
1236
1235
currentIndex = index;
1237
1236
}
1238
1237
1239
- if (specialItemPosition != SpecialItemPosition .none) {
1240
- final Widget ? specialItem = specialItemBuilder? .call (
1241
- context,
1242
- currentPathEntity,
1243
- _length,
1244
- );
1245
- if (specialItem != null ) {}
1246
- }
1247
-
1248
1238
if (currentPathEntity == null ) {
1249
1239
return const SizedBox .shrink ();
1250
1240
}
1251
1241
1252
- if (index == _length - gridCount * 3 &&
1253
- context. select < DefaultAssetPickerProvider , bool >(
1254
- ( DefaultAssetPickerProvider p) => p.hasMoreToLoad,
1255
- ) ) {
1242
+ final bool hasMoreToLoad = context. select < DefaultAssetPickerProvider , bool >(
1243
+ ( DefaultAssetPickerProvider p) => p.hasMoreToLoad,
1244
+ );
1245
+ if (index == _length - gridCount * 3 && hasMoreToLoad ) {
1256
1246
context.read <DefaultAssetPickerProvider >().loadMoreAssets ();
1257
1247
}
1258
1248
@@ -1384,20 +1374,21 @@ class DefaultAssetPickerBuilderDelegate
1384
1374
required BuildContext context,
1385
1375
required List <AssetEntity > assets,
1386
1376
int placeholderCount = 0 ,
1377
+ Widget ? specialItem,
1387
1378
}) {
1388
1379
final AssetPathEntity ? currentPathEntity =
1389
1380
context.select <DefaultAssetPickerProvider , AssetPathEntity ?>(
1390
1381
(DefaultAssetPickerProvider p) => p.currentPath,
1391
1382
);
1383
+ final int _length = assets.length + placeholderCount;
1392
1384
1393
- if (currentPathEntity == null &&
1394
- specialItemPosition != SpecialItemPosition .none ) {
1395
- return 1 ;
1385
+ // Return 1 if the [specialItem] build something.
1386
+ if (currentPathEntity == null && specialItem != null ) {
1387
+ return placeholderCount + 1 ;
1396
1388
}
1397
1389
1398
- /// Return actual length if current path is all.
1399
- /// 如果当前目录是全部内容,则返回实际的内容数量。
1400
- final int _length = assets.length + placeholderCount;
1390
+ // Return actual length if the current path is all.
1391
+ // 如果当前目录是全部内容,则返回实际的内容数量。
1401
1392
if (currentPathEntity? .isAll != true ) {
1402
1393
return _length;
1403
1394
}
@@ -1550,18 +1541,22 @@ class DefaultAssetPickerBuilderDelegate
1550
1541
);
1551
1542
}
1552
1543
1544
+ Widget emptyIndicator (BuildContext context) {
1545
+ return ScaleText (
1546
+ textDelegate.emptyList,
1547
+ maxScaleFactor: 1.5 ,
1548
+ semanticsLabel: semanticsTextDelegate.emptyList,
1549
+ );
1550
+ }
1551
+
1553
1552
@override
1554
1553
Widget loadingIndicator (BuildContext context) {
1555
1554
return Center (
1556
1555
child: Selector <DefaultAssetPickerProvider , bool >(
1557
1556
selector: (_, DefaultAssetPickerProvider p) => p.isAssetsEmpty,
1558
- builder: (_ , bool isAssetsEmpty, __) {
1557
+ builder: (BuildContext context , bool isAssetsEmpty, __) {
1559
1558
if (isAssetsEmpty) {
1560
- return ScaleText (
1561
- textDelegate.emptyList,
1562
- maxScaleFactor: 1.5 ,
1563
- semanticsLabel: semanticsTextDelegate.emptyList,
1564
- );
1559
+ return emptyIndicator (context);
1565
1560
}
1566
1561
return PlatformProgressIndicator (
1567
1562
color: theme.iconTheme.color,
@@ -1725,6 +1720,9 @@ class DefaultAssetPickerBuilderDelegate
1725
1720
return UnconstrainedBox (
1726
1721
child: GestureDetector (
1727
1722
onTap: () {
1723
+ if (provider.currentPath == null ) {
1724
+ return ;
1725
+ }
1728
1726
Feedback .forTap (context);
1729
1727
if (isPermissionLimited && provider.isAssetsEmpty) {
1730
1728
PhotoManager .presentLimited ();
0 commit comments