123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- part of ct_assets_picker;
-
- class ExtendedAssetPickerBuilderDelegate extends DefaultAssetPickerBuilderDelegate {
- ExtendedAssetPickerBuilderDelegate({
- @required ExtendedAssetPickerProvider provider,
- int gridCount = 4,
- Color themeColor,
- AssetsPickerTextDelegate textDelegate,
- ThemeData pickerTheme,
- SpecialItemPosition specialItemPosition = SpecialItemPosition.none,
- WidgetBuilder specialItemBuilder,
- bool allowSpecialItemWhenEmpty = false,
- List<int> previewThumbSize,
- SpecialPickerType specialPickerType,
- }) : assert(
- provider != null,
- 'AssetPickerProvider must be provided and not null.',
- ),
- assert(
- pickerTheme == null || themeColor == null,
- 'Theme and theme color cannot be set at the same time.',
- ),
- super(
- provider: provider,
- gridCount: gridCount,
- themeColor: themeColor,
- textDelegate: textDelegate,
- pickerTheme: pickerTheme,
- specialItemPosition: specialItemPosition,
- specialItemBuilder: specialItemBuilder,
- allowSpecialItemWhenEmpty: allowSpecialItemWhenEmpty,
- previewThumbSize: previewThumbSize,
- specialPickerType: specialPickerType,
- );
-
- @override
- bool get isAppleOS => true;
-
- @override
- double get appleOSBlurRadius => 0;
-
- /// Action bar widget aligned to bottom.
- /// 底部操作栏部件
- @override
- Widget bottomActionBar(BuildContext context) {
- return !isSingleAssetMode ? Container(
- width: Screens.width,
- height: bottomActionBarHeight + Screens.bottomSafeHeight,
- padding: EdgeInsets.only(
- left: 20.0,
- right: 20.0,
- bottom: Screens.bottomSafeHeight,
- ),
- color: theme.colorScheme.surface,
- child: Row(children: <Widget>[
- previewButton(context),
- Expanded(
- child: fullImageButton(context),
- ),
- confirmButton(context),
- ]),
- ) : Container(
- width: Screens.width,
- height: Screens.bottomSafeHeight,
- );
- }
-
- Widget fullImageButton(BuildContext context) {
- return Selector<DefaultAssetPickerProvider, bool>(
- selector: (BuildContext _, DefaultAssetPickerProvider provider) =>
- (provider as ExtendedAssetPickerProvider).fullImage,
- builder: (BuildContext _, bool fullImage, Widget __) {
- return GestureDetector(
- onTap: () {
- (provider as ExtendedAssetPickerProvider).fullImage = !fullImage;
- },
- child: Row(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Container(
- // margin: EdgeInsets.all(Screens.width / gridCount / 15.0),
- width: 18,
- height: 18,
- alignment: Alignment.center,
- child: AnimatedContainer(
- duration: switchingPathDuration,
- width: 18,
- height: 18,
- decoration: BoxDecoration(
- border: Border.all(
- color: fullImage
- ? theme.colorScheme.primary
- : theme.unselectedWidgetColor,
- width: 2.0),
- color: null,
- shape: BoxShape.circle,
- ),
- child: AnimatedSwitcher(
- duration: switchingPathDuration,
- reverseDuration: switchingPathDuration,
- child: fullImage
- ? Container(
- width: 10,
- height: 10,
- decoration: BoxDecoration(
- color: theme.colorScheme.primary,
- shape: BoxShape.circle,
- ),
- )
- : const SizedBox.shrink(),
- ),
- ),
- ),
- SizedBox(
- width: 8,
- ),
- Text(
- Constants.textDelegate.original,
- style: TextStyle(
- color: theme.textTheme.caption.color,
- fontSize: 18.0,
- ),
- ),
- ],
- ),
- );
- },
- );
- }
-
- /// The main grid view builder for assets.
- /// 主要的资源查看网格部件
- @override
- Widget assetsGridBuilder(BuildContext context) {
- return ColoredBox(
- color: theme.colorScheme.background,
- child: Selector<AssetPickerProvider<AssetEntity, AssetPathEntity>,
- List<AssetEntity>>(
- selector: (BuildContext _,
- AssetPickerProvider<AssetEntity, AssetPathEntity> provider) =>
- provider.currentAssets,
- builder: (
- BuildContext _,
- List<AssetEntity> currentAssets,
- Widget __,
- ) {
- return GridView.builder(
- padding: isAppleOS
- ? EdgeInsets.only(
- top: Screens.topSafeHeight + kToolbarHeight,
- bottom: bottomActionBarHeight,
- )
- : EdgeInsets.zero,
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: gridCount,
- mainAxisSpacing: itemSpacing,
- crossAxisSpacing: itemSpacing,
- ),
- itemCount: assetsGridItemCount(_, currentAssets),
- itemBuilder: (BuildContext _, int index) {
- return assetGridItemBuilder(_, index, currentAssets);
- },
- );
- },
- ),
- );
- }
-
- /// It'll pop with [AssetPickerProvider.selectedAssets]
- /// when there're any assets chosen.
- /// 当有资源已选时,点击按钮将把已选资源通过路由返回。
- @override
- Widget confirmButton(BuildContext context) {
- return Consumer<DefaultAssetPickerProvider>(
- builder: (
- BuildContext _,
- DefaultAssetPickerProvider provider,
- Widget __,
- ) {
- return FlatButton(
- minWidth: provider.isSelectedNotEmpty ? 48.0 : 20.0,
- height: appBarItemHeight,
- padding: const EdgeInsets.symmetric(horizontal: 12.0),
- color: provider.isSelectedNotEmpty
- ? theme.colorScheme.primary
- : theme.dividerColor,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(3.0),
- ),
- child: Text(
- provider.isSelectedNotEmpty && !isSingleAssetMode
- ? '${Constants.textDelegate.confirm}'
- '(${provider.selectedAssets.length}/${provider.maxAssets})'
- : Constants.textDelegate.confirm,
- style: TextStyle(
- color: provider.isSelectedNotEmpty
- ? theme.colorScheme.onPrimary
- : theme.textTheme.caption.color,
- fontSize: 17.0,
- fontWeight: FontWeight.normal,
- ),
- ),
- onPressed: () {
- if (provider.isSelectedNotEmpty) {
- Navigator.of(context).pop(AssetPickerEntity(
- assets: provider.selectedAssets,
- isFullImage: (provider as ExtendedAssetPickerProvider).fullImage,
- ));
- }
- },
- materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
- );
- },
- );
- }
-
- @override
- Widget previewButton(BuildContext context) {
- return Selector<DefaultAssetPickerProvider, bool>(
- selector: (BuildContext _, DefaultAssetPickerProvider provider) =>
- provider.isSelectedNotEmpty,
- builder: (BuildContext _, bool isSelectedNotEmpty, Widget __) {
- return GestureDetector(
- onTap: isSelectedNotEmpty
- ? () async {
- final List<AssetEntity> result =
- await ExtendedAssetPickerViewer.pushToViewer(
- context,
- currentIndex: 0,
- previewAssets: provider.currentAssets,
- previewThumbSize: previewThumbSize,
- selectedAssets: provider.selectedAssets,
- selectorProvider: provider as ExtendedAssetPickerProvider,
- themeData: theme,
- );
- if (result != null) {
- Navigator.of(context).pop(AssetPickerEntity(
- assets: result,
- isFullImage: (provider as ExtendedAssetPickerProvider).fullImage,
- ));
- }
- }
- : null,
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: 12.0),
- child: Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
- selector: (BuildContext _, DefaultAssetPickerProvider provider) =>
- provider.selectedAssets,
- builder: (
- BuildContext _,
- List<AssetEntity> selectedAssets,
- Widget __,
- ) {
- return Text(
- isSelectedNotEmpty
- ? '${Constants.textDelegate.preview}'
- '(${provider.selectedAssets.length})'
- : Constants.textDelegate.preview,
- style: TextStyle(
- color: isSelectedNotEmpty
- ? null
- : theme.textTheme.caption.color,
- fontSize: 18.0,
- ),
- );
- },
- ),
- ),
- );
- },
- );
- }
-
- @override
- Widget selectIndicator(BuildContext context, AssetEntity asset) {
- if (isSingleAssetMode) {
- return Container();
- }
- return Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
- selector: (BuildContext _, DefaultAssetPickerProvider provider) =>
- provider.selectedAssets,
- builder: (BuildContext _, List<AssetEntity> selectedAssets, Widget __) {
- final bool selected = selectedAssets.contains(asset);
- final double indicatorSize = Screens.width / gridCount / 3;
- return Positioned(
- top: 0.0,
- right: 0.0,
- child: GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () {
- if (selected) {
- provider.unSelectAsset(asset);
- } else {
- if (isSingleAssetMode) {
- provider.selectedAssets.clear();
- }
- provider.selectAsset(asset);
- }
- },
- child: Container(
- margin: EdgeInsets.all(Screens.width / gridCount / 15.0),
- width: indicatorSize,
- height: indicatorSize,
- alignment: AlignmentDirectional.topEnd,
- child: AnimatedContainer(
- duration: switchingPathDuration,
- width: indicatorSize / 1.5,
- height: indicatorSize / 1.5,
- decoration: BoxDecoration(
- border: !selected
- ? Border.all(color: Colors.white, width: 2.0)
- : null,
- color: selected ? theme.colorScheme.primary : null,
- shape: BoxShape.circle,
- ),
- child: AnimatedSwitcher(
- duration: switchingPathDuration,
- reverseDuration: switchingPathDuration,
- child: selected
- ? isSingleAssetMode
- ? const Icon(Icons.check, size: 18.0)
- : Text(
- '${selectedAssets.indexOf(asset) + 1}',
- style: TextStyle(
- color: selected
- ? theme.colorScheme.onPrimary
- : null,
- fontSize: 14.0,
- fontWeight: isAppleOS
- ? FontWeight.w600
- : FontWeight.bold,
- ),
- )
- : const SizedBox.shrink(),
- ),
- ),
- ),
- ),
- );
- },
- );
- }
-
- @override
- Widget selectedBackdrop(BuildContext context, int index, AssetEntity asset) {
- return Selector<DefaultAssetPickerProvider, List<AssetEntity>>(
- selector: (BuildContext _, DefaultAssetPickerProvider provider) =>
- provider.selectedAssets,
- builder: (BuildContext _, List<AssetEntity> selectedAssets, Widget __) {
- final bool selected = selectedAssets.contains(asset);
- return Positioned.fill(
- child: GestureDetector(
- onTap: () async {
- if (isSingleAssetMode) {
- Navigator.of(context).pop(AssetPickerEntity(
- assets: [asset],
- isFullImage: (provider as ExtendedAssetPickerProvider).fullImage,
- ));
- return;
- }
- final List<AssetEntity> result =
- await ExtendedAssetPickerViewer.pushToViewer(
- context,
- currentIndex: index,
- previewAssets: provider.currentAssets,
- previewThumbSize: previewThumbSize,
- selectedAssets: provider.selectedAssets,
- selectorProvider: provider as ExtendedAssetPickerProvider,
- themeData: theme,
- );
- if (result != null) {
- Navigator.of(context).pop(AssetPickerEntity(
- assets: result,
- isFullImage: (provider as ExtendedAssetPickerProvider).fullImage,
- ));
- }
- },
- child: AnimatedContainer(
- duration: switchingPathDuration,
- color: selected
- ? Colors.black.withOpacity(0.45)
- : Colors.black.withOpacity(0.1),
- ),
- ), // 点击预览同目录下所有资源
- );
- },
- );
- }
-
- @override
- Widget pathEntityListWidget(BuildContext context) {
- final double appBarHeight = kToolbarHeight + Screens.topSafeHeight;
- final double maxHeight = Screens.height * 0.625;
- return Selector<DefaultAssetPickerProvider, bool>(
- selector: (
- BuildContext _,
- DefaultAssetPickerProvider provider,
- ) =>
- provider.isSwitchingPath,
- builder: (BuildContext _, bool isSwitchingPath, Widget __) {
- final pathHeight = provider.pathEntityList.length * 65.0;
- final double height = pathHeight > maxHeight ? maxHeight : pathHeight;
- return AnimatedPositioned(
- duration: switchingPathDuration,
- curve: switchingPathCurve,
- top: isAppleOS
- ? !isSwitchingPath
- ? -height
- : appBarHeight
- : -(!isSwitchingPath ? maxHeight : 1.0),
- child: AnimatedOpacity(
- duration: switchingPathDuration,
- curve: switchingPathCurve,
- opacity: !isAppleOS || isSwitchingPath ? 1.0 : 0.0,
- child: Container(
- width: Screens.width,
- height: height,
- decoration: BoxDecoration(
- borderRadius: isAppleOS
- ? const BorderRadius.only(
- bottomLeft: Radius.circular(10.0),
- bottomRight: Radius.circular(10.0),
- )
- : null,
- color: theme.colorScheme.surface,
- ),
- child: Selector<DefaultAssetPickerProvider,
- Map<AssetPathEntity, Uint8List>>(
- selector: (
- BuildContext _,
- DefaultAssetPickerProvider provider,
- ) =>
- provider.pathEntityList,
- builder: (
- BuildContext _,
- Map<AssetPathEntity, Uint8List> pathEntityList,
- Widget __,
- ) {
- return ListView.separated(
- padding: const EdgeInsets.only(top: 1.0),
- itemCount: pathEntityList.length,
- itemBuilder: (BuildContext _, int index) {
- return pathEntityWidget(
- context,
- pathEntityList.keys.elementAt(index),
- );
- },
- separatorBuilder: (BuildContext _, int __) => Container(
- margin: const EdgeInsets.only(left: 60.0),
- height: 1.0,
- color: theme.canvasColor,
- ),
- );
- },
- ),
- ),
- ),
- );
- },
- );
- }
-
- @override
- Widget pathEntityWidget(BuildContext context, AssetPathEntity path) {
- Widget builder(
- BuildContext context,
- Map<AssetPathEntity, Uint8List> pathEntityList,
- Widget __,
- ) {
- if (context.watch<DefaultAssetPickerProvider>().requestType ==
- RequestType.audio) {
- return ColoredBox(
- color: theme.colorScheme.primary.withOpacity(0.12),
- child: const Center(child: Icon(Icons.audiotrack)),
- );
- }
-
- /// The reason that the `thumbData` should be checked at here to see if it
- /// is null is that even the image file is not exist, the `File` can still
- /// returned as it exist, which will cause the thumb bytes return null.
- ///
- /// 此处需要检查缩略图为空的原因是:尽管文件可能已经被删除,但通过`File`读取的文件
- /// 对象 仍然存在,使得返回的数据为空。
- final Uint8List thumbData = pathEntityList[path];
- if (thumbData != null) {
- return Image.memory(
- pathEntityList[path],
- fit: BoxFit.cover,
- );
- } else {
- return ColoredBox(
- color: theme.colorScheme.primary.withOpacity(0.12),
- );
- }
- }
-
- return Material(
- type: MaterialType.transparency,
- child: InkWell(
- splashFactory: InkSplash.splashFactory,
- onTap: () => provider.switchPath(path),
- child: SizedBox(
- height: isAppleOS ? 64.0 : 52.0,
- child: Padding(
- padding: EdgeInsets.symmetric(horizontal: 16),
- child: Row(
- children: <Widget>[
- SizedBox(
- width: 50,
- height: 50,
- child: RepaintBoundary(
- child: AspectRatio(
- aspectRatio: 1.0,
- child: Selector<DefaultAssetPickerProvider,
- Map<AssetPathEntity, Uint8List>>(
- selector: (
- BuildContext _,
- DefaultAssetPickerProvider provider,
- ) =>
- provider.pathEntityList,
- builder: builder,
- ),
- ),
- ),
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(left: 15.0, right: 20.0),
- child: Row(
- children: <Widget>[
- Flexible(
- child: Padding(
- padding: const EdgeInsets.only(right: 10.0),
- child: Text(
- path.name ?? '',
- style: const TextStyle(fontSize: 16.0),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- ),
- ),
- Text(
- '(${path.assetCount})',
- style: TextStyle(
- color: theme.textTheme.caption.color,
- fontSize: 16.0,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- ],
- ),
- ),
- ),
- Selector<DefaultAssetPickerProvider, AssetPathEntity>(
- selector: (
- BuildContext _,
- DefaultAssetPickerProvider provider,
- ) =>
- provider.currentPathEntity,
- builder: (
- BuildContext _,
- AssetPathEntity currentPathEntity,
- Widget __,
- ) {
- if (currentPathEntity == path) {
- return Icon(ZefyrFont.multiselect_selected,
- color: theme.colorScheme.primary, size: 20.0);
- } else {
- return const SizedBox.shrink();
- }
- },
- ),
- ],
- ),
- ),
- ),
- ),
- );
- }
- }
|