From 130189a9fde7a2182bff1e87bbea2c6c018f0eab Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sat, 9 Nov 2024 17:28:02 +0800 Subject: [PATCH 01/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/lib/constants/picker_method.dart | 1 + lib/src/constants/config.dart | 5 + .../asset_picker_builder_delegate.dart | 46 +++++- lib/src/delegates/asset_picker_delegate.dart | 1 + lib/src/provider/asset_picker_provider.dart | 149 ++++++++++++++++++ 5 files changed, 196 insertions(+), 6 deletions(-) diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index 00857410..d43f64ab 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -36,6 +36,7 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, + enableDragAndSelect: true, ), ); }, diff --git a/lib/src/constants/config.dart b/lib/src/constants/config.dart index 939f5fa8..46befbec 100644 --- a/lib/src/constants/config.dart +++ b/lib/src/constants/config.dart @@ -39,6 +39,7 @@ class AssetPickerConfig { this.assetsChangeCallback, this.assetsChangeRefreshPredicate, this.shouldAutoplayPreview = false, + this.enableDragAndSelect = true, }) : assert( pickerTheme == null || themeColor == null, 'pickerTheme and themeColor cannot be set at the same time.', @@ -205,4 +206,8 @@ class AssetPickerConfig { /// Whether the preview should auto play. /// 预览是否自动播放 final bool shouldAutoplayPreview; + + /// Should enable drag and select function. + /// 是否开启拖拽选择 + final bool enableDragAndSelect; } diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index aa85ec03..49e6c689 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -47,6 +47,7 @@ abstract class AssetPickerBuilderDelegate { this.pathNameBuilder, this.assetsChangeCallback, this.assetsChangeRefreshPredicate, + this.enableDragAndSelect = true, Color? themeColor, AssetPickerTextDelegate? textDelegate, Locale? locale, @@ -130,6 +131,10 @@ abstract class AssetPickerBuilderDelegate { final AssetsChangeRefreshPredicate? assetsChangeRefreshPredicate; + /// Should enable drag and select function. + /// 是否开启拖拽选择 + final bool enableDragAndSelect; + /// [ThemeData] for the picker. /// 选择器使用的主题 ThemeData get theme => pickerTheme ?? AssetPicker.themeData(themeColor); @@ -755,6 +760,7 @@ class DefaultAssetPickerBuilderDelegate super.themeColor, super.textDelegate, super.locale, + super.enableDragAndSelect, this.gridThumbnailSize = defaultAssetGridPreviewSize, this.previewThumbnailSize, this.specialPickerType, @@ -1268,6 +1274,10 @@ class DefaultAssetPickerBuilderDelegate context.topPadding + appBarPreferredSize!.height; final textDirection = Directionality.of(context); + final provider = Provider.of(context); + final double screenWidth = MediaQuery.sizeOf(context).width; + final double itemSize = screenWidth / gridCount; + Widget sliverGrid(BuildContext context, List assets) { return SliverGrid( delegate: SliverChildBuilderDelegate( @@ -1278,15 +1288,39 @@ class DefaultAssetPickerBuilderDelegate } index -= placeholderCount; } - return MergeSemantics( - child: Directionality( - textDirection: textDirection, - child: assetGridItemBuilder( + + Widget child = assetGridItemBuilder( + context, + index, + assets, + specialItem: specialItem, + ); + + if (enableDragAndSelect) { + child = GestureDetector( + onLongPressStart: (d) => provider.onDragStart( context, + d, index, - assets, - specialItem: specialItem, + assets[index], ), + onLongPressMoveUpdate: (d) => provider.onDragUpdate( + context, + d, + itemSize, + gridCount, + topPadding, + ), + onLongPressCancel: provider.resetDraggingStatus, + onLongPressEnd: provider.onDragEnd, + child: child, + ); + } + + return MergeSemantics( + child: Directionality( + textDirection: textDirection, + child: child, ), ); }, diff --git a/lib/src/delegates/asset_picker_delegate.dart b/lib/src/delegates/asset_picker_delegate.dart index 3f788b3d..e57b434c 100644 --- a/lib/src/delegates/asset_picker_delegate.dart +++ b/lib/src/delegates/asset_picker_delegate.dart @@ -119,6 +119,7 @@ class AssetPickerDelegate { themeColor: pickerConfig.themeColor, locale: Localizations.maybeLocaleOf(context), shouldAutoplayPreview: pickerConfig.shouldAutoplayPreview, + enableDragAndSelect: pickerConfig.enableDragAndSelect, ), ); final List? result = await Navigator.maybeOf( diff --git a/lib/src/provider/asset_picker_provider.dart b/lib/src/provider/asset_picker_provider.dart index 4938fe15..ace37f1f 100644 --- a/lib/src/provider/asset_picker_provider.dart +++ b/lib/src/provider/asset_picker_provider.dart @@ -254,6 +254,155 @@ abstract class AssetPickerProvider extends ChangeNotifier { set.remove(item); selectedAssets = set; } + + /// 拖拽状态 + /// Drag status + bool isInDragging = false; + + /// 边缘自动滚动控制器 + /// Edge Auto Scrolling Detector. Use to support edge auto scroll when drag position reach the edge of device's screen. + EdgeDraggingAutoScroller? _autoScroller; + + // An eyeballed value for a smooth scrolling experience. + static const double _kDefaultAutoScrollVelocityScalar = 50; + + /// 起始选择序号 + /// Item index of the first selected item + int initialSelectedIdx = -1; + + /// 拖拽选择 或 拖拽取消选择 + /// Drag to select or deselect state + bool dragSelect = true; + + /// 长按启动拖拽 + /// Long Press to enable drag and select + void onDragStart( + BuildContext context, + LongPressStartDetails details, + int index, + Asset entity, + ) { + isInDragging = true; + + final scrollableState = _checkScrollableStatePresent(context); + if (scrollableState == null) { + return; + } + + _autoScroller = EdgeDraggingAutoScroller( + scrollableState, + velocityScalar: _kDefaultAutoScrollVelocityScalar, + ); + + initialSelectedIdx = index; + + dragSelect = !selectedAssets.contains(entity); + } + + void onDragUpdate( + BuildContext context, + LongPressMoveUpdateDetails details, + double itemSize, + int gridCount, + double topPadding, + ) { + if (!isInDragging) { + return; + } + + if (dragSelect && selectedAssets.length == maxAssets) { + return; + } + + final scrollableState = _checkScrollableStatePresent(context); + if (scrollableState == null) { + return; + } + + final column = _getIndex(details.globalPosition.dx, itemSize); + final row = _getIndex( + details.globalPosition.dy - + topPadding - + 24.0 + + scrollableState.position.pixels, + itemSize, + ); + + final currentDragIndex = row * gridCount + column; + + List filteredAssetList = []; + // add asset + if (currentDragIndex < initialSelectedIdx) { + filteredAssetList = _currentAssets + .getRange( + currentDragIndex, + math.min(initialSelectedIdx + 1, currentAssets.length), + ) + .toList() + ..reversed; + } else { + filteredAssetList = _currentAssets + .getRange( + initialSelectedIdx, + math.min(currentDragIndex + 1, currentAssets.length), + ) + .toList(); + } + + filteredAssetList.forEach(dragSelect ? selectAsset : unSelectAsset); + + _autoScroller?.startAutoScrollIfNecessary( + Rect.fromLTWH( + (column + 1) * itemSize, + details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 + ? (row + 1) * itemSize + : math.max(topPadding, details.globalPosition.dy), + itemSize, + itemSize, + ), + ); + } + + void onDragEnd(LongPressEndDetails details) { + resetDraggingStatus(); + } + + /// 复原拖拽状态 + /// Reset dragging status + void resetDraggingStatus() { + isInDragging = false; + initialSelectedIdx = -1; + dragSelect = true; + _autoScroller?.stopAutoScroll(); + _autoScroller = null; + } + + /// 检查[Scrollable] state是否存在 + /// + ScrollableState? _checkScrollableStatePresent(BuildContext context) { + final scrollable = Scrollable.maybeOf(context); + assert( + scrollable != null, + 'To use drag and select function, Scrollable state must be the present to get the actual item position.', + ); + assert( + scrollable?.position.axis == Axis.vertical, + 'To use drag and select function. The Scrollable Axis must be in vertical direction', + ); + + if (scrollable == null || scrollable.position.axis != Axis.vertical) { + resetDraggingStatus(); + return null; + } + + return scrollable; + } + + /// 获取坐标 + /// Get Coordinate Helper + int _getIndex(double delta, double itemSize) { + return delta ~/ itemSize; + } } /// The default implementation of the [AssetPickerProvider] for the picker. From a1e594d9ff7df4774faee52d0e7d693f440ada13 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sun, 17 Nov 2024 20:50:11 +0800 Subject: [PATCH 02/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asset_picker_builder_delegate.dart | 162 +++++++++++++++++- lib/src/provider/asset_picker_provider.dart | 149 ---------------- 2 files changed, 157 insertions(+), 154 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 49e6c689..13e12a31 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:math' as math; import 'dart:ui' as ui; +import 'dart:ui'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -1228,6 +1229,158 @@ class DefaultAssetPickerBuilderDelegate ); } + /// 拖拽状态 + /// Drag status + bool isInDragging = false; + + /// 边缘自动滚动控制器 + /// Edge Auto Scrolling Detector. Use to support edge auto scroll when drag position reach the edge of device's screen. + EdgeDraggingAutoScroller? _autoScroller; + + // An eyeballed value for a smooth scrolling experience. + static const double _kDefaultAutoScrollVelocityScalar = 50; + + /// 起始选择序号 + /// Item index of the first selected item + int initialSelectedIdx = -1; + + /// 拖拽选择 或 拖拽取消选择 + /// Drag to select or deselect state + bool dragSelect = true; + + /// 长按启动拖拽 + /// Long Press to enable drag and select + void onDragStart( + BuildContext context, + LongPressStartDetails details, + int index, + AssetEntity entity, + ) { + isInDragging = true; + + final scrollableState = _checkScrollableStatePresent(context); + if (scrollableState == null) { + return; + } + + _autoScroller = EdgeDraggingAutoScroller( + scrollableState, + velocityScalar: _kDefaultAutoScrollVelocityScalar, + ); + + initialSelectedIdx = index; + + dragSelect = !provider.selectedAssets.contains(entity); + } + + void onDragUpdate( + BuildContext context, + LongPressMoveUpdateDetails details, + double itemSize, + int gridCount, + double topPadding, + ) { + if (!isInDragging) { + return; + } + + if (dragSelect && provider.selectedAssets.length == provider.maxAssets) { + return; + } + + final scrollableState = _checkScrollableStatePresent(context); + if (scrollableState == null) { + return; + } + + final column = _getDragPositionIndex(details.globalPosition.dx, itemSize); + final row = _getDragPositionIndex( + details.globalPosition.dy - + topPadding - + (View.of(context).viewPadding.top / + View.of(context).devicePixelRatio) + + scrollableState.position.pixels, + itemSize, + ); + + final currentDragIndex = row * gridCount + column; + + List filteredAssetList = []; + // add asset + if (currentDragIndex < initialSelectedIdx) { + filteredAssetList = provider.currentAssets + .getRange( + currentDragIndex, + math.min(initialSelectedIdx + 1, provider.currentAssets.length), + ) + .toList() + ..reversed; + } else { + filteredAssetList = provider.currentAssets + .getRange( + initialSelectedIdx, + math.min(currentDragIndex + 1, provider.currentAssets.length), + ) + .toList(); + } + + filteredAssetList.forEach( + dragSelect ? provider.selectAsset : provider.unSelectAsset, + ); + + _autoScroller?.startAutoScrollIfNecessary( + Rect.fromLTWH( + (column + 1) * itemSize, + details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 + ? (row + 1) * itemSize + : math.max(topPadding, details.globalPosition.dy), + itemSize, + itemSize, + ), + ); + } + + void onDragEnd(LongPressEndDetails details) { + resetDraggingStatus(); + } + + /// 复原拖拽状态 + /// Reset dragging status + void resetDraggingStatus() { + isInDragging = false; + initialSelectedIdx = -1; + dragSelect = true; + _autoScroller?.stopAutoScroll(); + _autoScroller = null; + } + + /// 检查[Scrollable] state是否存在 + /// + ScrollableState? _checkScrollableStatePresent(BuildContext context) { + final scrollable = Scrollable.maybeOf(context); + assert( + scrollable != null, + 'To use drag and select function, Scrollable state must be the present to get the actual item position.', + ); + assert( + scrollable?.position.axis == Axis.vertical, + 'To use drag and select function. The Scrollable Axis must be in vertical direction', + ); + + if (scrollable == null || scrollable.position.axis != Axis.vertical) { + resetDraggingStatus(); + return null; + } + + return scrollable; + } + + /// 获取坐标 + /// Get Coordinate Helper + int _getDragPositionIndex(double delta, double itemSize) { + return delta ~/ itemSize; + } + @override Widget assetsGridBuilder(BuildContext context) { appBarPreferredSize ??= appBar(context).preferredSize; @@ -1274,7 +1427,6 @@ class DefaultAssetPickerBuilderDelegate context.topPadding + appBarPreferredSize!.height; final textDirection = Directionality.of(context); - final provider = Provider.of(context); final double screenWidth = MediaQuery.sizeOf(context).width; final double itemSize = screenWidth / gridCount; @@ -1298,21 +1450,21 @@ class DefaultAssetPickerBuilderDelegate if (enableDragAndSelect) { child = GestureDetector( - onLongPressStart: (d) => provider.onDragStart( + onLongPressStart: (d) => onDragStart( context, d, index, assets[index], ), - onLongPressMoveUpdate: (d) => provider.onDragUpdate( + onLongPressMoveUpdate: (d) => onDragUpdate( context, d, itemSize, gridCount, topPadding, ), - onLongPressCancel: provider.resetDraggingStatus, - onLongPressEnd: provider.onDragEnd, + onLongPressCancel: resetDraggingStatus, + onLongPressEnd: onDragEnd, child: child, ); } diff --git a/lib/src/provider/asset_picker_provider.dart b/lib/src/provider/asset_picker_provider.dart index ace37f1f..4938fe15 100644 --- a/lib/src/provider/asset_picker_provider.dart +++ b/lib/src/provider/asset_picker_provider.dart @@ -254,155 +254,6 @@ abstract class AssetPickerProvider extends ChangeNotifier { set.remove(item); selectedAssets = set; } - - /// 拖拽状态 - /// Drag status - bool isInDragging = false; - - /// 边缘自动滚动控制器 - /// Edge Auto Scrolling Detector. Use to support edge auto scroll when drag position reach the edge of device's screen. - EdgeDraggingAutoScroller? _autoScroller; - - // An eyeballed value for a smooth scrolling experience. - static const double _kDefaultAutoScrollVelocityScalar = 50; - - /// 起始选择序号 - /// Item index of the first selected item - int initialSelectedIdx = -1; - - /// 拖拽选择 或 拖拽取消选择 - /// Drag to select or deselect state - bool dragSelect = true; - - /// 长按启动拖拽 - /// Long Press to enable drag and select - void onDragStart( - BuildContext context, - LongPressStartDetails details, - int index, - Asset entity, - ) { - isInDragging = true; - - final scrollableState = _checkScrollableStatePresent(context); - if (scrollableState == null) { - return; - } - - _autoScroller = EdgeDraggingAutoScroller( - scrollableState, - velocityScalar: _kDefaultAutoScrollVelocityScalar, - ); - - initialSelectedIdx = index; - - dragSelect = !selectedAssets.contains(entity); - } - - void onDragUpdate( - BuildContext context, - LongPressMoveUpdateDetails details, - double itemSize, - int gridCount, - double topPadding, - ) { - if (!isInDragging) { - return; - } - - if (dragSelect && selectedAssets.length == maxAssets) { - return; - } - - final scrollableState = _checkScrollableStatePresent(context); - if (scrollableState == null) { - return; - } - - final column = _getIndex(details.globalPosition.dx, itemSize); - final row = _getIndex( - details.globalPosition.dy - - topPadding - - 24.0 + - scrollableState.position.pixels, - itemSize, - ); - - final currentDragIndex = row * gridCount + column; - - List filteredAssetList = []; - // add asset - if (currentDragIndex < initialSelectedIdx) { - filteredAssetList = _currentAssets - .getRange( - currentDragIndex, - math.min(initialSelectedIdx + 1, currentAssets.length), - ) - .toList() - ..reversed; - } else { - filteredAssetList = _currentAssets - .getRange( - initialSelectedIdx, - math.min(currentDragIndex + 1, currentAssets.length), - ) - .toList(); - } - - filteredAssetList.forEach(dragSelect ? selectAsset : unSelectAsset); - - _autoScroller?.startAutoScrollIfNecessary( - Rect.fromLTWH( - (column + 1) * itemSize, - details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 - ? (row + 1) * itemSize - : math.max(topPadding, details.globalPosition.dy), - itemSize, - itemSize, - ), - ); - } - - void onDragEnd(LongPressEndDetails details) { - resetDraggingStatus(); - } - - /// 复原拖拽状态 - /// Reset dragging status - void resetDraggingStatus() { - isInDragging = false; - initialSelectedIdx = -1; - dragSelect = true; - _autoScroller?.stopAutoScroll(); - _autoScroller = null; - } - - /// 检查[Scrollable] state是否存在 - /// - ScrollableState? _checkScrollableStatePresent(BuildContext context) { - final scrollable = Scrollable.maybeOf(context); - assert( - scrollable != null, - 'To use drag and select function, Scrollable state must be the present to get the actual item position.', - ); - assert( - scrollable?.position.axis == Axis.vertical, - 'To use drag and select function. The Scrollable Axis must be in vertical direction', - ); - - if (scrollable == null || scrollable.position.axis != Axis.vertical) { - resetDraggingStatus(); - return null; - } - - return scrollable; - } - - /// 获取坐标 - /// Get Coordinate Helper - int _getIndex(double delta, double itemSize) { - return delta ~/ itemSize; - } } /// The default implementation of the [AssetPickerProvider] for the picker. From aa6f46ed7727b93dd1119a06463f477c6dfcbe17 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sun, 17 Nov 2024 20:56:52 +0800 Subject: [PATCH 03/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/delegates/asset_picker_builder_delegate.dart | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 13e12a31..918e2242 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -48,7 +48,6 @@ abstract class AssetPickerBuilderDelegate { this.pathNameBuilder, this.assetsChangeCallback, this.assetsChangeRefreshPredicate, - this.enableDragAndSelect = true, Color? themeColor, AssetPickerTextDelegate? textDelegate, Locale? locale, @@ -132,10 +131,6 @@ abstract class AssetPickerBuilderDelegate { final AssetsChangeRefreshPredicate? assetsChangeRefreshPredicate; - /// Should enable drag and select function. - /// 是否开启拖拽选择 - final bool enableDragAndSelect; - /// [ThemeData] for the picker. /// 选择器使用的主题 ThemeData get theme => pickerTheme ?? AssetPicker.themeData(themeColor); @@ -761,12 +756,12 @@ class DefaultAssetPickerBuilderDelegate super.themeColor, super.textDelegate, super.locale, - super.enableDragAndSelect, this.gridThumbnailSize = defaultAssetGridPreviewSize, this.previewThumbnailSize, this.specialPickerType, this.keepScrollOffset = false, this.shouldAutoplayPreview = false, + this.enableDragAndSelect = true, }) { // Add the listener if [keepScrollOffset] is true. if (keepScrollOffset) { @@ -825,6 +820,10 @@ class DefaultAssetPickerBuilderDelegate /// 预览是否自动播放 final bool shouldAutoplayPreview; + /// Should enable drag and select function. + /// 是否开启拖拽选择 + final bool enableDragAndSelect; + /// [Duration] when triggering path switching. /// 切换路径时的动画时长 Duration get switchingPathDuration => const Duration(milliseconds: 300); From 0e82a3bddf5402af5ae3b377c5843a1e988018a1 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sat, 23 Nov 2024 17:29:32 +0800 Subject: [PATCH 04/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asset_grid_drag_selection_aggregator.dart | 186 ++++++++++++++++++ .../asset_picker_builder_delegate.dart | 167 ++-------------- 2 files changed, 197 insertions(+), 156 deletions(-) create mode 100644 lib/src/delegates/asset_grid_drag_selection_aggregator.dart diff --git a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart new file mode 100644 index 00000000..5777eccf --- /dev/null +++ b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart @@ -0,0 +1,186 @@ +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +class AssetGridDragSelectionAggregator { + AssetGridDragSelectionAggregator({ + required this.delegate, + }); + + /// [ChangeNotifier] for asset picker. + /// 资源选择器状态保持 + final DefaultAssetPickerBuilderDelegate delegate; + + /// 拖拽状态 + /// Drag status + bool isInDragging = false; + + /// 边缘自动滚动控制器 + /// Edge Auto Scrolling Detector. Use to support edge auto scroll when drag position reach the edge of device's screen. + EdgeDraggingAutoScroller? _autoScroller; + + // An eyeballed value for a smooth scrolling experience. + static const double _kDefaultAutoScrollVelocityScalar = 50; + + /// 起始选择序号 + /// Item index of the first selected item + int initialSelectedIdx = -1; + + /// 拖拽选择 或 拖拽取消选择 + /// Drag to select or deselect state + bool dragSelect = true; + + /// 长按启动拖拽 + /// Long Press to enable drag and select + void onDragStart( + BuildContext context, + LongPressStartDetails details, + int index, + AssetEntity entity, + ) { + isInDragging = true; + + final scrollableState = _checkScrollableStatePresent(context); + if (scrollableState == null) { + return; + } + + _autoScroller = EdgeDraggingAutoScroller( + scrollableState, + velocityScalar: _kDefaultAutoScrollVelocityScalar, + ); + + initialSelectedIdx = index; + + dragSelect = !delegate.provider.selectedAssets.contains(entity); + } + + void onDragUpdate( + BuildContext context, + LongPressMoveUpdateDetails details, + double itemSize, + int gridCount, + double topPadding, + ) { + if (!isInDragging) { + return; + } + + if (dragSelect && + delegate.provider.selectedAssets.length == + delegate.provider.maxAssets) { + return; + } + + final scrollableState = _checkScrollableStatePresent(context); + if (scrollableState == null) { + return; + } + + final column = _getDragPositionIndex(details.globalPosition.dx, itemSize); + final row = _getDragPositionIndex( + details.globalPosition.dy - + topPadding - + (View.of(context).viewPadding.top / + View.of(context).devicePixelRatio) + + scrollableState.position.pixels, + itemSize, + ); + + final currentDragIndex = row * gridCount + column; + + List filteredAssetList = []; + // add asset + if (currentDragIndex < initialSelectedIdx) { + filteredAssetList = delegate.provider.currentAssets + .getRange( + currentDragIndex, + math.min( + initialSelectedIdx + 1, delegate.provider.currentAssets.length), + ) + .toList() + ..reversed; + } else { + filteredAssetList = delegate.provider.currentAssets + .getRange( + initialSelectedIdx, + math.min( + currentDragIndex + 1, delegate.provider.currentAssets.length), + ) + .toList(); + } + + for (final asset in filteredAssetList) { + delegate.selectAsset(context, asset, currentDragIndex, !dragSelect); + } + + // dragSelect ? provider.selectAsset : provider.unSelectAsset, + + final bool stopAutoScroll = + (!dragSelect && delegate.provider.selectedAssets.isEmpty) || + (dragSelect && + delegate.provider.selectedAssets.length == + delegate.provider.maxAssets); + + if (stopAutoScroll) { + _autoScroller?.stopAutoScroll(); + _autoScroller = null; + return; + } + + if (!dragSelect && delegate.provider.selectedAssets.isEmpty) {} + + _autoScroller?.startAutoScrollIfNecessary( + Rect.fromLTWH( + (column + 1) * itemSize, + details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 + ? (row + 1) * itemSize + : math.max(topPadding, details.globalPosition.dy), + itemSize, + itemSize, + ), + ); + } + + void onDragEnd(LongPressEndDetails details) { + resetDraggingStatus(); + } + + /// 复原拖拽状态 + /// Reset dragging status + void resetDraggingStatus() { + isInDragging = false; + initialSelectedIdx = -1; + dragSelect = true; + _autoScroller?.stopAutoScroll(); + _autoScroller = null; + } + + /// 检查[Scrollable] state是否存在 + /// + ScrollableState? _checkScrollableStatePresent(BuildContext context) { + final scrollable = Scrollable.maybeOf(context); + assert( + scrollable != null, + 'To use drag and select function, Scrollable state must be the present to get the actual item position.', + ); + assert( + scrollable?.position.axis == Axis.vertical, + 'To use drag and select function. The Scrollable Axis must be in vertical direction', + ); + + if (scrollable == null || scrollable.position.axis != Axis.vertical) { + resetDraggingStatus(); + return null; + } + + return scrollable; + } + + /// 获取坐标 + /// Get Coordinate Helper + int _getDragPositionIndex(double delta, double itemSize) { + return delta ~/ itemSize; + } +} diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 918e2242..6d109b0a 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -14,6 +14,7 @@ import 'package:flutter/services.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager_image_provider/photo_manager_image_provider.dart'; import 'package:provider/provider.dart'; +import 'package:wechat_assets_picker/src/delegates/asset_grid_drag_selection_aggregator.dart'; import 'package:wechat_picker_library/wechat_picker_library.dart'; import '../constants/constants.dart'; @@ -767,6 +768,8 @@ class DefaultAssetPickerBuilderDelegate if (keepScrollOffset) { gridScrollController.addListener(keepScrollOffsetListener); } + + dragSelector = AssetGridDragSelectionAggregator(delegate: this); } /// [ChangeNotifier] for asset picker. @@ -812,6 +815,10 @@ class DefaultAssetPickerBuilderDelegate /// * [SpecialPickerType.noPreview] 禁用资源预览。多选时单击资产将直接选中,单选时选中并返回。 final SpecialPickerType? specialPickerType; + /// Drag Selector + /// 拖拽选择器 + late final AssetGridDragSelectionAggregator dragSelector; + /// Whether the picker should save the scroll offset between pushes and pops. /// 选择器是否可以从同样的位置开始选择 final bool keepScrollOffset; @@ -1228,158 +1235,6 @@ class DefaultAssetPickerBuilderDelegate ); } - /// 拖拽状态 - /// Drag status - bool isInDragging = false; - - /// 边缘自动滚动控制器 - /// Edge Auto Scrolling Detector. Use to support edge auto scroll when drag position reach the edge of device's screen. - EdgeDraggingAutoScroller? _autoScroller; - - // An eyeballed value for a smooth scrolling experience. - static const double _kDefaultAutoScrollVelocityScalar = 50; - - /// 起始选择序号 - /// Item index of the first selected item - int initialSelectedIdx = -1; - - /// 拖拽选择 或 拖拽取消选择 - /// Drag to select or deselect state - bool dragSelect = true; - - /// 长按启动拖拽 - /// Long Press to enable drag and select - void onDragStart( - BuildContext context, - LongPressStartDetails details, - int index, - AssetEntity entity, - ) { - isInDragging = true; - - final scrollableState = _checkScrollableStatePresent(context); - if (scrollableState == null) { - return; - } - - _autoScroller = EdgeDraggingAutoScroller( - scrollableState, - velocityScalar: _kDefaultAutoScrollVelocityScalar, - ); - - initialSelectedIdx = index; - - dragSelect = !provider.selectedAssets.contains(entity); - } - - void onDragUpdate( - BuildContext context, - LongPressMoveUpdateDetails details, - double itemSize, - int gridCount, - double topPadding, - ) { - if (!isInDragging) { - return; - } - - if (dragSelect && provider.selectedAssets.length == provider.maxAssets) { - return; - } - - final scrollableState = _checkScrollableStatePresent(context); - if (scrollableState == null) { - return; - } - - final column = _getDragPositionIndex(details.globalPosition.dx, itemSize); - final row = _getDragPositionIndex( - details.globalPosition.dy - - topPadding - - (View.of(context).viewPadding.top / - View.of(context).devicePixelRatio) + - scrollableState.position.pixels, - itemSize, - ); - - final currentDragIndex = row * gridCount + column; - - List filteredAssetList = []; - // add asset - if (currentDragIndex < initialSelectedIdx) { - filteredAssetList = provider.currentAssets - .getRange( - currentDragIndex, - math.min(initialSelectedIdx + 1, provider.currentAssets.length), - ) - .toList() - ..reversed; - } else { - filteredAssetList = provider.currentAssets - .getRange( - initialSelectedIdx, - math.min(currentDragIndex + 1, provider.currentAssets.length), - ) - .toList(); - } - - filteredAssetList.forEach( - dragSelect ? provider.selectAsset : provider.unSelectAsset, - ); - - _autoScroller?.startAutoScrollIfNecessary( - Rect.fromLTWH( - (column + 1) * itemSize, - details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 - ? (row + 1) * itemSize - : math.max(topPadding, details.globalPosition.dy), - itemSize, - itemSize, - ), - ); - } - - void onDragEnd(LongPressEndDetails details) { - resetDraggingStatus(); - } - - /// 复原拖拽状态 - /// Reset dragging status - void resetDraggingStatus() { - isInDragging = false; - initialSelectedIdx = -1; - dragSelect = true; - _autoScroller?.stopAutoScroll(); - _autoScroller = null; - } - - /// 检查[Scrollable] state是否存在 - /// - ScrollableState? _checkScrollableStatePresent(BuildContext context) { - final scrollable = Scrollable.maybeOf(context); - assert( - scrollable != null, - 'To use drag and select function, Scrollable state must be the present to get the actual item position.', - ); - assert( - scrollable?.position.axis == Axis.vertical, - 'To use drag and select function. The Scrollable Axis must be in vertical direction', - ); - - if (scrollable == null || scrollable.position.axis != Axis.vertical) { - resetDraggingStatus(); - return null; - } - - return scrollable; - } - - /// 获取坐标 - /// Get Coordinate Helper - int _getDragPositionIndex(double delta, double itemSize) { - return delta ~/ itemSize; - } - @override Widget assetsGridBuilder(BuildContext context) { appBarPreferredSize ??= appBar(context).preferredSize; @@ -1449,21 +1304,21 @@ class DefaultAssetPickerBuilderDelegate if (enableDragAndSelect) { child = GestureDetector( - onLongPressStart: (d) => onDragStart( + onLongPressStart: (d) => dragSelector.onDragStart( context, d, index, assets[index], ), - onLongPressMoveUpdate: (d) => onDragUpdate( + onLongPressMoveUpdate: (d) => dragSelector.onDragUpdate( context, d, itemSize, gridCount, topPadding, ), - onLongPressCancel: resetDraggingStatus, - onLongPressEnd: onDragEnd, + onLongPressCancel: dragSelector.resetDraggingStatus, + onLongPressEnd: dragSelector.onDragEnd, child: child, ); } From 6a366fb900b26206d27492571abb636c1be480fa Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sat, 23 Nov 2024 17:34:16 +0800 Subject: [PATCH 05/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegates/asset_grid_drag_selection_aggregator.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart index 5777eccf..8c8c02c3 100644 --- a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart @@ -115,8 +115,6 @@ class AssetGridDragSelectionAggregator { delegate.selectAsset(context, asset, currentDragIndex, !dragSelect); } - // dragSelect ? provider.selectAsset : provider.unSelectAsset, - final bool stopAutoScroll = (!dragSelect && delegate.provider.selectedAssets.isEmpty) || (dragSelect && @@ -157,8 +155,12 @@ class AssetGridDragSelectionAggregator { _autoScroller = null; } - /// 检查[Scrollable] state是否存在 + /// 检查 [Scrollable] state是否存在 + /// Check if the [Scrollable] state is exist /// + /// This is to ensure that the edge auto scrolling is functioning and the drag function is placed correctly + /// inside the Scrollable + /// 拖拽选择功能必须被放在 可滚动视图下才能启动边缘自动滚动功能 ScrollableState? _checkScrollableStatePresent(BuildContext context) { final scrollable = Scrollable.maybeOf(context); assert( From 1f989bbd5028a385475ab325204305c780a96682 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sun, 24 Nov 2024 20:26:28 +0800 Subject: [PATCH 06/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asset_grid_drag_selection_aggregator.dart | 42 +++++++++++-------- .../asset_picker_builder_delegate.dart | 3 +- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart index 8c8c02c3..497d2c49 100644 --- a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart @@ -90,25 +90,33 @@ class AssetGridDragSelectionAggregator { final currentDragIndex = row * gridCount + column; - List filteredAssetList = []; + final List filteredAssetList = []; // add asset if (currentDragIndex < initialSelectedIdx) { - filteredAssetList = delegate.provider.currentAssets - .getRange( - currentDragIndex, - math.min( - initialSelectedIdx + 1, delegate.provider.currentAssets.length), - ) - .toList() - ..reversed; + filteredAssetList.addAll( + delegate.provider.currentAssets + .getRange( + currentDragIndex, + math.min( + initialSelectedIdx + 1, + delegate.provider.currentAssets.length, + ), + ) + .toList() + ..reversed, + ); } else { - filteredAssetList = delegate.provider.currentAssets - .getRange( - initialSelectedIdx, - math.min( - currentDragIndex + 1, delegate.provider.currentAssets.length), - ) - .toList(); + filteredAssetList.addAll( + delegate.provider.currentAssets + .getRange( + initialSelectedIdx, + math.min( + currentDragIndex + 1, + delegate.provider.currentAssets.length, + ), + ) + .toList(), + ); } for (final asset in filteredAssetList) { @@ -127,8 +135,6 @@ class AssetGridDragSelectionAggregator { return; } - if (!dragSelect && delegate.provider.selectedAssets.isEmpty) {} - _autoScroller?.startAutoScrollIfNecessary( Rect.fromLTWH( (column + 1) * itemSize, diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 6d109b0a..5d77a92b 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -5,7 +5,6 @@ import 'dart:async'; import 'dart:math' as math; import 'dart:ui' as ui; -import 'dart:ui'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -14,12 +13,12 @@ import 'package:flutter/services.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager_image_provider/photo_manager_image_provider.dart'; import 'package:provider/provider.dart'; -import 'package:wechat_assets_picker/src/delegates/asset_grid_drag_selection_aggregator.dart'; import 'package:wechat_picker_library/wechat_picker_library.dart'; import '../constants/constants.dart'; import '../constants/enums.dart'; import '../constants/typedefs.dart'; +import '../delegates/asset_grid_drag_selection_aggregator.dart'; import '../delegates/asset_picker_text_delegate.dart'; import '../internals/singleton.dart'; import '../models/path_wrapper.dart'; From c42e7cc9b05b91776506f83befb4f8f12ef9d04e Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sun, 24 Nov 2024 21:26:52 +0800 Subject: [PATCH 07/23] =?UTF-8?q?=E2=9E=95=20Support=20Drag=20and=20Select?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asset_grid_drag_selection_aggregator.dart | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart index 497d2c49..ebd37ffd 100644 --- a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart @@ -78,17 +78,27 @@ class AssetGridDragSelectionAggregator { return; } - final column = _getDragPositionIndex(details.globalPosition.dx, itemSize); - final row = _getDragPositionIndex( + /// Calculate the coordinate of the current drag position's asset representation + final columnIndex = + _getDragPositionIndex(details.globalPosition.dx, itemSize); + + /// Get the actual top padding + /// Since viewPadding represents the physical pixels, + /// it should be divided by the device pixel ratio to get the logical pixels. + final extraTopPadding = topPadding + + (View.of(context).viewPadding.top / View.of(context).devicePixelRatio); + + /// Row index is calculated based on the drag's global position. + /// The AppBar height, status bar height, and scroll offset are subtracted to adjust for padding and scrolling. + /// This gives the actual row index. + final rowIndex = _getDragPositionIndex( details.globalPosition.dy - - topPadding - - (View.of(context).viewPadding.top / - View.of(context).devicePixelRatio) + + extraTopPadding + scrollableState.position.pixels, itemSize, ); - final currentDragIndex = row * gridCount + column; + final currentDragIndex = rowIndex * gridCount + columnIndex; final List filteredAssetList = []; // add asset @@ -135,11 +145,12 @@ class AssetGridDragSelectionAggregator { return; } + /// Enable auto scrolling if the drag detail is at edge _autoScroller?.startAutoScrollIfNecessary( Rect.fromLTWH( - (column + 1) * itemSize, + (columnIndex + 1) * itemSize, details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 - ? (row + 1) * itemSize + ? (rowIndex + 1) * itemSize : math.max(topPadding, details.globalPosition.dy), itemSize, itemSize, From f7dd57d42c50187ef54a9b3e4c7fb72901aee223 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Mon, 2 Dec 2024 16:44:39 +0800 Subject: [PATCH 08/23] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20horizonal=20ge?= =?UTF-8?q?stures=20to=20trigger=20aggregator=20calculations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/lib/constants/picker_method.dart | 1 - .../asset_grid_drag_selection_aggregator.dart | 185 ++++++++++-------- .../asset_picker_builder_delegate.dart | 8 +- 3 files changed, 111 insertions(+), 83 deletions(-) diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index d43f64ab..00857410 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -36,7 +36,6 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, - enableDragAndSelect: true, ), ); }, diff --git a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart index ebd37ffd..0b9ffae2 100644 --- a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_aggregator.dart @@ -1,8 +1,18 @@ +// Copyright 2019 The FlutterCandies author. All rights reserved. +// Use of this source code is governed by an Apache license that can be found +// in the LICENSE file. + import 'dart:math' as math; import 'package:flutter/material.dart'; -import 'package:wechat_assets_picker/wechat_assets_picker.dart'; +import 'package:photo_manager/photo_manager.dart' show AssetEntity; + +import '../provider/asset_picker_provider.dart'; +import 'asset_picker_builder_delegate.dart'; +/// The aggregator that will calculates the corresponding item position based on +/// gesture details. This will only works with +/// the [DefaultAssetPickerBuilderDelegate] and the [DefaultAssetPickerProvider]. class AssetGridDragSelectionAggregator { AssetGridDragSelectionAggregator({ required this.delegate, @@ -12,34 +22,40 @@ class AssetGridDragSelectionAggregator { /// 资源选择器状态保持 final DefaultAssetPickerBuilderDelegate delegate; - /// 拖拽状态 - /// Drag status - bool isInDragging = false; + // An eyeballed value for a smooth scrolling experience. + static const double _kDefaultAutoScrollVelocityScalar = 50.0; /// 边缘自动滚动控制器 - /// Edge Auto Scrolling Detector. Use to support edge auto scroll when drag position reach the edge of device's screen. + /// Support edge auto scroll when drag positions reach + /// the edge of device's screen. EdgeDraggingAutoScroller? _autoScroller; - // An eyeballed value for a smooth scrolling experience. - static const double _kDefaultAutoScrollVelocityScalar = 50; - /// 起始选择序号 - /// Item index of the first selected item - int initialSelectedIdx = -1; + /// The first selecting item index. + int initialSelectingIndex = -1; + + int largestSelectingIndex = -1; + int smallestSelectingIndex = -1; + + /// 拖拽状态 + /// Dragging status. + bool dragging = false; /// 拖拽选择 或 拖拽取消选择 - /// Drag to select or deselect state - bool dragSelect = true; + /// Whether to add or to remove the selected assets. + bool addSelected = true; + + DefaultAssetPickerProvider get provider => delegate.provider; /// 长按启动拖拽 /// Long Press to enable drag and select void onDragStart( BuildContext context, - LongPressStartDetails details, + DragStartDetails details, int index, AssetEntity entity, ) { - isInDragging = true; + dragging = true; final scrollableState = _checkScrollableStatePresent(context); if (scrollableState == null) { @@ -51,25 +67,25 @@ class AssetGridDragSelectionAggregator { velocityScalar: _kDefaultAutoScrollVelocityScalar, ); - initialSelectedIdx = index; + initialSelectingIndex = index; + largestSelectingIndex = index; + smallestSelectingIndex = index; - dragSelect = !delegate.provider.selectedAssets.contains(entity); + addSelected = !delegate.provider.selectedAssets.contains(entity); } void onDragUpdate( BuildContext context, - LongPressMoveUpdateDetails details, + DragUpdateDetails details, double itemSize, int gridCount, double topPadding, ) { - if (!isInDragging) { + if (!dragging) { return; } - if (dragSelect && - delegate.provider.selectedAssets.length == - delegate.provider.maxAssets) { + if (addSelected && provider.selectedAssets.length == provider.maxAssets) { return; } @@ -78,19 +94,24 @@ class AssetGridDragSelectionAggregator { return; } - /// Calculate the coordinate of the current drag position's asset representation - final columnIndex = - _getDragPositionIndex(details.globalPosition.dx, itemSize); + /// Calculate the coordinate of the current drag position's + /// asset representation. + final columnIndex = _getDragPositionIndex( + details.globalPosition.dx, + itemSize, + ); + + final view = View.of(context); - /// Get the actual top padding - /// Since viewPadding represents the physical pixels, - /// it should be divided by the device pixel ratio to get the logical pixels. - final extraTopPadding = topPadding + - (View.of(context).viewPadding.top / View.of(context).devicePixelRatio); + /// Get the actual top padding. Since `viewPadding` represents the + /// physical pixels, it should be divided by the device pixel ratio + /// to get the logical pixels. + final extraTopPadding = + topPadding + view.viewPadding.top / view.devicePixelRatio; /// Row index is calculated based on the drag's global position. - /// The AppBar height, status bar height, and scroll offset are subtracted to adjust for padding and scrolling. - /// This gives the actual row index. + /// The AppBar height, status bar height, and scroll offset are subtracted + /// to adjust for padding and scrolling. This gives the actual row index. final rowIndex = _getDragPositionIndex( details.globalPosition.dy - extraTopPadding + @@ -100,44 +121,52 @@ class AssetGridDragSelectionAggregator { final currentDragIndex = rowIndex * gridCount + columnIndex; - final List filteredAssetList = []; - // add asset - if (currentDragIndex < initialSelectedIdx) { - filteredAssetList.addAll( - delegate.provider.currentAssets - .getRange( - currentDragIndex, - math.min( - initialSelectedIdx + 1, - delegate.provider.currentAssets.length, - ), - ) - .toList() - ..reversed, - ); + // Check the selecting index in order to diff unselecting assets. + largestSelectingIndex = math.max(currentDragIndex, largestSelectingIndex); + smallestSelectingIndex = math.min(currentDragIndex, smallestSelectingIndex); + + // Filter out pending assets to manipulate. + final Iterable filteredAssetList; + if (currentDragIndex < initialSelectingIndex) { + filteredAssetList = provider.currentAssets + .getRange( + currentDragIndex, + math.min( + initialSelectingIndex + 1, + provider.currentAssets.length, + ), + ) + .toList() + .reversed; } else { - filteredAssetList.addAll( - delegate.provider.currentAssets - .getRange( - initialSelectedIdx, - math.min( - currentDragIndex + 1, - delegate.provider.currentAssets.length, - ), - ) - .toList(), + filteredAssetList = provider.currentAssets.getRange( + initialSelectingIndex, + math.min( + currentDragIndex + 1, + provider.currentAssets.length, + ), ); } - + final touchedAssets = List.from( + provider.currentAssets.getRange( + smallestSelectingIndex, + largestSelectingIndex, + ), + ); + // Toggle all filtered assets. for (final asset in filteredAssetList) { - delegate.selectAsset(context, asset, currentDragIndex, !dragSelect); + delegate.selectAsset(context, asset, currentDragIndex, !addSelected); + touchedAssets.remove(asset); + } + // Revert the selection of touched but not filtered assets. + for (final asset in touchedAssets) { + delegate.selectAsset(context, asset, currentDragIndex, addSelected); } - final bool stopAutoScroll = - (!dragSelect && delegate.provider.selectedAssets.isEmpty) || - (dragSelect && - delegate.provider.selectedAssets.length == - delegate.provider.maxAssets); + final stopAutoScroll = switch (addSelected) { + true => provider.selectedAssets.length == provider.maxAssets, + false => provider.selectedAssets.isEmpty, + }; if (stopAutoScroll) { _autoScroller?.stopAutoScroll(); @@ -147,29 +176,30 @@ class AssetGridDragSelectionAggregator { /// Enable auto scrolling if the drag detail is at edge _autoScroller?.startAutoScrollIfNecessary( - Rect.fromLTWH( - (columnIndex + 1) * itemSize, - details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 - ? (rowIndex + 1) * itemSize - : math.max(topPadding, details.globalPosition.dy), - itemSize, - itemSize, - ), + Offset( + (columnIndex + 1) * itemSize, + details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 + ? (rowIndex + 1) * itemSize + : math.max(topPadding, details.globalPosition.dy), + ) & + Size.square(itemSize), ); } - void onDragEnd(LongPressEndDetails details) { + void onDragEnd(DragEndDetails details) { resetDraggingStatus(); } /// 复原拖拽状态 /// Reset dragging status void resetDraggingStatus() { - isInDragging = false; - initialSelectedIdx = -1; - dragSelect = true; _autoScroller?.stopAutoScroll(); _autoScroller = null; + dragging = false; + addSelected = true; + initialSelectingIndex = -1; + largestSelectingIndex = -1; + smallestSelectingIndex = -1; } /// 检查 [Scrollable] state是否存在 @@ -182,13 +212,12 @@ class AssetGridDragSelectionAggregator { final scrollable = Scrollable.maybeOf(context); assert( scrollable != null, - 'To use drag and select function, Scrollable state must be the present to get the actual item position.', + 'The drag select feature must use along with scrollables.', ); assert( scrollable?.position.axis == Axis.vertical, - 'To use drag and select function. The Scrollable Axis must be in vertical direction', + 'The drag select feature must use along with vertical scrollables.', ); - if (scrollable == null || scrollable.position.axis != Axis.vertical) { resetDraggingStatus(); return null; diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 5d77a92b..c80fae14 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1303,21 +1303,21 @@ class DefaultAssetPickerBuilderDelegate if (enableDragAndSelect) { child = GestureDetector( - onLongPressStart: (d) => dragSelector.onDragStart( + onHorizontalDragStart: (d) => dragSelector.onDragStart( context, d, index, assets[index], ), - onLongPressMoveUpdate: (d) => dragSelector.onDragUpdate( + onHorizontalDragUpdate: (d) => dragSelector.onDragUpdate( context, d, itemSize, gridCount, topPadding, ), - onLongPressCancel: dragSelector.resetDraggingStatus, - onLongPressEnd: dragSelector.onDragEnd, + onHorizontalDragCancel: dragSelector.resetDraggingStatus, + onHorizontalDragEnd: dragSelector.onDragEnd, child: child, ); } From ff77528d77edb6488bc8beb4ae4a3bb9ccb317fd Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 3 Dec 2024 21:04:14 +0800 Subject: [PATCH 09/23] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refine=20the=20coord?= =?UTF-8?q?inator=20and=20add=20multiple=20gestures=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sset_grid_drag_selection_coordinator.dart} | 64 ++++++------- .../asset_picker_builder_delegate.dart | 90 +++++++++++++------ 2 files changed, 93 insertions(+), 61 deletions(-) rename lib/src/delegates/{asset_grid_drag_selection_aggregator.dart => asset_grid_drag_selection_coordinator.dart} (79%) diff --git a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart similarity index 79% rename from lib/src/delegates/asset_grid_drag_selection_aggregator.dart rename to lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 0b9ffae2..ab259a7c 100644 --- a/lib/src/delegates/asset_grid_drag_selection_aggregator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -10,11 +10,11 @@ import 'package:photo_manager/photo_manager.dart' show AssetEntity; import '../provider/asset_picker_provider.dart'; import 'asset_picker_builder_delegate.dart'; -/// The aggregator that will calculates the corresponding item position based on +/// The coordinator that will calculates the corresponding item position based on /// gesture details. This will only works with /// the [DefaultAssetPickerBuilderDelegate] and the [DefaultAssetPickerProvider]. -class AssetGridDragSelectionAggregator { - AssetGridDragSelectionAggregator({ +class AssetGridDragSelectionCoordinator { + AssetGridDragSelectionCoordinator({ required this.delegate, }); @@ -49,9 +49,9 @@ class AssetGridDragSelectionAggregator { /// 长按启动拖拽 /// Long Press to enable drag and select - void onDragStart( + void onSelectionStart( BuildContext context, - DragStartDetails details, + Offset globalPosition, int index, AssetEntity entity, ) { @@ -74,13 +74,7 @@ class AssetGridDragSelectionAggregator { addSelected = !delegate.provider.selectedAssets.contains(entity); } - void onDragUpdate( - BuildContext context, - DragUpdateDetails details, - double itemSize, - int gridCount, - double topPadding, - ) { + void onSelectionUpdate(BuildContext context, Offset globalPosition) { if (!dragging) { return; } @@ -94,28 +88,26 @@ class AssetGridDragSelectionAggregator { return; } - /// Calculate the coordinate of the current drag position's - /// asset representation. - final columnIndex = _getDragPositionIndex( - details.globalPosition.dx, - itemSize, - ); - + // Calculate the coordinate of the current drag position's + // asset representation. final view = View.of(context); - - /// Get the actual top padding. Since `viewPadding` represents the - /// physical pixels, it should be divided by the device pixel ratio - /// to get the logical pixels. - final extraTopPadding = - topPadding + view.viewPadding.top / view.devicePixelRatio; - - /// Row index is calculated based on the drag's global position. - /// The AppBar height, status bar height, and scroll offset are subtracted - /// to adjust for padding and scrolling. This gives the actual row index. + final gridCount = delegate.gridCount; + final itemSize = view.physicalSize.width / gridCount; + final columnIndex = _getDragPositionIndex(globalPosition.dx, itemSize); + + // Get the actual top padding. Since `viewPadding` represents the + // physical pixels, it should be divided by the device pixel ratio + // to get the logical pixels. + final appBarSize = + delegate.appBarPreferredSize ?? delegate.appBar(context).preferredSize; + final topPadding = + appBarSize.height + view.viewPadding.top / view.devicePixelRatio; + + // Row index is calculated based on the drag's global position. + // The AppBar height, status bar height, and scroll offset are subtracted + // to adjust for padding and scrolling. This gives the actual row index. final rowIndex = _getDragPositionIndex( - details.globalPosition.dy - - extraTopPadding + - scrollableState.position.pixels, + globalPosition.dy - topPadding + scrollableState.position.pixels, itemSize, ); @@ -174,19 +166,19 @@ class AssetGridDragSelectionAggregator { return; } - /// Enable auto scrolling if the drag detail is at edge + // Enable auto scrolling if the drag detail is at edge _autoScroller?.startAutoScrollIfNecessary( Offset( (columnIndex + 1) * itemSize, - details.globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 + globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 ? (rowIndex + 1) * itemSize - : math.max(topPadding, details.globalPosition.dy), + : math.max(topPadding, globalPosition.dy), ) & Size.square(itemSize), ); } - void onDragEnd(DragEndDetails details) { + void onDragEnd(Offset globalPosition) { resetDraggingStatus(); } diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index c80fae14..645138de 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -18,7 +18,7 @@ import 'package:wechat_picker_library/wechat_picker_library.dart'; import '../constants/constants.dart'; import '../constants/enums.dart'; import '../constants/typedefs.dart'; -import '../delegates/asset_grid_drag_selection_aggregator.dart'; +import '../delegates/asset_grid_drag_selection_coordinator.dart'; import '../delegates/asset_picker_text_delegate.dart'; import '../internals/singleton.dart'; import '../models/path_wrapper.dart'; @@ -767,8 +767,7 @@ class DefaultAssetPickerBuilderDelegate if (keepScrollOffset) { gridScrollController.addListener(keepScrollOffsetListener); } - - dragSelector = AssetGridDragSelectionAggregator(delegate: this); + dragSelectCoordinator = AssetGridDragSelectionCoordinator(delegate: this); } /// [ChangeNotifier] for asset picker. @@ -814,9 +813,9 @@ class DefaultAssetPickerBuilderDelegate /// * [SpecialPickerType.noPreview] 禁用资源预览。多选时单击资产将直接选中,单选时选中并返回。 final SpecialPickerType? specialPickerType; - /// Drag Selector - /// 拖拽选择器 - late final AssetGridDragSelectionAggregator dragSelector; + /// Drag select aggregator. + /// 拖拽选择协调器 + late final AssetGridDragSelectionCoordinator dragSelectCoordinator; /// Whether the picker should save the scroll offset between pushes and pops. /// 选择器是否可以从同样的位置开始选择 @@ -1279,9 +1278,9 @@ class DefaultAssetPickerBuilderDelegate final double topPadding = context.topPadding + appBarPreferredSize!.height; - final textDirection = Directionality.of(context); - final double screenWidth = MediaQuery.sizeOf(context).width; - final double itemSize = screenWidth / gridCount; + // Obtain the text direction from the correct context and apply to + // the grid item before it gets manipulated by the grid revert. + final textDirectionCorrection = Directionality.of(context); Widget sliverGrid(BuildContext context, List assets) { return SliverGrid( @@ -1303,28 +1302,69 @@ class DefaultAssetPickerBuilderDelegate if (enableDragAndSelect) { child = GestureDetector( - onHorizontalDragStart: (d) => dragSelector.onDragStart( - context, - d, - index, - assets[index], - ), - onHorizontalDragUpdate: (d) => dragSelector.onDragUpdate( - context, - d, - itemSize, - gridCount, - topPadding, - ), - onHorizontalDragCancel: dragSelector.resetDraggingStatus, - onHorizontalDragEnd: dragSelector.onDragEnd, + onHorizontalDragStart: (d) { + dragSelectCoordinator.onSelectionStart( + context, + d.globalPosition, + index, + assets[index], + ); + }, + onHorizontalDragUpdate: (d) { + dragSelectCoordinator.onSelectionUpdate( + context, + d.globalPosition, + ); + }, + onHorizontalDragCancel: + dragSelectCoordinator.resetDraggingStatus, + onHorizontalDragEnd: (d) { + dragSelectCoordinator.onDragEnd(d.globalPosition); + }, + onLongPressStart: (d) { + dragSelectCoordinator.onSelectionStart( + context, + d.globalPosition, + index, + assets[index], + ); + }, + onLongPressMoveUpdate: (d) { + dragSelectCoordinator.onSelectionUpdate( + context, + d.globalPosition, + ); + }, + onLongPressCancel: + dragSelectCoordinator.resetDraggingStatus, + onLongPressEnd: (d) { + dragSelectCoordinator.onDragEnd(d.globalPosition); + }, + onPanStart: (d) { + dragSelectCoordinator.onSelectionStart( + context, + d.globalPosition, + index, + assets[index], + ); + }, + onPanUpdate: (d) { + dragSelectCoordinator.onSelectionUpdate( + context, + d.globalPosition, + ); + }, + onPanCancel: dragSelectCoordinator.resetDraggingStatus, + onPanEnd: (d) { + dragSelectCoordinator.onDragEnd(d.globalPosition); + }, child: child, ); } return MergeSemantics( child: Directionality( - textDirection: textDirection, + textDirection: textDirectionCorrection, child: child, ), ); From 6bca4c2eb2ed1e08ba3eb527a4f828e33313d2bc Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 3 Dec 2024 22:18:10 +0800 Subject: [PATCH 10/23] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20`enableDragAndSelect?= =?UTF-8?q?`=20->=20`dragToSelect`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/constants/config.dart | 8 +++++--- lib/src/delegates/asset_picker_builder_delegate.dart | 9 ++++----- lib/src/delegates/asset_picker_delegate.dart | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/src/constants/config.dart b/lib/src/constants/config.dart index 46befbec..40a416f5 100644 --- a/lib/src/constants/config.dart +++ b/lib/src/constants/config.dart @@ -39,7 +39,7 @@ class AssetPickerConfig { this.assetsChangeCallback, this.assetsChangeRefreshPredicate, this.shouldAutoplayPreview = false, - this.enableDragAndSelect = true, + this.dragToSelect = true, }) : assert( pickerTheme == null || themeColor == null, 'pickerTheme and themeColor cannot be set at the same time.', @@ -207,7 +207,9 @@ class AssetPickerConfig { /// 预览是否自动播放 final bool shouldAutoplayPreview; - /// Should enable drag and select function. + /// {@template wechat_assets_picker.constants.AssetPickerConfig.dragToSelect} + /// Whether assets selection can be done with drag gestures. /// 是否开启拖拽选择 - final bool enableDragAndSelect; + /// {@endtemplate} + final bool dragToSelect; } diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index 645138de..d4df42ae 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -761,7 +761,7 @@ class DefaultAssetPickerBuilderDelegate this.specialPickerType, this.keepScrollOffset = false, this.shouldAutoplayPreview = false, - this.enableDragAndSelect = true, + this.dragToSelect = true, }) { // Add the listener if [keepScrollOffset] is true. if (keepScrollOffset) { @@ -825,9 +825,8 @@ class DefaultAssetPickerBuilderDelegate /// 预览是否自动播放 final bool shouldAutoplayPreview; - /// Should enable drag and select function. - /// 是否开启拖拽选择 - final bool enableDragAndSelect; + /// {@macro wechat_assets_picker.constants.AssetPickerConfig.dragToSelect} + final bool dragToSelect; /// [Duration] when triggering path switching. /// 切换路径时的动画时长 @@ -1300,7 +1299,7 @@ class DefaultAssetPickerBuilderDelegate specialItem: specialItem, ); - if (enableDragAndSelect) { + if (dragToSelect) { child = GestureDetector( onHorizontalDragStart: (d) { dragSelectCoordinator.onSelectionStart( diff --git a/lib/src/delegates/asset_picker_delegate.dart b/lib/src/delegates/asset_picker_delegate.dart index e57b434c..1d7af894 100644 --- a/lib/src/delegates/asset_picker_delegate.dart +++ b/lib/src/delegates/asset_picker_delegate.dart @@ -119,7 +119,7 @@ class AssetPickerDelegate { themeColor: pickerConfig.themeColor, locale: Localizations.maybeLocaleOf(context), shouldAutoplayPreview: pickerConfig.shouldAutoplayPreview, - enableDragAndSelect: pickerConfig.enableDragAndSelect, + dragToSelect: pickerConfig.dragToSelect, ), ); final List? result = await Navigator.maybeOf( From cb464607ef7c1063cf2a342d8a7e9ba8ab5a345d Mon Sep 17 00:00:00 2001 From: Alex Li Date: Wed, 4 Dec 2024 10:59:15 +0800 Subject: [PATCH 11/23] =?UTF-8?q?=F0=9F=90=9B=20Fix=20dimension=20calculat?= =?UTF-8?q?ions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegates/asset_grid_drag_selection_coordinator.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index ab259a7c..e8f8ebe0 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -88,11 +88,13 @@ class AssetGridDragSelectionCoordinator { return; } + final view = View.of(context); + final dimensionSize = view.physicalSize / view.devicePixelRatio; + // Calculate the coordinate of the current drag position's // asset representation. - final view = View.of(context); final gridCount = delegate.gridCount; - final itemSize = view.physicalSize.width / gridCount; + final itemSize = dimensionSize.width / gridCount; final columnIndex = _getDragPositionIndex(globalPosition.dx, itemSize); // Get the actual top padding. Since `viewPadding` represents the From b6bcc6e25c7bcfde7126af1fb8c42f50e73c24f8 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Wed, 4 Dec 2024 11:07:33 +0800 Subject: [PATCH 12/23] =?UTF-8?q?=F0=9F=90=9B=20Fix=20the=20missing=20rang?= =?UTF-8?q?e=20from=20the=20largest=20index?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asset_grid_drag_selection_coordinator.dart | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index e8f8ebe0..c9e7f797 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -79,10 +79,6 @@ class AssetGridDragSelectionCoordinator { return; } - if (addSelected && provider.selectedAssets.length == provider.maxAssets) { - return; - } - final scrollableState = _checkScrollableStatePresent(context); if (scrollableState == null) { return; @@ -116,8 +112,14 @@ class AssetGridDragSelectionCoordinator { final currentDragIndex = rowIndex * gridCount + columnIndex; // Check the selecting index in order to diff unselecting assets. - largestSelectingIndex = math.max(currentDragIndex, largestSelectingIndex); - smallestSelectingIndex = math.min(currentDragIndex, smallestSelectingIndex); + smallestSelectingIndex = math.min( + currentDragIndex, + smallestSelectingIndex, + ); + largestSelectingIndex = math.max( + currentDragIndex + 1, + largestSelectingIndex, + ); // Filter out pending assets to manipulate. final Iterable filteredAssetList; From ec57fba776e86c13ee6674190ae286a0cb4b75f5 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Wed, 4 Dec 2024 11:16:14 +0800 Subject: [PATCH 13/23] =?UTF-8?q?=E2=99=BF=EF=B8=8F=20Try=20to=20fix=20acc?= =?UTF-8?q?essibility=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/constants/config.dart | 7 +++++-- lib/src/delegates/asset_picker_builder_delegate.dart | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/src/constants/config.dart b/lib/src/constants/config.dart index 40a416f5..6832f2cc 100644 --- a/lib/src/constants/config.dart +++ b/lib/src/constants/config.dart @@ -39,7 +39,7 @@ class AssetPickerConfig { this.assetsChangeCallback, this.assetsChangeRefreshPredicate, this.shouldAutoplayPreview = false, - this.dragToSelect = true, + this.dragToSelect, }) : assert( pickerTheme == null || themeColor == null, 'pickerTheme and themeColor cannot be set at the same time.', @@ -210,6 +210,9 @@ class AssetPickerConfig { /// {@template wechat_assets_picker.constants.AssetPickerConfig.dragToSelect} /// Whether assets selection can be done with drag gestures. /// 是否开启拖拽选择 + /// + /// The feature enables by default if no accessibility service is being used. + /// 在未使用辅助功能的情况下会默认启用该功能。 /// {@endtemplate} - final bool dragToSelect; + final bool? dragToSelect; } diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index d4df42ae..b91e6b17 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -761,7 +761,7 @@ class DefaultAssetPickerBuilderDelegate this.specialPickerType, this.keepScrollOffset = false, this.shouldAutoplayPreview = false, - this.dragToSelect = true, + this.dragToSelect, }) { // Add the listener if [keepScrollOffset] is true. if (keepScrollOffset) { @@ -826,7 +826,7 @@ class DefaultAssetPickerBuilderDelegate final bool shouldAutoplayPreview; /// {@macro wechat_assets_picker.constants.AssetPickerConfig.dragToSelect} - final bool dragToSelect; + final bool? dragToSelect; /// [Duration] when triggering path switching. /// 切换路径时的动画时长 @@ -1299,8 +1299,10 @@ class DefaultAssetPickerBuilderDelegate specialItem: specialItem, ); - if (dragToSelect) { + if (dragToSelect ?? + !MediaQuery.accessibleNavigationOf(context)) { child = GestureDetector( + excludeFromSemantics: true, onHorizontalDragStart: (d) { dragSelectCoordinator.onSelectionStart( context, From 9a1bcdf60e9d99af6e533ab002edfc5d60f09407 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Wed, 4 Dec 2024 15:46:52 +0800 Subject: [PATCH 14/23] =?UTF-8?q?=F0=9F=90=9B=20Fix=20grid=20revert=20calc?= =?UTF-8?q?ulations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...asset_grid_drag_selection_coordinator.dart | 38 +++++++++++++------ .../asset_picker_builder_delegate.dart | 2 +- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index c9e7f797..6633d122 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -79,11 +79,6 @@ class AssetGridDragSelectionCoordinator { return; } - final scrollableState = _checkScrollableStatePresent(context); - if (scrollableState == null) { - return; - } - final view = View.of(context); final dimensionSize = view.physicalSize / view.devicePixelRatio; @@ -91,7 +86,6 @@ class AssetGridDragSelectionCoordinator { // asset representation. final gridCount = delegate.gridCount; final itemSize = dimensionSize.width / gridCount; - final columnIndex = _getDragPositionIndex(globalPosition.dx, itemSize); // Get the actual top padding. Since `viewPadding` represents the // physical pixels, it should be divided by the device pixel ratio @@ -100,12 +94,22 @@ class AssetGridDragSelectionCoordinator { delegate.appBarPreferredSize ?? delegate.appBar(context).preferredSize; final topPadding = appBarSize.height + view.viewPadding.top / view.devicePixelRatio; + final bottomPadding = delegate.bottomActionBarHeight + + view.viewPadding.bottom / view.devicePixelRatio; // Row index is calculated based on the drag's global position. // The AppBar height, status bar height, and scroll offset are subtracted // to adjust for padding and scrolling. This gives the actual row index. + final gridRevert = delegate.effectiveShouldRevertGrid(context); + int columnIndex = _getDragPositionIndex(globalPosition.dx, itemSize); + if (gridRevert) { + columnIndex = gridCount - columnIndex - 2; + } final rowIndex = _getDragPositionIndex( - globalPosition.dy - topPadding + scrollableState.position.pixels, + switch (gridRevert) { + true => dimensionSize.height - bottomPadding - globalPosition.dy, + false => globalPosition.dy - topPadding, + }, itemSize, ); @@ -116,17 +120,19 @@ class AssetGridDragSelectionCoordinator { currentDragIndex, smallestSelectingIndex, ); + smallestSelectingIndex = math.max(0, smallestSelectingIndex); largestSelectingIndex = math.max( currentDragIndex + 1, largestSelectingIndex, ); + largestSelectingIndex = math.max(0, largestSelectingIndex); // Filter out pending assets to manipulate. final Iterable filteredAssetList; if (currentDragIndex < initialSelectingIndex) { filteredAssetList = provider.currentAssets .getRange( - currentDragIndex, + math.max(0, currentDragIndex), math.min( initialSelectingIndex + 1, provider.currentAssets.length, @@ -136,7 +142,7 @@ class AssetGridDragSelectionCoordinator { .reversed; } else { filteredAssetList = provider.currentAssets.getRange( - initialSelectingIndex, + math.max(0, initialSelectingIndex), math.min( currentDragIndex + 1, provider.currentAssets.length, @@ -149,6 +155,17 @@ class AssetGridDragSelectionCoordinator { largestSelectingIndex, ), ); + + // Do not select or unselect more assets if the limit has been reached. + if (filteredAssetList.isNotEmpty) { + if (addSelected && provider.selectedMaximumAssets) { + return; + } + if (!addSelected && !provider.isSelectedNotEmpty) { + return; + } + } + // Toggle all filtered assets. for (final asset in filteredAssetList) { delegate.selectAsset(context, asset, currentDragIndex, !addSelected); @@ -166,7 +183,6 @@ class AssetGridDragSelectionCoordinator { if (stopAutoScroll) { _autoScroller?.stopAutoScroll(); - _autoScroller = null; return; } @@ -174,7 +190,7 @@ class AssetGridDragSelectionCoordinator { _autoScroller?.startAutoScrollIfNecessary( Offset( (columnIndex + 1) * itemSize, - globalPosition.dy > MediaQuery.sizeOf(context).height * 0.8 + globalPosition.dy > dimensionSize.height * 0.8 ? (rowIndex + 1) * itemSize : math.max(topPadding, globalPosition.dy), ) & diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index b91e6b17..ea12fa04 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1533,7 +1533,7 @@ class DefaultAssetPickerBuilderDelegate builder, selectedBackdrop(context, currentIndex, asset), if (!isWeChatMoment || asset.type != AssetType.video) - selectIndicator(context, index, asset), + selectIndicator(context, currentIndex, asset), itemBannedIndicator(context, asset), ], ); From 3026576c45c6931cecb7ca0ecb4f98e37c5b72f0 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Thu, 12 Dec 2024 22:37:31 +0800 Subject: [PATCH 15/23] =?UTF-8?q?=F0=9F=90=9B=20Fix=20column=20and=20row?= =?UTF-8?q?=20index=20inaccurate=20when=20asset=20is=20less=20than=20a=20p?= =?UTF-8?q?age?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...asset_grid_drag_selection_coordinator.dart | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 6633d122..95d1e094 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -102,10 +102,18 @@ class AssetGridDragSelectionCoordinator { // to adjust for padding and scrolling. This gives the actual row index. final gridRevert = delegate.effectiveShouldRevertGrid(context); int columnIndex = _getDragPositionIndex(globalPosition.dx, itemSize); + final maxRow = (provider.currentAssets.length / delegate.gridCount).ceil(); + final maxRowPerPage = + ((dimensionSize.height - bottomPadding) / itemSize).ceil(); + if (gridRevert) { - columnIndex = gridCount - columnIndex - 2; + columnIndex = gridCount - columnIndex; + if (maxRow > maxRowPerPage) { + columnIndex -= 1; + } } - final rowIndex = _getDragPositionIndex( + + int rowIndex = _getDragPositionIndex( switch (gridRevert) { true => dimensionSize.height - bottomPadding - globalPosition.dy, false => globalPosition.dy - topPadding, @@ -113,6 +121,11 @@ class AssetGridDragSelectionCoordinator { itemSize, ); + // Correct the row index when asset length is less than one page + if (maxRowPerPage > maxRow) { + rowIndex = maxRow - (maxRowPerPage - rowIndex); + } + final currentDragIndex = rowIndex * gridCount + columnIndex; // Check the selecting index in order to diff unselecting assets. @@ -125,7 +138,12 @@ class AssetGridDragSelectionCoordinator { currentDragIndex + 1, largestSelectingIndex, ); - largestSelectingIndex = math.max(0, largestSelectingIndex); + + // To avoid array indexed out of bounds + largestSelectingIndex = math.min( + math.max(0, largestSelectingIndex), + provider.currentAssets.length, + ); // Filter out pending assets to manipulate. final Iterable filteredAssetList; From 9388adadb7db67b26b4fd88b895717c9e638839f Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Tue, 17 Dec 2024 23:27:29 +0800 Subject: [PATCH 16/23] =?UTF-8?q?=F0=9F=90=9B=20Fix=20android=20revert=20d?= =?UTF-8?q?rag=20select=20calculation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...asset_grid_drag_selection_coordinator.dart | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 95d1e094..1e03e022 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -102,10 +102,17 @@ class AssetGridDragSelectionCoordinator { // to adjust for padding and scrolling. This gives the actual row index. final gridRevert = delegate.effectiveShouldRevertGrid(context); int columnIndex = _getDragPositionIndex(globalPosition.dx, itemSize); - final maxRow = (provider.currentAssets.length / delegate.gridCount).ceil(); + final maxRow = (provider.currentAssets.length / gridCount).ceil(); final maxRowPerPage = ((dimensionSize.height - bottomPadding) / itemSize).ceil(); + // // Get the total asset count of the current Asset path + // final totalCount = provider.currentPath?.assetCount ?? 0; + // // Check if special item does exist + // final specialItemExist = delegate.shouldBuildSpecialItem; + // final lastRowCount = (totalCount + (specialItemExist ? 1 : 0)) % gridCount; + // final placeholderCount = gridCount - lastRowCount; + if (gridRevert) { columnIndex = gridCount - columnIndex; if (maxRow > maxRowPerPage) { @@ -115,8 +122,12 @@ class AssetGridDragSelectionCoordinator { int rowIndex = _getDragPositionIndex( switch (gridRevert) { - true => dimensionSize.height - bottomPadding - globalPosition.dy, - false => globalPosition.dy - topPadding, + true => dimensionSize.height - + bottomPadding - + globalPosition.dy + + -delegate.gridScrollController.offset, + false => + globalPosition.dy - topPadding + delegate.gridScrollController.offset, }, itemSize, ); @@ -174,16 +185,6 @@ class AssetGridDragSelectionCoordinator { ), ); - // Do not select or unselect more assets if the limit has been reached. - if (filteredAssetList.isNotEmpty) { - if (addSelected && provider.selectedMaximumAssets) { - return; - } - if (!addSelected && !provider.isSelectedNotEmpty) { - return; - } - } - // Toggle all filtered assets. for (final asset in filteredAssetList) { delegate.selectAsset(context, asset, currentDragIndex, !addSelected); From f72478dcdc026850b3dd126a48c8cb2f1ee4c0ab Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Wed, 18 Dec 2024 23:50:15 +0800 Subject: [PATCH 17/23] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Optimize=20column=20?= =?UTF-8?q?and=20row=20index=20calculation=20in=20reverse=20grid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...asset_grid_drag_selection_coordinator.dart | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 1e03e022..1f85d2ff 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -106,15 +106,25 @@ class AssetGridDragSelectionCoordinator { final maxRowPerPage = ((dimensionSize.height - bottomPadding) / itemSize).ceil(); - // // Get the total asset count of the current Asset path - // final totalCount = provider.currentPath?.assetCount ?? 0; - // // Check if special item does exist - // final specialItemExist = delegate.shouldBuildSpecialItem; - // final lastRowCount = (totalCount + (specialItemExist ? 1 : 0)) % gridCount; - // final placeholderCount = gridCount - lastRowCount; + final int placeholderCount; + if (gridRevert) { + // Get the total asset count of the current Asset path + final totalCount = provider.currentPath?.assetCount ?? 0; + // Check if special item does exist + final specialItemExist = delegate.shouldBuildSpecialItem; + final lastRowCount = + (totalCount + (specialItemExist ? 1 : 0)) % gridCount; + placeholderCount = gridCount - lastRowCount; + } else { + placeholderCount = 0; + } + + final bottomGap = MediaQuery.paddingOf(context).bottom + + delegate.bottomSectionHeight - + (delegate.isAppleOS(context) ? delegate.permissionLimitedBarHeight : 0); if (gridRevert) { - columnIndex = gridCount - columnIndex; + columnIndex = gridCount - columnIndex - placeholderCount; if (maxRow > maxRowPerPage) { columnIndex -= 1; } @@ -123,8 +133,9 @@ class AssetGridDragSelectionCoordinator { int rowIndex = _getDragPositionIndex( switch (gridRevert) { true => dimensionSize.height - - bottomPadding - + topPadding - globalPosition.dy + + (delegate.gridScrollController.offset <= 0 ? bottomGap : 0) + -delegate.gridScrollController.offset, false => globalPosition.dy - topPadding + delegate.gridScrollController.offset, @@ -132,6 +143,10 @@ class AssetGridDragSelectionCoordinator { itemSize, ); + if (placeholderCount > 0) { + rowIndex -= 1; + } + // Correct the row index when asset length is less than one page if (maxRowPerPage > maxRow) { rowIndex = maxRow - (maxRowPerPage - rowIndex); @@ -139,6 +154,9 @@ class AssetGridDragSelectionCoordinator { final currentDragIndex = rowIndex * gridCount + columnIndex; + print( + "Check drag index: $currentDragIndex | $initialSelectingIndex | $rowIndex | $columnIndex"); + // Check the selecting index in order to diff unselecting assets. smallestSelectingIndex = math.min( currentDragIndex, From f9016c14c8f5faff2e9aff70ef9846e283065fb3 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Mon, 23 Dec 2024 23:22:13 +0800 Subject: [PATCH 18/23] :bug: Fix drag select index accuracy when asset size is one page --- example/lib/constants/picker_method.dart | 1 + ...asset_grid_drag_selection_coordinator.dart | 28 ++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index 00857410..ba72204a 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -36,6 +36,7 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, + // shouldRevertGrid: true, ), ); }, diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 1f85d2ff..6a767470 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -130,6 +130,15 @@ class AssetGridDragSelectionCoordinator { } } + final double dividedSpacing = delegate.itemSpacing / gridCount; + final double anchor = math.min( + (maxRow * (itemSize + dividedSpacing) + + topPadding - + delegate.itemSpacing) / + dimensionSize.height, + 1, + ); + int rowIndex = _getDragPositionIndex( switch (gridRevert) { true => dimensionSize.height - @@ -143,20 +152,19 @@ class AssetGridDragSelectionCoordinator { itemSize, ); - if (placeholderCount > 0) { - rowIndex -= 1; + final double initialFirstPosition = dimensionSize.height * anchor; + if (gridRevert && dimensionSize.height > initialFirstPosition) { + final deductedRow = + (dimensionSize.height - initialFirstPosition) ~/ itemSize; + rowIndex -= deductedRow; } - // Correct the row index when asset length is less than one page - if (maxRowPerPage > maxRow) { - rowIndex = maxRow - (maxRowPerPage - rowIndex); + if (placeholderCount > 0 && maxRow > maxRowPerPage) { + rowIndex -= 1; } final currentDragIndex = rowIndex * gridCount + columnIndex; - print( - "Check drag index: $currentDragIndex | $initialSelectingIndex | $rowIndex | $columnIndex"); - // Check the selecting index in order to diff unselecting assets. smallestSelectingIndex = math.min( currentDragIndex, @@ -164,7 +172,7 @@ class AssetGridDragSelectionCoordinator { ); smallestSelectingIndex = math.max(0, smallestSelectingIndex); largestSelectingIndex = math.max( - currentDragIndex + 1, + currentDragIndex, largestSelectingIndex, ); @@ -191,7 +199,7 @@ class AssetGridDragSelectionCoordinator { filteredAssetList = provider.currentAssets.getRange( math.max(0, initialSelectingIndex), math.min( - currentDragIndex + 1, + currentDragIndex + (maxRow > maxRowPerPage ? 1 : 0), provider.currentAssets.length, ), ); From 77d44290d77b10d6842d4db3f4560999256adae5 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Mon, 23 Dec 2024 23:22:20 +0800 Subject: [PATCH 19/23] Revert ":bug: Fix drag select index accuracy when asset size is one page" This reverts commit f9016c14c8f5faff2e9aff70ef9846e283065fb3. --- example/lib/constants/picker_method.dart | 1 - ...asset_grid_drag_selection_coordinator.dart | 28 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/example/lib/constants/picker_method.dart b/example/lib/constants/picker_method.dart index ba72204a..00857410 100644 --- a/example/lib/constants/picker_method.dart +++ b/example/lib/constants/picker_method.dart @@ -36,7 +36,6 @@ class PickMethod { pickerConfig: AssetPickerConfig( maxAssets: maxAssetsCount, selectedAssets: assets, - // shouldRevertGrid: true, ), ); }, diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 6a767470..1f85d2ff 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -130,15 +130,6 @@ class AssetGridDragSelectionCoordinator { } } - final double dividedSpacing = delegate.itemSpacing / gridCount; - final double anchor = math.min( - (maxRow * (itemSize + dividedSpacing) + - topPadding - - delegate.itemSpacing) / - dimensionSize.height, - 1, - ); - int rowIndex = _getDragPositionIndex( switch (gridRevert) { true => dimensionSize.height - @@ -152,19 +143,20 @@ class AssetGridDragSelectionCoordinator { itemSize, ); - final double initialFirstPosition = dimensionSize.height * anchor; - if (gridRevert && dimensionSize.height > initialFirstPosition) { - final deductedRow = - (dimensionSize.height - initialFirstPosition) ~/ itemSize; - rowIndex -= deductedRow; + if (placeholderCount > 0) { + rowIndex -= 1; } - if (placeholderCount > 0 && maxRow > maxRowPerPage) { - rowIndex -= 1; + // Correct the row index when asset length is less than one page + if (maxRowPerPage > maxRow) { + rowIndex = maxRow - (maxRowPerPage - rowIndex); } final currentDragIndex = rowIndex * gridCount + columnIndex; + print( + "Check drag index: $currentDragIndex | $initialSelectingIndex | $rowIndex | $columnIndex"); + // Check the selecting index in order to diff unselecting assets. smallestSelectingIndex = math.min( currentDragIndex, @@ -172,7 +164,7 @@ class AssetGridDragSelectionCoordinator { ); smallestSelectingIndex = math.max(0, smallestSelectingIndex); largestSelectingIndex = math.max( - currentDragIndex, + currentDragIndex + 1, largestSelectingIndex, ); @@ -199,7 +191,7 @@ class AssetGridDragSelectionCoordinator { filteredAssetList = provider.currentAssets.getRange( math.max(0, initialSelectingIndex), math.min( - currentDragIndex + (maxRow > maxRowPerPage ? 1 : 0), + currentDragIndex + 1, provider.currentAssets.length, ), ); From dfa8352e6e04a622cc47f40f82987d2d1c610bcf Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Mon, 23 Dec 2024 23:23:16 +0800 Subject: [PATCH 20/23] =?UTF-8?q?=20=F0=9F=90=9B=20Fix=20drag=20select=20i?= =?UTF-8?q?ndex=20accuracy=20when=20asset=20size=20is=20one=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...asset_grid_drag_selection_coordinator.dart | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 1f85d2ff..6a767470 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -130,6 +130,15 @@ class AssetGridDragSelectionCoordinator { } } + final double dividedSpacing = delegate.itemSpacing / gridCount; + final double anchor = math.min( + (maxRow * (itemSize + dividedSpacing) + + topPadding - + delegate.itemSpacing) / + dimensionSize.height, + 1, + ); + int rowIndex = _getDragPositionIndex( switch (gridRevert) { true => dimensionSize.height - @@ -143,20 +152,19 @@ class AssetGridDragSelectionCoordinator { itemSize, ); - if (placeholderCount > 0) { - rowIndex -= 1; + final double initialFirstPosition = dimensionSize.height * anchor; + if (gridRevert && dimensionSize.height > initialFirstPosition) { + final deductedRow = + (dimensionSize.height - initialFirstPosition) ~/ itemSize; + rowIndex -= deductedRow; } - // Correct the row index when asset length is less than one page - if (maxRowPerPage > maxRow) { - rowIndex = maxRow - (maxRowPerPage - rowIndex); + if (placeholderCount > 0 && maxRow > maxRowPerPage) { + rowIndex -= 1; } final currentDragIndex = rowIndex * gridCount + columnIndex; - print( - "Check drag index: $currentDragIndex | $initialSelectingIndex | $rowIndex | $columnIndex"); - // Check the selecting index in order to diff unselecting assets. smallestSelectingIndex = math.min( currentDragIndex, @@ -164,7 +172,7 @@ class AssetGridDragSelectionCoordinator { ); smallestSelectingIndex = math.max(0, smallestSelectingIndex); largestSelectingIndex = math.max( - currentDragIndex + 1, + currentDragIndex, largestSelectingIndex, ); @@ -191,7 +199,7 @@ class AssetGridDragSelectionCoordinator { filteredAssetList = provider.currentAssets.getRange( math.max(0, initialSelectingIndex), math.min( - currentDragIndex + 1, + currentDragIndex + (maxRow > maxRowPerPage ? 1 : 0), provider.currentAssets.length, ), ); From f39b2baa2697bf8f538df26db2e94ec47d11cde7 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Mon, 30 Dec 2024 21:10:01 +0800 Subject: [PATCH 21/23] =?UTF-8?q?=20=F0=9F=90=9B=20Improve=20the=20accurac?= =?UTF-8?q?y=20of=20select=20asset=20on=20iOS=20device?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asset_grid_drag_selection_coordinator.dart | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 6a767470..581677c8 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -119,10 +119,6 @@ class AssetGridDragSelectionCoordinator { placeholderCount = 0; } - final bottomGap = MediaQuery.paddingOf(context).bottom + - delegate.bottomSectionHeight - - (delegate.isAppleOS(context) ? delegate.permissionLimitedBarHeight : 0); - if (gridRevert) { columnIndex = gridCount - columnIndex - placeholderCount; if (maxRow > maxRowPerPage) { @@ -139,6 +135,14 @@ class AssetGridDragSelectionCoordinator { 1, ); + final bottomGap = anchor == 1.0 && delegate.isAppleOS(context) && gridRevert + ? delegate.bottomActionBarHeight + : MediaQuery.paddingOf(context).bottom + + delegate.bottomSectionHeight - + (delegate.isAppleOS(context) + ? delegate.permissionLimitedBarHeight + : 0); + int rowIndex = _getDragPositionIndex( switch (gridRevert) { true => dimensionSize.height - @@ -206,8 +210,8 @@ class AssetGridDragSelectionCoordinator { } final touchedAssets = List.from( provider.currentAssets.getRange( - smallestSelectingIndex, - largestSelectingIndex, + math.max(0, smallestSelectingIndex), + math.min(largestSelectingIndex + 1, provider.currentAssets.length), ), ); From 8580c40523ffae708548cafb7db8961727fcee79 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 31 Dec 2024 11:29:20 +0800 Subject: [PATCH 22/23] =?UTF-8?q?=F0=9F=90=9B=20Fix=20bottom=20gaps=20when?= =?UTF-8?q?=20grid=20reverting=20on=20Android?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/delegates/asset_picker_builder_delegate.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/delegates/asset_picker_builder_delegate.dart b/lib/src/delegates/asset_picker_builder_delegate.dart index ea12fa04..23d1d030 100644 --- a/lib/src/delegates/asset_picker_builder_delegate.dart +++ b/lib/src/delegates/asset_picker_builder_delegate.dart @@ -1447,13 +1447,14 @@ class DefaultAssetPickerBuilderDelegate ), sliverGrid(context, assets), // Ignore the gap when the [anchor] is not equal to 1. - if (gridRevert && anchor == 1) bottomGap, + if (gridRevert && isAppleOS(context) && anchor == 1) + bottomGap, if (gridRevert) SliverToBoxAdapter( key: gridRevertKey, child: const SizedBox.shrink(), ), - if (isAppleOS(context) && !gridRevert) bottomGap, + if (!gridRevert && isAppleOS(context)) bottomGap, ], ); }, From 60239f6c669b806aa8a4b977da86aa37130d1ee9 Mon Sep 17 00:00:00 2001 From: WeiJun0507 Date: Sat, 4 Jan 2025 23:38:37 +0800 Subject: [PATCH 23/23] =?UTF-8?q?=F0=9F=90=9B=20Improve=20the=20accuracy?= =?UTF-8?q?=20of=20select=20asset=20on=20iOS=20device?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delegates/asset_grid_drag_selection_coordinator.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart index 581677c8..4a3f3400 100644 --- a/lib/src/delegates/asset_grid_drag_selection_coordinator.dart +++ b/lib/src/delegates/asset_grid_drag_selection_coordinator.dart @@ -163,7 +163,10 @@ class AssetGridDragSelectionCoordinator { rowIndex -= deductedRow; } - if (placeholderCount > 0 && maxRow > maxRowPerPage) { + if (placeholderCount > 0 && + maxRow > maxRowPerPage && + rowIndex > 0 && + anchor < 1.0) { rowIndex -= 1; } @@ -226,7 +229,8 @@ class AssetGridDragSelectionCoordinator { } final stopAutoScroll = switch (addSelected) { - true => provider.selectedAssets.length == provider.maxAssets, + true => provider.selectedAssets.length == provider.maxAssets || + (gridRevert && delegate.gridScrollController.offset == 0.0), false => provider.selectedAssets.isEmpty, };