Skip to content

Commit debd10f

Browse files
committed
itemBannedIndicator
1 parent f9702b6 commit debd10f

File tree

1 file changed

+153
-102
lines changed

1 file changed

+153
-102
lines changed

lib/src/delegates/asset_picker_builder_delegate.dart

Lines changed: 153 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,21 @@ abstract class AssetPickerBuilderDelegate<A, P> {
255255
/// 资源是否已选的指示器
256256
Widget selectIndicator(BuildContext context, A asset);
257257

258+
/// Indicator when the asset cannot be selected.
259+
/// 当资源无法被选中时的遮罩
260+
Widget itemBannedIndicator(BuildContext context, A asset) {
261+
return Consumer<AssetPickerProvider<A, P>>(
262+
builder: (_, AssetPickerProvider<A, P> p, __) {
263+
if (!p.selectedAssets.contains(asset) && p.selectedMaximumAssets) {
264+
return Container(
265+
color: theme.colorScheme.background.withOpacity(.85),
266+
);
267+
}
268+
return const SizedBox.shrink();
269+
},
270+
);
271+
}
272+
258273
/// Loading indicator.
259274
/// 加载指示器
260275
Widget loadingIndicator(BuildContext context) {
@@ -652,7 +667,7 @@ class DefaultAssetPickerBuilderDelegate
652667

653668
/// [Duration] when triggering path switching.
654669
/// 切换路径时的动画时长
655-
Duration get switchingPathDuration => kThemeAnimationDuration * 1.5;
670+
Duration get switchingPathDuration => kThemeAnimationDuration;
656671

657672
/// [Curve] when triggering path switching.
658673
/// 切换路径时的动画曲线
@@ -971,6 +986,7 @@ class DefaultAssetPickerBuilderDelegate
971986
builder,
972987
if (!isWeChatMoment || asset.type != AssetType.video)
973988
selectIndicator(context, asset),
989+
itemBannedIndicator(context, asset),
974990
],
975991
);
976992
}
@@ -1199,98 +1215,104 @@ class DefaultAssetPickerBuilderDelegate
11991215
return Positioned.fill(
12001216
top: isAppleOS ? context.topPadding + kToolbarHeight : 0,
12011217
bottom: null,
1202-
child: Selector<DefaultAssetPickerProvider, bool>(
1203-
selector: (_, DefaultAssetPickerProvider p) => p.isSwitchingPath,
1204-
builder: (_, bool isSwitchingPath, Widget? w) => AnimatedAlign(
1205-
duration: switchingPathDuration,
1206-
curve: switchingPathCurve,
1207-
alignment: Alignment.bottomCenter,
1208-
heightFactor: isSwitchingPath ? 1 : 0,
1209-
child: AnimatedOpacity(
1218+
child: ClipRRect(
1219+
borderRadius: const BorderRadius.vertical(
1220+
bottom: Radius.circular(10.0),
1221+
),
1222+
child: Selector<DefaultAssetPickerProvider, bool>(
1223+
selector: (_, DefaultAssetPickerProvider p) => p.isSwitchingPath,
1224+
builder: (_, bool isSwitchingPath, Widget? w) => AnimatedAlign(
12101225
duration: switchingPathDuration,
12111226
curve: switchingPathCurve,
1212-
opacity: !isAppleOS || isSwitchingPath ? 1.0 : 0.0,
1213-
child: Container(
1214-
height: context.mediaQuery.size.height * (isAppleOS ? .6 : .8),
1215-
decoration: BoxDecoration(
1216-
borderRadius: isAppleOS
1217-
? const BorderRadius.vertical(bottom: Radius.circular(10.0))
1218-
: null,
1227+
alignment: Alignment.bottomCenter,
1228+
heightFactor: isSwitchingPath ? 1 : 0,
1229+
child: AnimatedOpacity(
1230+
duration: switchingPathDuration,
1231+
curve: switchingPathCurve,
1232+
opacity: !isAppleOS || isSwitchingPath ? 1.0 : 0.0,
1233+
child: Container(
1234+
constraints: BoxConstraints(
1235+
maxHeight:
1236+
context.mediaQuery.size.height * (isAppleOS ? .6 : .8),
1237+
),
12191238
color: theme.colorScheme.background,
1239+
child: w,
12201240
),
1221-
child: w,
12221241
),
12231242
),
1224-
),
1225-
child: Column(
1226-
children: <Widget>[
1227-
ValueListenableBuilder<PermissionState>(
1228-
valueListenable: permission,
1229-
builder: (_, PermissionState ps, Widget? child) {
1230-
if (isPermissionLimited) {
1231-
return child!;
1232-
}
1233-
return const SizedBox.shrink();
1234-
},
1235-
child: Padding(
1236-
padding: const EdgeInsets.symmetric(
1237-
horizontal: 20,
1238-
vertical: 12,
1239-
),
1240-
child: Text.rich(
1241-
TextSpan(
1242-
children: <TextSpan>[
1243-
TextSpan(
1244-
text: Constants.textDelegate.viewingLimitedAssetsTip,
1245-
),
1246-
TextSpan(
1247-
text: ' '
1248-
'${Constants.textDelegate.changeAccessibleLimitedAssets}',
1249-
style: TextStyle(color: interactiveTextColor(context)),
1250-
recognizer: TapGestureRecognizer()
1251-
..onTap = PhotoManager.presentLimited,
1252-
),
1253-
],
1243+
child: Column(
1244+
mainAxisSize: MainAxisSize.min,
1245+
children: <Widget>[
1246+
ValueListenableBuilder<PermissionState>(
1247+
valueListenable: permission,
1248+
builder: (_, PermissionState ps, Widget? child) {
1249+
if (isPermissionLimited) {
1250+
return child!;
1251+
}
1252+
return const SizedBox.shrink();
1253+
},
1254+
child: Padding(
1255+
padding: const EdgeInsets.symmetric(
1256+
horizontal: 20,
1257+
vertical: 12,
12541258
),
1255-
style: context.themeData.textTheme.caption?.copyWith(
1256-
fontSize: 15,
1259+
child: Text.rich(
1260+
TextSpan(
1261+
children: <TextSpan>[
1262+
TextSpan(
1263+
text: Constants.textDelegate.viewingLimitedAssetsTip,
1264+
),
1265+
TextSpan(
1266+
text: ' '
1267+
'${Constants.textDelegate.changeAccessibleLimitedAssets}',
1268+
style:
1269+
TextStyle(color: interactiveTextColor(context)),
1270+
recognizer: TapGestureRecognizer()
1271+
..onTap = PhotoManager.presentLimited,
1272+
),
1273+
],
1274+
),
1275+
style: context.themeData.textTheme.caption?.copyWith(
1276+
fontSize: 15,
1277+
),
12571278
),
12581279
),
12591280
),
1260-
),
1261-
Expanded(
1262-
child: Selector<DefaultAssetPickerProvider, int>(
1263-
selector: (_, DefaultAssetPickerProvider p) =>
1264-
p.validPathThumbCount,
1265-
builder: (_, int count, __) => Selector<
1266-
DefaultAssetPickerProvider,
1267-
Map<AssetPathEntity, Uint8List?>>(
1281+
Flexible(
1282+
child: Selector<DefaultAssetPickerProvider, int>(
12681283
selector: (_, DefaultAssetPickerProvider p) =>
1269-
p.pathEntityList,
1270-
builder: (_, Map<AssetPathEntity, Uint8List?> list, __) {
1271-
return ListView.separated(
1272-
padding: const EdgeInsetsDirectional.only(top: 1.0),
1273-
itemCount: list.length,
1274-
itemBuilder: (BuildContext c, int index) =>
1275-
pathEntityWidget(
1276-
context: c,
1277-
list: list,
1278-
index: index,
1279-
isAudio: (provider as DefaultAssetPickerProvider)
1280-
.requestType ==
1281-
RequestType.audio,
1282-
),
1283-
separatorBuilder: (_, __) => Container(
1284-
margin: const EdgeInsetsDirectional.only(start: 60.0),
1285-
height: 1.0,
1286-
color: theme.canvasColor,
1287-
),
1288-
);
1289-
},
1284+
p.validPathThumbCount,
1285+
builder: (_, int count, __) => Selector<
1286+
DefaultAssetPickerProvider,
1287+
Map<AssetPathEntity, Uint8List?>>(
1288+
selector: (_, DefaultAssetPickerProvider p) =>
1289+
p.pathEntityList,
1290+
builder: (_, Map<AssetPathEntity, Uint8List?> list, __) {
1291+
return ListView.separated(
1292+
padding: const EdgeInsetsDirectional.only(top: 1.0),
1293+
shrinkWrap: true,
1294+
itemCount: list.length,
1295+
itemBuilder: (BuildContext c, int i) =>
1296+
pathEntityWidget(
1297+
context: c,
1298+
list: list,
1299+
index: i,
1300+
isAudio: (provider as DefaultAssetPickerProvider)
1301+
.requestType ==
1302+
RequestType.audio,
1303+
),
1304+
separatorBuilder: (_, __) => Container(
1305+
margin: const EdgeInsetsDirectional.only(start: 60.0),
1306+
height: 1.0,
1307+
color: theme.canvasColor,
1308+
),
1309+
);
1310+
},
1311+
),
12901312
),
12911313
),
1292-
),
1293-
],
1314+
],
1315+
),
12941316
),
12951317
),
12961318
);
@@ -1519,8 +1541,26 @@ class DefaultAssetPickerBuilderDelegate
15191541
);
15201542
}
15211543

1544+
@override
1545+
Widget itemBannedIndicator(BuildContext context, AssetEntity asset) {
1546+
return Consumer<DefaultAssetPickerProvider>(
1547+
builder: (_, DefaultAssetPickerProvider p, __) {
1548+
if ((!p.selectedAssets.contains(asset) && p.selectedMaximumAssets) ||
1549+
(isWeChatMoment &&
1550+
asset.type == AssetType.video &&
1551+
p.selectedAssets.isNotEmpty)) {
1552+
return Container(
1553+
color: theme.colorScheme.background.withOpacity(.85),
1554+
);
1555+
}
1556+
return const SizedBox.shrink();
1557+
},
1558+
);
1559+
}
1560+
15221561
@override
15231562
Widget selectIndicator(BuildContext context, AssetEntity asset) {
1563+
final Duration duration = switchingPathDuration * 0.75;
15241564
return Selector<DefaultAssetPickerProvider, String>(
15251565
selector: (_, DefaultAssetPickerProvider p) => p.selectedDescriptions,
15261566
builder: (BuildContext context, _, __) {
@@ -1532,7 +1572,7 @@ class DefaultAssetPickerBuilderDelegate
15321572
final double indicatorSize =
15331573
context.mediaQuery.size.width / gridCount / 3;
15341574
final Widget innerSelector = AnimatedContainer(
1535-
duration: switchingPathDuration,
1575+
duration: duration,
15361576
width: indicatorSize / (isAppleOS ? 1.25 : 1.5),
15371577
height: indicatorSize / (isAppleOS ? 1.25 : 1.5),
15381578
decoration: BoxDecoration(
@@ -1542,22 +1582,10 @@ class DefaultAssetPickerBuilderDelegate
15421582
shape: BoxShape.circle,
15431583
),
15441584
child: AnimatedSwitcher(
1545-
duration: switchingPathDuration,
1546-
reverseDuration: switchingPathDuration,
1585+
duration: duration,
1586+
reverseDuration: duration,
15471587
child: selected
1548-
? isSingleAssetMode
1549-
? const Icon(Icons.check, size: 18.0)
1550-
: Text(
1551-
'${selectedAssets.indexOf(asset) + 1}',
1552-
style: TextStyle(
1553-
color: selected
1554-
? theme.textTheme.bodyText1?.color
1555-
: null,
1556-
fontSize: isAppleOS ? 16.0 : 14.0,
1557-
fontWeight:
1558-
isAppleOS ? FontWeight.w600 : FontWeight.bold,
1559-
),
1560-
)
1588+
? const Icon(Icons.check, size: 18.0)
15611589
: const SizedBox.shrink(),
15621590
),
15631591
);
@@ -1602,15 +1630,23 @@ class DefaultAssetPickerBuilderDelegate
16021630

16031631
@override
16041632
Widget selectedBackdrop(BuildContext context, int index, AssetEntity asset) {
1633+
bool selectedAllAndNotSelected() =>
1634+
!provider.selectedAssets.contains(asset) &&
1635+
provider.selectedMaximumAssets;
1636+
bool selectedPhotosAndIsVideo() =>
1637+
isWeChatMoment &&
1638+
asset.type == AssetType.video &&
1639+
provider.selectedAssets.isNotEmpty;
1640+
16051641
return Positioned.fill(
16061642
child: GestureDetector(
16071643
onTap: () async {
1644+
// When we reached the maximum select count and the asset
1645+
// is not selected, do nothing.
16081646
// When the special type is WeChat Moment, pictures and videos cannot
16091647
// be selected at the same time. Video select should be banned if any
16101648
// pictures are selected.
1611-
if (isWeChatMoment &&
1612-
asset.type == AssetType.video &&
1613-
provider.selectedAssets.isNotEmpty) {
1649+
if (selectedAllAndNotSelected() || selectedPhotosAndIsVideo()) {
16141650
return;
16151651
}
16161652
final List<AssetEntity> _current;
@@ -1652,12 +1688,27 @@ class DefaultAssetPickerBuilderDelegate
16521688
child: Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
16531689
selector: (_, DefaultAssetPickerProvider p) => p.selectedAssets,
16541690
builder: (_, List<AssetEntity> selectedAssets, __) {
1655-
final bool selected = selectedAssets.contains(asset);
1691+
final int index = selectedAssets.indexOf(asset);
1692+
final bool selected = index != -1;
16561693
return AnimatedContainer(
16571694
duration: switchingPathDuration,
16581695
color: selected
1659-
? theme.colorScheme.primary.withOpacity(0.45)
1660-
: Colors.black.withOpacity(0.1),
1696+
? theme.colorScheme.primary.withOpacity(.45)
1697+
: Colors.black.withOpacity(.1),
1698+
child: selected && !isSingleAssetMode
1699+
? Container(
1700+
alignment: AlignmentDirectional.topStart,
1701+
padding: const EdgeInsets.all(14),
1702+
child: Text(
1703+
'${index + 1}',
1704+
style: TextStyle(
1705+
color: theme.textTheme.bodyText1?.color
1706+
?.withOpacity(.75),
1707+
fontWeight: FontWeight.w600,
1708+
),
1709+
),
1710+
)
1711+
: const SizedBox.shrink(),
16611712
);
16621713
},
16631714
),

0 commit comments

Comments
 (0)