mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: add documentation
This commit is contained in:
parent
9e4dbc53f7
commit
8ca1cc0a21
@ -95,7 +95,7 @@ class BoardContent extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
final BoardColumnFooterBuilder? footBuilder;
|
final BoardColumnFooterBuilder? footBuilder;
|
||||||
|
|
||||||
final OverlapReorderFlexDragTargetDelegate delegate;
|
final OverlapDragTargetDelegate delegate;
|
||||||
|
|
||||||
final BoardPhantomController phantomController;
|
final BoardPhantomController phantomController;
|
||||||
|
|
||||||
@ -122,15 +122,14 @@ class BoardContent extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _BoardContentState extends State<BoardContent> {
|
class _BoardContentState extends State<BoardContent> {
|
||||||
final GlobalKey _columnContainerOverlayKey =
|
final GlobalKey _columnContainerOverlayKey = GlobalKey(debugLabel: '$BoardContent overlay key');
|
||||||
GlobalKey(debugLabel: '$BoardContent overlay key');
|
|
||||||
late BoardOverlayEntry _overlayEntry;
|
late BoardOverlayEntry _overlayEntry;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_overlayEntry = BoardOverlayEntry(
|
_overlayEntry = BoardOverlayEntry(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
final interceptor = OverlapReorderFlexDragTargetInteceptor(
|
final interceptor = OverlappingDragTargetInteceptor(
|
||||||
reorderFlexId: widget.dataController.identifier,
|
reorderFlexId: widget.dataController.identifier,
|
||||||
acceptedReorderFlexId: widget.dataController.columnIds,
|
acceptedReorderFlexId: widget.dataController.columnIds,
|
||||||
delegate: widget.delegate,
|
delegate: widget.delegate,
|
||||||
@ -216,8 +215,7 @@ class _BoardColumnDataSourceImpl extends BoardColumnDataDataSource {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
BoardColumnData get columnData =>
|
BoardColumnData get columnData => dataController.columnController(columnId).columnData;
|
||||||
dataController.columnController(columnId).columnData;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<String> get acceptedColumnIds => dataController.columnIds;
|
List<String> get acceptedColumnIds => dataController.columnIds;
|
||||||
|
@ -46,16 +46,12 @@ class DraggingState {
|
|||||||
final String id;
|
final String id;
|
||||||
|
|
||||||
/// The member of widget.children currently being dragged.
|
/// The member of widget.children currently being dragged.
|
||||||
///
|
|
||||||
/// Null if no drag is underway.
|
|
||||||
Widget? _draggingWidget;
|
Widget? _draggingWidget;
|
||||||
|
|
||||||
Widget? get draggingWidget => _draggingWidget;
|
Widget? get draggingWidget => _draggingWidget;
|
||||||
|
|
||||||
/// The last computed size of the feedback widget being dragged.
|
/// The last computed size of the feedback widget being dragged.
|
||||||
Size? _draggingFeedbackSize = Size.zero;
|
Size? feedbackSize = Size.zero;
|
||||||
|
|
||||||
Size? get feedbackSize => _draggingFeedbackSize;
|
|
||||||
|
|
||||||
/// The location that the dragging widget occupied before it started to drag.
|
/// The location that the dragging widget occupied before it started to drag.
|
||||||
int dragStartIndex = -1;
|
int dragStartIndex = -1;
|
||||||
@ -79,15 +75,17 @@ class DraggingState {
|
|||||||
DraggingState(this.id);
|
DraggingState(this.id);
|
||||||
|
|
||||||
Size get dropAreaSize {
|
Size get dropAreaSize {
|
||||||
if (_draggingFeedbackSize == null) {
|
if (feedbackSize == null) {
|
||||||
return Size.zero;
|
return Size.zero;
|
||||||
}
|
}
|
||||||
return _draggingFeedbackSize! +
|
return feedbackSize! + const Offset(_dropAreaMargin, _dropAreaMargin);
|
||||||
const Offset(_dropAreaMargin, _dropAreaMargin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void startDragging(Widget draggingWidget, int draggingWidgetIndex,
|
void startDragging(
|
||||||
Size? draggingWidgetSize) {
|
Widget draggingWidget,
|
||||||
|
int draggingWidgetIndex,
|
||||||
|
Size? draggingWidgetSize,
|
||||||
|
) {
|
||||||
///
|
///
|
||||||
assert(draggingWidgetIndex >= 0);
|
assert(draggingWidgetIndex >= 0);
|
||||||
|
|
||||||
@ -95,7 +93,7 @@ class DraggingState {
|
|||||||
phantomIndex = draggingWidgetIndex;
|
phantomIndex = draggingWidgetIndex;
|
||||||
dragStartIndex = draggingWidgetIndex;
|
dragStartIndex = draggingWidgetIndex;
|
||||||
currentIndex = draggingWidgetIndex;
|
currentIndex = draggingWidgetIndex;
|
||||||
_draggingFeedbackSize = draggingWidgetSize;
|
feedbackSize = draggingWidgetSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void endDragging() {
|
void endDragging() {
|
||||||
@ -130,12 +128,10 @@ class DraggingState {
|
|||||||
|
|
||||||
/// Set the currentIndex to nextIndex
|
/// Set the currentIndex to nextIndex
|
||||||
void moveDragTargetToNext() {
|
void moveDragTargetToNext() {
|
||||||
Log.trace('moveDragTargetToNext: $nextIndex');
|
|
||||||
currentIndex = nextIndex;
|
currentIndex = nextIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateNextIndex(int index) {
|
void updateNextIndex(int index) {
|
||||||
assert(index >= 0);
|
|
||||||
Log.trace('updateNextIndex: $index');
|
Log.trace('updateNextIndex: $index');
|
||||||
nextIndex = index;
|
nextIndex = index;
|
||||||
}
|
}
|
||||||
|
@ -5,24 +5,18 @@ abstract class DragTargetData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class ReorderFlexDraggableTargetBuilder {
|
abstract class ReorderFlexDraggableTargetBuilder {
|
||||||
Widget? build<T extends DragTargetData>(
|
Widget? build<T extends DragTargetData>(BuildContext context, Widget child, DragTargetOnStarted onDragStarted,
|
||||||
BuildContext context,
|
DragTargetOnEnded<T> onDragEnded, DragTargetWillAccpet<T> onWillAccept);
|
||||||
Widget child,
|
|
||||||
DragTargetOnStarted onDragStarted,
|
|
||||||
DragTargetOnEnded<T> onDragEnded,
|
|
||||||
DragTargetWillAccpet<T> onWillAccept);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
typedef DragTargetWillAccpet<T extends DragTargetData> = bool Function(
|
typedef DragTargetWillAccpet<T extends DragTargetData> = bool Function(T dragTargetData);
|
||||||
T dragTargetData);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
typedef DragTargetOnStarted = void Function(Widget, int, Size?);
|
typedef DragTargetOnStarted = void Function(Widget, int, Size?);
|
||||||
|
|
||||||
///
|
///
|
||||||
typedef DragTargetOnEnded<T extends DragTargetData> = void Function(
|
typedef DragTargetOnEnded<T extends DragTargetData> = void Function(T dragTargetData);
|
||||||
T dragTargetData);
|
|
||||||
|
|
||||||
/// [ReorderDragTarget] is a [DragTarget] that carries the index information of
|
/// [ReorderDragTarget] is a [DragTarget] that carries the index information of
|
||||||
/// the child.
|
/// the child.
|
||||||
@ -75,8 +69,7 @@ class ReorderDragTarget<T extends DragTargetData> extends StatefulWidget {
|
|||||||
State<ReorderDragTarget<T>> createState() => _ReorderDragTargetState<T>();
|
State<ReorderDragTarget<T>> createState() => _ReorderDragTargetState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReorderDragTargetState<T extends DragTargetData>
|
class _ReorderDragTargetState<T extends DragTargetData> extends State<ReorderDragTarget<T>> {
|
||||||
extends State<ReorderDragTarget<T>> {
|
|
||||||
/// Returns the dragTarget's size
|
/// Returns the dragTarget's size
|
||||||
Size? _draggingFeedbackSize = Size.zero;
|
Size? _draggingFeedbackSize = Size.zero;
|
||||||
|
|
||||||
@ -108,8 +101,7 @@ class _ReorderDragTargetState<T extends DragTargetData>
|
|||||||
List<dynamic> rejectedCandidates,
|
List<dynamic> rejectedCandidates,
|
||||||
) {
|
) {
|
||||||
Widget feedbackBuilder = Builder(builder: (BuildContext context) {
|
Widget feedbackBuilder = Builder(builder: (BuildContext context) {
|
||||||
BoxConstraints contentSizeConstraints =
|
BoxConstraints contentSizeConstraints = BoxConstraints.loose(_draggingFeedbackSize!);
|
||||||
BoxConstraints.loose(_draggingFeedbackSize!);
|
|
||||||
return _buildDraggableFeedback(
|
return _buildDraggableFeedback(
|
||||||
context,
|
context,
|
||||||
contentSizeConstraints,
|
contentSizeConstraints,
|
||||||
@ -149,21 +141,19 @@ class _ReorderDragTargetState<T extends DragTargetData>
|
|||||||
/// When the drag does not end inside a DragTarget widget, the
|
/// When the drag does not end inside a DragTarget widget, the
|
||||||
/// drag fails, but we still reorder the widget to the last position it
|
/// drag fails, but we still reorder the widget to the last position it
|
||||||
/// had been dragged to.
|
/// had been dragged to.
|
||||||
onDraggableCanceled: (Velocity velocity, Offset offset) =>
|
onDraggableCanceled: (Velocity velocity, Offset offset) => widget.onDragEnded(widget.dragTargetData),
|
||||||
widget.onDragEnded(widget.dragTargetData),
|
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
);
|
);
|
||||||
|
|
||||||
return draggableWidget;
|
return draggableWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDraggableFeedback(
|
Widget _buildDraggableFeedback(BuildContext context, BoxConstraints constraints, Widget child) {
|
||||||
BuildContext context, BoxConstraints constraints, Widget child) {
|
|
||||||
return Transform(
|
return Transform(
|
||||||
transform: Matrix4.rotationZ(0),
|
transform: Matrix4.rotationZ(0),
|
||||||
alignment: FractionalOffset.topLeft,
|
alignment: FractionalOffset.topLeft,
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation: 6.0,
|
elevation: 2.0,
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.zero,
|
borderRadius: BorderRadius.zero,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
@ -177,10 +167,6 @@ class DragAnimationController {
|
|||||||
// How long an animation to reorder an element in the list takes.
|
// How long an animation to reorder an element in the list takes.
|
||||||
final Duration reorderAnimationDuration;
|
final Duration reorderAnimationDuration;
|
||||||
|
|
||||||
// How long an animation to scroll to an off-screen element in the
|
|
||||||
// list takes.
|
|
||||||
final Duration scrollAnimationDuration;
|
|
||||||
|
|
||||||
// This controls the entrance of the dragging widget into a new place.
|
// This controls the entrance of the dragging widget into a new place.
|
||||||
late AnimationController entranceController;
|
late AnimationController entranceController;
|
||||||
|
|
||||||
@ -190,14 +176,11 @@ class DragAnimationController {
|
|||||||
|
|
||||||
DragAnimationController({
|
DragAnimationController({
|
||||||
required this.reorderAnimationDuration,
|
required this.reorderAnimationDuration,
|
||||||
required this.scrollAnimationDuration,
|
|
||||||
required TickerProvider vsync,
|
required TickerProvider vsync,
|
||||||
required void Function(AnimationStatus) entranceAnimateStatusChanged,
|
required void Function(AnimationStatus) entranceAnimateStatusChanged,
|
||||||
}) {
|
}) {
|
||||||
entranceController = AnimationController(
|
entranceController = AnimationController(value: 1.0, vsync: vsync, duration: reorderAnimationDuration);
|
||||||
value: 1.0, vsync: vsync, duration: reorderAnimationDuration);
|
phantomController = AnimationController(value: 0, vsync: vsync, duration: reorderAnimationDuration);
|
||||||
phantomController = AnimationController(
|
|
||||||
value: 0, vsync: vsync, duration: reorderAnimationDuration);
|
|
||||||
entranceController.addStatusListener(entranceAnimateStatusChanged);
|
entranceController.addStatusListener(entranceAnimateStatusChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,9 +217,7 @@ class IgnorePointerWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final sizedChild = useIntrinsicSize
|
final sizedChild = useIntrinsicSize ? child : SizedBox(width: 0.0, height: 0.0, child: child);
|
||||||
? child
|
|
||||||
: SizedBox(width: 0.0, height: 0.0, child: child);
|
|
||||||
return IgnorePointer(
|
return IgnorePointer(
|
||||||
ignoring: true,
|
ignoring: true,
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
@ -276,10 +257,8 @@ class PhantomAnimateContorller {
|
|||||||
required this.reorderAnimationDuration,
|
required this.reorderAnimationDuration,
|
||||||
required void Function(AnimationStatus) appearAnimateStatusChanged,
|
required void Function(AnimationStatus) appearAnimateStatusChanged,
|
||||||
}) {
|
}) {
|
||||||
appearController = AnimationController(
|
appearController = AnimationController(value: 1.0, vsync: vsync, duration: reorderAnimationDuration);
|
||||||
value: 1.0, vsync: vsync, duration: reorderAnimationDuration);
|
disappearController = AnimationController(value: 0, vsync: vsync, duration: reorderAnimationDuration);
|
||||||
disappearController = AnimationController(
|
|
||||||
value: 0, vsync: vsync, duration: reorderAnimationDuration);
|
|
||||||
appearController.addStatusListener(appearAnimateStatusChanged);
|
appearController.addStatusListener(appearAnimateStatusChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,8 +312,7 @@ class FakeDragTarget<T extends DragTargetData> extends StatefulWidget {
|
|||||||
State<FakeDragTarget<T>> createState() => _FakeDragTargetState<T>();
|
State<FakeDragTarget<T>> createState() => _FakeDragTargetState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FakeDragTargetState<T extends DragTargetData>
|
class _FakeDragTargetState<T extends DragTargetData> extends State<FakeDragTarget<T>> {
|
||||||
extends State<FakeDragTarget<T>> {
|
|
||||||
bool isDragging = false;
|
bool isDragging = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -5,9 +5,13 @@ import 'drag_state.dart';
|
|||||||
import 'drag_target.dart';
|
import 'drag_target.dart';
|
||||||
import 'reorder_flex.dart';
|
import 'reorder_flex.dart';
|
||||||
|
|
||||||
abstract class ReorderFlexDragTargetInterceptor {
|
/// [DragTargetInterceptor] is used to intercept the [DragTarget]'s
|
||||||
|
/// [onWillAccept], [OnAccept], and [onLeave] event.
|
||||||
|
abstract class DragTargetInterceptor {
|
||||||
|
/// Returns [yes] to receive the [DragTarget]'s event.
|
||||||
bool canHandler(FlexDragTargetData dragTargetData);
|
bool canHandler(FlexDragTargetData dragTargetData);
|
||||||
|
|
||||||
|
/// Handle the [DragTarget]'s [onWillAccept] event.
|
||||||
bool onWillAccept({
|
bool onWillAccept({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required ReorderFlexState reorderFlexState,
|
required ReorderFlexState reorderFlexState,
|
||||||
@ -16,29 +20,36 @@ abstract class ReorderFlexDragTargetInterceptor {
|
|||||||
required int dragTargetIndex,
|
required int dragTargetIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Handle the [DragTarget]'s [onAccept] event.
|
||||||
void onAccept(FlexDragTargetData dragTargetData) {}
|
void onAccept(FlexDragTargetData dragTargetData) {}
|
||||||
|
|
||||||
|
/// Handle the [DragTarget]'s [onLeave] event.
|
||||||
void onLeave(FlexDragTargetData dragTargetData) {}
|
void onLeave(FlexDragTargetData dragTargetData) {}
|
||||||
|
|
||||||
ReorderFlexDraggableTargetBuilder? get draggableTargetBuilder => null;
|
ReorderFlexDraggableTargetBuilder? get draggableTargetBuilder => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class OverlapReorderFlexDragTargetDelegate {
|
abstract class OverlapDragTargetDelegate {
|
||||||
void dragTargetDidDisappear();
|
void didReturnOriginalDragTarget();
|
||||||
bool acceptNewDragTargetData(
|
void didCrossOtherDragTarget(
|
||||||
String reorderFlexId,
|
String reorderFlexId,
|
||||||
FlexDragTargetData dragTargetData,
|
FlexDragTargetData dragTargetData,
|
||||||
int dragTargetIndex,
|
int dragTargetIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class OverlapReorderFlexDragTargetInteceptor
|
/// [OverlappingDragTargetInteceptor] is used to receive the overlapping
|
||||||
extends ReorderFlexDragTargetInterceptor {
|
/// [DragTarget] event. If a [DragTarget] child is [DragTarget], it will
|
||||||
|
/// receive the [DragTarget] event when being dragged.
|
||||||
|
///
|
||||||
|
/// Receive the [DragTarget] event if the [acceptedReorderFlexId] contains
|
||||||
|
/// the passed in dragTarget' reorderFlexId.
|
||||||
|
class OverlappingDragTargetInteceptor extends DragTargetInterceptor {
|
||||||
final String reorderFlexId;
|
final String reorderFlexId;
|
||||||
final List<String> acceptedReorderFlexId;
|
final List<String> acceptedReorderFlexId;
|
||||||
final OverlapReorderFlexDragTargetDelegate delegate;
|
final OverlapDragTargetDelegate delegate;
|
||||||
|
|
||||||
OverlapReorderFlexDragTargetInteceptor({
|
OverlappingDragTargetInteceptor({
|
||||||
required this.delegate,
|
required this.delegate,
|
||||||
required this.reorderFlexId,
|
required this.reorderFlexId,
|
||||||
required this.acceptedReorderFlexId,
|
required this.acceptedReorderFlexId,
|
||||||
@ -57,9 +68,9 @@ class OverlapReorderFlexDragTargetInteceptor
|
|||||||
required String dragTargetId,
|
required String dragTargetId,
|
||||||
required int dragTargetIndex}) {
|
required int dragTargetIndex}) {
|
||||||
if (dragTargetId == dragTargetData.reorderFlexId) {
|
if (dragTargetId == dragTargetData.reorderFlexId) {
|
||||||
delegate.dragTargetDidDisappear();
|
delegate.didReturnOriginalDragTarget();
|
||||||
} else {
|
} else {
|
||||||
delegate.acceptNewDragTargetData(
|
delegate.didCrossOtherDragTarget(
|
||||||
dragTargetId,
|
dragTargetId,
|
||||||
dragTargetData,
|
dragTargetData,
|
||||||
dragTargetIndex,
|
dragTargetIndex,
|
||||||
@ -84,8 +95,7 @@ abstract class CrossReorderFlexDragTargetDelegate {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class CrossReorderFlexDragTargetInterceptor
|
class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor {
|
||||||
extends ReorderFlexDragTargetInterceptor {
|
|
||||||
final String reorderFlexId;
|
final String reorderFlexId;
|
||||||
final List<String> acceptedReorderFlexIds;
|
final List<String> acceptedReorderFlexIds;
|
||||||
final CrossReorderFlexDragTargetDelegate delegate;
|
final CrossReorderFlexDragTargetDelegate delegate;
|
||||||
@ -117,14 +127,12 @@ class CrossReorderFlexDragTargetInterceptor
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onAccept(FlexDragTargetData dragTargetData) {
|
void onAccept(FlexDragTargetData dragTargetData) {
|
||||||
Log.trace(
|
Log.trace('[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on onAccept');
|
||||||
'[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on onAccept');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onLeave(FlexDragTargetData dragTargetData) {
|
void onLeave(FlexDragTargetData dragTargetData) {
|
||||||
Log.trace(
|
Log.trace('[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on leave');
|
||||||
'[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on leave');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -14,26 +14,34 @@ typedef OnDragEnded = void Function();
|
|||||||
typedef OnReorder = void Function(int fromIndex, int toIndex);
|
typedef OnReorder = void Function(int fromIndex, int toIndex);
|
||||||
typedef OnDeleted = void Function(int deletedIndex);
|
typedef OnDeleted = void Function(int deletedIndex);
|
||||||
typedef OnInserted = void Function(int insertedIndex);
|
typedef OnInserted = void Function(int insertedIndex);
|
||||||
typedef OnReveivePassedInPhantom = void Function(
|
typedef OnReveivePassedInPhantom = void Function(FlexDragTargetData dragTargetData, int phantomIndex);
|
||||||
FlexDragTargetData dragTargetData, int phantomIndex);
|
|
||||||
|
|
||||||
abstract class ReoderFlextDataSource {
|
abstract class ReoderFlextDataSource {
|
||||||
|
/// [identifier] represents the id the [ReorderFlex]. It must be unique.
|
||||||
String get identifier;
|
String get identifier;
|
||||||
|
|
||||||
|
/// The number of [ReoderFlexItem]s will be displaied in the [ReorderFlex].
|
||||||
UnmodifiableListView<ReoderFlexItem> get items;
|
UnmodifiableListView<ReoderFlexItem> get items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Each item displaied in the [ReorderFlex] required to implement the [ReoderFlexItem].
|
||||||
abstract class ReoderFlexItem {
|
abstract class ReoderFlexItem {
|
||||||
/// [id] is used to identify the item
|
/// [id] is used to identify the item. It must be unique.
|
||||||
String get id;
|
String get id;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReorderFlexConfig {
|
class ReorderFlexConfig {
|
||||||
final bool needsLongPressDraggable = true;
|
/// The opacity of the dragging widget
|
||||||
final double draggingWidgetOpacity = 0.2;
|
final double draggingWidgetOpacity = 0.2;
|
||||||
|
|
||||||
|
// How long an animation to reorder an element
|
||||||
final Duration reorderAnimationDuration = const Duration(milliseconds: 250);
|
final Duration reorderAnimationDuration = const Duration(milliseconds: 250);
|
||||||
|
|
||||||
|
// How long an animation to scroll to an off-screen element
|
||||||
final Duration scrollAnimationDuration = const Duration(milliseconds: 250);
|
final Duration scrollAnimationDuration = const Duration(milliseconds: 250);
|
||||||
|
|
||||||
final double? spacing;
|
final double? spacing;
|
||||||
|
|
||||||
const ReorderFlexConfig({this.spacing});
|
const ReorderFlexConfig({this.spacing});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,17 +50,25 @@ class ReorderFlex extends StatefulWidget {
|
|||||||
|
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
final EdgeInsets? padding;
|
final EdgeInsets? padding;
|
||||||
|
|
||||||
|
/// [direction] How to place the children, default is Axis.vertical
|
||||||
final Axis direction;
|
final Axis direction;
|
||||||
final MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start;
|
final MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start;
|
||||||
|
|
||||||
final ScrollController? scrollController;
|
final ScrollController? scrollController;
|
||||||
|
|
||||||
|
/// [onDragStarted] is called when start dragging
|
||||||
final OnDragStarted? onDragStarted;
|
final OnDragStarted? onDragStarted;
|
||||||
|
|
||||||
|
/// [onReorder] is called when dragTarget did end dragging
|
||||||
final OnReorder onReorder;
|
final OnReorder onReorder;
|
||||||
|
|
||||||
|
/// [onDragEnded] is called when dragTarget did end dragging
|
||||||
final OnDragEnded? onDragEnded;
|
final OnDragEnded? onDragEnded;
|
||||||
|
|
||||||
final ReoderFlextDataSource dataSource;
|
final ReoderFlextDataSource dataSource;
|
||||||
|
|
||||||
final ReorderFlexDragTargetInterceptor? interceptor;
|
final DragTargetInterceptor? interceptor;
|
||||||
|
|
||||||
const ReorderFlex({
|
const ReorderFlex({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -74,16 +90,20 @@ class ReorderFlex extends StatefulWidget {
|
|||||||
String get reorderFlexId => dataSource.identifier;
|
String get reorderFlexId => dataSource.identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReorderFlexState extends State<ReorderFlex>
|
class ReorderFlexState extends State<ReorderFlex> with ReorderFlexMinxi, TickerProviderStateMixin<ReorderFlex> {
|
||||||
with ReorderFlexMinxi, TickerProviderStateMixin<ReorderFlex> {
|
|
||||||
/// Controls scrolls and measures scroll progress.
|
/// Controls scrolls and measures scroll progress.
|
||||||
late ScrollController _scrollController;
|
late ScrollController _scrollController;
|
||||||
|
|
||||||
|
/// Records the position of the [Scrollable]
|
||||||
ScrollPosition? _attachedScrollPosition;
|
ScrollPosition? _attachedScrollPosition;
|
||||||
|
|
||||||
/// Whether or not we are currently scrolling this view to show a widget.
|
/// Whether or not we are currently scrolling this view to show a widget.
|
||||||
bool _scrolling = false;
|
bool _scrolling = false;
|
||||||
|
|
||||||
|
/// [dragState] records the dragging state including dragStartIndex, and phantomIndex, etc.
|
||||||
late DraggingState dragState;
|
late DraggingState dragState;
|
||||||
|
|
||||||
|
/// [_dragAnimationController] controls the dragging animations
|
||||||
late DragAnimationController _dragAnimationController;
|
late DragAnimationController _dragAnimationController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -92,7 +112,6 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
|
|
||||||
_dragAnimationController = DragAnimationController(
|
_dragAnimationController = DragAnimationController(
|
||||||
reorderAnimationDuration: widget.config.reorderAnimationDuration,
|
reorderAnimationDuration: widget.config.reorderAnimationDuration,
|
||||||
scrollAnimationDuration: widget.config.scrollAnimationDuration,
|
|
||||||
entranceAnimateStatusChanged: (status) {
|
entranceAnimateStatusChanged: (status) {
|
||||||
if (status == AnimationStatus.completed) {
|
if (status == AnimationStatus.completed) {
|
||||||
setState(() => _requestAnimationToNextIndex());
|
setState(() => _requestAnimationToNextIndex());
|
||||||
@ -111,9 +130,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
_attachedScrollPosition = null;
|
_attachedScrollPosition = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_scrollController = widget.scrollController ??
|
_scrollController = widget.scrollController ?? PrimaryScrollController.of(context) ?? ScrollController();
|
||||||
PrimaryScrollController.of(context) ??
|
|
||||||
ScrollController();
|
|
||||||
|
|
||||||
if (_scrollController.hasClients) {
|
if (_scrollController.hasClients) {
|
||||||
_attachedScrollPosition = Scrollable.of(context)?.position;
|
_attachedScrollPosition = Scrollable.of(context)?.position;
|
||||||
@ -235,9 +252,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
]);
|
]);
|
||||||
} else if (childIndex == dragPhantomIndex) {
|
} else if (childIndex == dragPhantomIndex) {
|
||||||
return _buildDraggingContainer(
|
return _buildDraggingContainer(
|
||||||
children: shiftedIndex <= childIndex
|
children: shiftedIndex <= childIndex ? [dragTarget, disappearSpace] : [disappearSpace, dragTarget]);
|
||||||
? [dragTarget, disappearSpace]
|
|
||||||
: [disappearSpace, dragTarget]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,9 +273,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
]);
|
]);
|
||||||
} else if (childIndex == dragPhantomIndex) {
|
} else if (childIndex == dragPhantomIndex) {
|
||||||
return _buildDraggingContainer(
|
return _buildDraggingContainer(
|
||||||
children: shiftedIndex >= childIndex
|
children: shiftedIndex >= childIndex ? [disappearSpace, dragTarget] : [dragTarget, disappearSpace]);
|
||||||
? [disappearSpace, dragTarget]
|
|
||||||
: [dragTarget, disappearSpace]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,8 +299,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
Widget child,
|
Widget child,
|
||||||
int dragTargetIndex,
|
int dragTargetIndex,
|
||||||
) {
|
) {
|
||||||
final ReoderFlexItem reorderFlexItem =
|
final ReoderFlexItem reorderFlexItem = widget.dataSource.items[dragTargetIndex];
|
||||||
widget.dataSource.items[dragTargetIndex];
|
|
||||||
return ReorderDragTarget<FlexDragTargetData>(
|
return ReorderDragTarget<FlexDragTargetData>(
|
||||||
dragTargetData: FlexDragTargetData(
|
dragTargetData: FlexDragTargetData(
|
||||||
draggingIndex: dragTargetIndex,
|
draggingIndex: dragTargetIndex,
|
||||||
@ -297,14 +309,12 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
dragTargetId: reorderFlexItem.id,
|
dragTargetId: reorderFlexItem.id,
|
||||||
),
|
),
|
||||||
onDragStarted: (draggingWidget, draggingIndex, size) {
|
onDragStarted: (draggingWidget, draggingIndex, size) {
|
||||||
Log.debug(
|
Log.debug("[DragTarget] Column${widget.dataSource.identifier} start dragging");
|
||||||
"[DragTarget] Column${widget.dataSource.identifier} start dragging");
|
|
||||||
_startDragging(draggingWidget, draggingIndex, size);
|
_startDragging(draggingWidget, draggingIndex, size);
|
||||||
widget.onDragStarted?.call(draggingIndex);
|
widget.onDragStarted?.call(draggingIndex);
|
||||||
},
|
},
|
||||||
onDragEnded: (dragTargetData) {
|
onDragEnded: (dragTargetData) {
|
||||||
Log.debug(
|
Log.debug("[DragTarget]: Column${widget.dataSource.identifier} end dragging");
|
||||||
"[DragTarget]: Column${widget.dataSource.identifier} end dragging");
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_onReordered(
|
_onReordered(
|
||||||
@ -352,7 +362,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
|
|
||||||
bool _interceptDragTarget(
|
bool _interceptDragTarget(
|
||||||
FlexDragTargetData dragTargetData,
|
FlexDragTargetData dragTargetData,
|
||||||
void Function(ReorderFlexDragTargetInterceptor) callback,
|
void Function(DragTargetInterceptor) callback,
|
||||||
) {
|
) {
|
||||||
final interceptor = widget.interceptor;
|
final interceptor = widget.interceptor;
|
||||||
if (interceptor != null && interceptor.canHandler(dragTargetData)) {
|
if (interceptor != null && interceptor.canHandler(dragTargetData)) {
|
||||||
@ -401,8 +411,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
Log.trace(
|
Log.trace(
|
||||||
'[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, dragIndex:$dragIndex, dragTargetIndex:$dragTargetIndex, count: ${widget.dataSource.items.length}');
|
'[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, dragIndex:$dragIndex, dragTargetIndex:$dragTargetIndex, count: ${widget.dataSource.items.length}');
|
||||||
|
|
||||||
bool willAccept =
|
bool willAccept = dragState.dragStartIndex == dragIndex && dragIndex != dragTargetIndex;
|
||||||
dragState.dragStartIndex == dragIndex && dragIndex != dragTargetIndex;
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if (willAccept) {
|
if (willAccept) {
|
||||||
int shiftedIndex = dragState.calculateShiftedIndex(dragTargetIndex);
|
int shiftedIndex = dragState.calculateShiftedIndex(dragTargetIndex);
|
||||||
@ -429,8 +438,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _wrapScrollView({required Widget child}) {
|
Widget _wrapScrollView({required Widget child}) {
|
||||||
if (widget.scrollController != null &&
|
if (widget.scrollController != null && PrimaryScrollController.of(context) == null) {
|
||||||
PrimaryScrollController.of(context) == null) {
|
|
||||||
return child;
|
return child;
|
||||||
} else {
|
} else {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
@ -484,14 +492,12 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
void _scrollTo(BuildContext context) {
|
void _scrollTo(BuildContext context) {
|
||||||
if (_scrolling) return;
|
if (_scrolling) return;
|
||||||
final RenderObject contextObject = context.findRenderObject()!;
|
final RenderObject contextObject = context.findRenderObject()!;
|
||||||
final RenderAbstractViewport viewport =
|
final RenderAbstractViewport viewport = RenderAbstractViewport.of(contextObject)!;
|
||||||
RenderAbstractViewport.of(contextObject)!;
|
|
||||||
// If and only if the current scroll offset falls in-between the offsets
|
// If and only if the current scroll offset falls in-between the offsets
|
||||||
// necessary to reveal the selected context at the top or bottom of the
|
// necessary to reveal the selected context at the top or bottom of the
|
||||||
// screen, then it is already on-screen.
|
// screen, then it is already on-screen.
|
||||||
final double margin = widget.direction == Axis.horizontal
|
final double margin =
|
||||||
? dragState.dropAreaSize.width
|
widget.direction == Axis.horizontal ? dragState.dropAreaSize.width : dragState.dropAreaSize.height;
|
||||||
: dragState.dropAreaSize.height;
|
|
||||||
if (_scrollController.hasClients) {
|
if (_scrollController.hasClients) {
|
||||||
final double scrollOffset = _scrollController.offset;
|
final double scrollOffset = _scrollController.offset;
|
||||||
final double topOffset = max(
|
final double topOffset = max(
|
||||||
@ -502,8 +508,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
_scrollController.position.maxScrollExtent,
|
_scrollController.position.maxScrollExtent,
|
||||||
viewport.getOffsetToReveal(contextObject, 1.0).offset + margin,
|
viewport.getOffsetToReveal(contextObject, 1.0).offset + margin,
|
||||||
);
|
);
|
||||||
final bool onScreen =
|
final bool onScreen = scrollOffset <= topOffset && scrollOffset >= bottomOffset;
|
||||||
scrollOffset <= topOffset && scrollOffset >= bottomOffset;
|
|
||||||
|
|
||||||
// If the context is off screen, then we request a scroll to make it visible.
|
// If the context is off screen, then we request a scroll to make it visible.
|
||||||
if (!onScreen) {
|
if (!onScreen) {
|
||||||
@ -511,7 +516,7 @@ class ReorderFlexState extends State<ReorderFlex>
|
|||||||
_scrollController.position
|
_scrollController.position
|
||||||
.animateTo(
|
.animateTo(
|
||||||
scrollOffset < bottomOffset ? bottomOffset : topOffset,
|
scrollOffset < bottomOffset ? bottomOffset : topOffset,
|
||||||
duration: _dragAnimationController.scrollAnimationDuration,
|
duration: widget.config.scrollAnimationDuration,
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
)
|
)
|
||||||
.then((void value) {
|
.then((void value) {
|
||||||
|
@ -34,8 +34,7 @@ abstract class BoardPhantomControllerDelegate {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate
|
class BoardPhantomController extends OverlapDragTargetDelegate with CrossReorderFlexDragTargetDelegate {
|
||||||
with CrossReorderFlexDragTargetDelegate {
|
|
||||||
PhantomRecord? phantomRecord;
|
PhantomRecord? phantomRecord;
|
||||||
final BoardPhantomControllerDelegate delegate;
|
final BoardPhantomControllerDelegate delegate;
|
||||||
final columnsState = ColumnPhantomStateController();
|
final columnsState = ColumnPhantomStateController();
|
||||||
@ -117,8 +116,7 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate
|
|||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Future.delayed(const Duration(milliseconds: 100), () {
|
Future.delayed(const Duration(milliseconds: 100), () {
|
||||||
Log.debug(
|
Log.debug('[$BoardPhantomController] notify $toColumnId to insert phantom');
|
||||||
'[$BoardPhantomController] notify $toColumnId to insert phantom');
|
|
||||||
columnsState.notifyDidInsertPhantom(toColumnId);
|
columnsState.notifyDidInsertPhantom(toColumnId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -185,7 +183,7 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dragTargetDidDisappear() {
|
void didReturnOriginalDragTarget() {
|
||||||
if (phantomRecord == null) {
|
if (phantomRecord == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -193,6 +191,19 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate
|
|||||||
_removePhantom(phantomRecord!.toColumnId);
|
_removePhantom(phantomRecord!.toColumnId);
|
||||||
phantomRecord = null;
|
phantomRecord = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didCrossOtherDragTarget(
|
||||||
|
String reorderFlexId,
|
||||||
|
FlexDragTargetData dragTargetData,
|
||||||
|
int dragTargetIndex,
|
||||||
|
) {
|
||||||
|
acceptNewDragTargetData(
|
||||||
|
reorderFlexId,
|
||||||
|
dragTargetData,
|
||||||
|
dragTargetIndex,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use [PhantomRecord] to record where to remove the column item and where to
|
/// Use [PhantomRecord] to record where to remove the column item and where to
|
||||||
@ -221,8 +232,7 @@ class PhantomRecord {
|
|||||||
if (fromColumnIndex == index) {
|
if (fromColumnIndex == index) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.debug(
|
Log.debug('[$PhantomRecord] Update Column$fromColumnId remove position to $index');
|
||||||
'[$PhantomRecord] Update Column$fromColumnId remove position to $index');
|
|
||||||
fromColumnIndex = index;
|
fromColumnIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,8 +241,7 @@ class PhantomRecord {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.debug(
|
Log.debug('[$PhantomRecord] Column$toColumnId update position $toColumnIndex -> $index');
|
||||||
'[$PhantomRecord] Column$toColumnId update position $toColumnIndex -> $index');
|
|
||||||
toColumnIndex = index;
|
toColumnIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,8 +254,7 @@ class PhantomRecord {
|
|||||||
class PhantomColumnItem extends ColumnItem {
|
class PhantomColumnItem extends ColumnItem {
|
||||||
final PassthroughPhantomContext phantomContext;
|
final PassthroughPhantomContext phantomContext;
|
||||||
|
|
||||||
PhantomColumnItem(PassthroughPhantomContext insertedPhantom)
|
PhantomColumnItem(PassthroughPhantomContext insertedPhantom) : phantomContext = insertedPhantom;
|
||||||
: phantomContext = insertedPhantom;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isPhantom => true;
|
bool get isPhantom => true;
|
||||||
@ -256,9 +264,8 @@ class PhantomColumnItem extends ColumnItem {
|
|||||||
|
|
||||||
Size? get feedbackSize => phantomContext.feedbackSize;
|
Size? get feedbackSize => phantomContext.feedbackSize;
|
||||||
|
|
||||||
Widget get draggingWidget => phantomContext.draggingWidget == null
|
Widget get draggingWidget =>
|
||||||
? const SizedBox()
|
phantomContext.draggingWidget == null ? const SizedBox() : phantomContext.draggingWidget!;
|
||||||
: phantomContext.draggingWidget!;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -97,13 +97,7 @@ class PhantomInsertNotifier extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PhantomDeleteNotifier extends ChangeNotifier {
|
class PhantomDeleteNotifier extends ChangeNotifier {
|
||||||
// int deletedIndex = -1;
|
|
||||||
|
|
||||||
void remove() {
|
void remove() {
|
||||||
// if (this.deletedIndex != deletedIndex) {
|
|
||||||
// this.deletedIndex = deletedIndex;
|
|
||||||
// notifyListeners();
|
|
||||||
// }
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user