From aec5c3e8070d137c29f8c268c63137c5f7383b0d Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 23 Aug 2022 13:10:26 +0800 Subject: [PATCH 1/5] chore: fix insert animation --- .../packages/appflowy_board/CHANGELOG.md | 4 +- .../example/lib/multi_board_list_example.dart | 13 ++-- .../appflowy_board/lib/src/utils/log.dart | 8 +-- .../lib/src/widgets/board_data.dart | 3 +- .../src/widgets/reorder_flex/drag_state.dart | 6 +- .../src/widgets/reorder_flex/drag_target.dart | 10 ++- .../reorder_flex/drag_target_interceptor.dart | 22 ++++++- .../widgets/reorder_flex/reorder_flex.dart | 22 ++++--- .../reorder_phantom/phantom_controller.dart | 61 +++++++++++++------ .../reorder_phantom/phantom_state.dart | 20 +++--- 10 files changed, 111 insertions(+), 58 deletions(-) diff --git a/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md b/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md index 76f33711b1..fec474244d 100644 --- a/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md +++ b/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md @@ -6,11 +6,11 @@ * Update example * Add AppFlowy style widget -## 0.0.2 +# 0.0.2 * Update documentation -## 0.0.1 +# 0.0.1 * Support drag and drop column * Support drag and drop column items from one to another diff --git a/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart b/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart index 01aba725a5..218331d198 100644 --- a/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart +++ b/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart @@ -26,13 +26,18 @@ class _MultiBoardListExampleState extends State { List a = [ TextItem("Card 1"), TextItem("Card 2"), - // RichTextItem(title: "Card 3", subtitle: 'Aug 1, 2020 4:05 PM'), + RichTextItem(title: "Card 3", subtitle: 'Aug 1, 2020 4:05 PM'), TextItem("Card 4"), + TextItem("Card 5"), + TextItem("Card 6"), + RichTextItem(title: "Card 7", subtitle: 'Aug 1, 2020 4:05 PM'), + RichTextItem(title: "Card 8", subtitle: 'Aug 1, 2020 4:05 PM'), + TextItem("Card 9"), ]; final column1 = AFBoardColumnData(id: "To Do", items: a); final column2 = AFBoardColumnData(id: "In Progress", items: [ - // RichTextItem(title: "Card 5", subtitle: 'Aug 1, 2020 4:05 PM'), - // TextItem("Card 6"), + RichTextItem(title: "Card 10", subtitle: 'Aug 1, 2020 4:05 PM'), + TextItem("Card 11"), ]); final column3 = AFBoardColumnData(id: "Done", items: []); @@ -93,7 +98,7 @@ class _MultiBoardListExampleState extends State { return Align( alignment: Alignment.centerLeft, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 40), child: Text(item.s), ), ); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart index 20f810a966..d3b795f5f8 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart @@ -6,7 +6,7 @@ const DART_LOG = "Dart_LOG"; class Log { // static const enableLog = bool.hasEnvironment(DART_LOG); // static final shared = Log(); - static const enableLog = false; + static const enableLog = true; static void info(String? message) { if (enableLog) { @@ -16,19 +16,19 @@ class Log { static void debug(String? message) { if (enableLog) { - debugPrint('🐛[Debug]=> $message'); + debugPrint('🐛[Debug] - ${DateTime.now().second}=> $message'); } } static void warn(String? message) { if (enableLog) { - debugPrint('🐛[Warn]=> $message'); + debugPrint('🐛[Warn] - ${DateTime.now().second} => $message'); } } static void trace(String? message) { if (enableLog) { - // debugPrint('❗️[Trace]=> $message'); + debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); } } } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart index e8d5471939..d0d102cba3 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart @@ -197,7 +197,8 @@ class AFBoardDataController extends ChangeNotifier assert(index != -1); if (index != -1) { if (index != newIndex) { - // Log.debug('[$BoardPhantomController] update $toColumnId:$index to $toColumnId:$phantomIndex'); + Log.debug( + '[$BoardPhantomController] update $columnId:$index to $columnId:$newIndex'); final item = columnDataController.removeAt(index, notify: false); columnDataController.insert(newIndex, item, notify: false); } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart index f5f7250834..250a4eb020 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart @@ -43,7 +43,7 @@ class FlexDragTargetData extends DragTargetData { } class DraggingState { - final String id; + final String reorderFlexId; /// The member of widget.children currently being dragged. Widget? _draggingWidget; @@ -72,7 +72,7 @@ class DraggingState { /// The additional margin to place around a computed drop area. static const double _dropAreaMargin = 0.0; - DraggingState(this.id); + DraggingState(this.reorderFlexId); Size get dropAreaSize { if (feedbackSize == null) { @@ -132,7 +132,7 @@ class DraggingState { } void updateNextIndex(int index) { - Log.trace('updateNextIndex: $index'); + Log.trace('$reorderFlexId updateNextIndex: $index'); nextIndex = index; } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart index 132d3d9bc4..57bd7343d9 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart @@ -1,3 +1,4 @@ +import 'package:appflowy_board/src/utils/log.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:provider/provider.dart'; @@ -222,10 +223,10 @@ class DragTargetAnimation { value: 0, vsync: vsync, duration: reorderAnimationDuration); insertController = AnimationController( - value: 0.0, vsync: vsync, duration: const Duration(milliseconds: 100)); + value: 0.0, vsync: vsync, duration: const Duration(milliseconds: 200)); deleteController = AnimationController( - value: 0.0, vsync: vsync, duration: const Duration(milliseconds: 10)); + value: 0.0, vsync: vsync, duration: const Duration(milliseconds: 1)); } void startDragging() { @@ -371,6 +372,7 @@ class _DragTargeMovePlaceholderState extends State { } abstract class FakeDragTargetEventTrigger { + void fakeOnDragStart(void Function(int?) callback); void fakeOnDragEnded(VoidCallback callback); } @@ -421,6 +423,10 @@ class _FakeDragTargetState /// Start insert animation widget.insertAnimationController.forward(from: 0.0); + widget.eventTrigger.fakeOnDragStart((insertIndex) { + Log.debug("[$FakeDragTarget] on drag $insertIndex"); + }); + widget.eventTrigger.fakeOnDragEnded(() { WidgetsBinding.instance.addPostFrameCallback((_) { widget.onDragEnded(widget.eventData.dragTargetData as T); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart index be74b4eef8..1438e396a4 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import '../../utils/log.dart'; @@ -8,6 +10,8 @@ import 'reorder_flex.dart'; /// [DragTargetInterceptor] is used to intercept the [DragTarget]'s /// [onWillAccept], [OnAccept], and [onLeave] event. abstract class DragTargetInterceptor { + String get reorderFlexId; + /// Returns [yes] to receive the [DragTarget]'s event. bool canHandler(FlexDragTargetData dragTargetData); @@ -37,7 +41,7 @@ abstract class OverlapDragTargetDelegate { int dragTargetIndex, ); - bool canMoveTo(String dragTargetId); + int canMoveTo(String dragTargetId); } /// [OverlappingDragTargetInterceptor] is used to receive the overlapping @@ -47,6 +51,7 @@ abstract class OverlapDragTargetDelegate { /// Receive the [DragTarget] event if the [acceptedReorderFlexId] contains /// the passed in dragTarget' reorderFlexId. class OverlappingDragTargetInterceptor extends DragTargetInterceptor { + @override final String reorderFlexId; final List acceptedReorderFlexId; final OverlapDragTargetDelegate delegate; @@ -72,8 +77,11 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor { if (dragTargetId == dragTargetData.reorderFlexId) { delegate.cancel(); } else { - if (delegate.canMoveTo(dragTargetId)) { - delegate.moveTo(dragTargetId, dragTargetData, 0); + final index = delegate.canMoveTo(dragTargetId); + Log.trace( + '[$OverlappingDragTargetInterceptor] move to $dragTargetId at $index'); + if (index != -1) { + delegate.moveTo(dragTargetId, dragTargetData, index); } } @@ -96,6 +104,7 @@ abstract class CrossReorderFlexDragTargetDelegate { } class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor { + @override final String reorderFlexId; final List acceptedReorderFlexIds; final CrossReorderFlexDragTargetDelegate delegate; @@ -119,8 +128,12 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor { /// If the columnId equal to the dragTargetData's columnId, /// it means the dragTarget is dragging on the top of its own list. /// Otherwise, it means the dargTarget was moved to another list. + Log.trace( + "[$CrossReorderFlexDragTargetInterceptor] $reorderFlexId accept ${dragTargetData.reorderFlexId} ${reorderFlexId != dragTargetData.reorderFlexId}"); return reorderFlexId != dragTargetData.reorderFlexId; } else { + Log.trace( + "[$CrossReorderFlexDragTargetInterceptor] not accept ${dragTargetData.reorderFlexId}"); return false; } } @@ -151,6 +164,9 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor { dragTargetIndex, ); + Log.debug( + '[$CrossReorderFlexDragTargetInterceptor] dargTargetIndex: $dragTargetIndex, reorderFlexId: $reorderFlexId'); + if (isNewDragTarget == false) { delegate.updateDragTargetData(reorderFlexId, dragTargetIndex); reorderFlexState.handleOnWillAccept(context, dragTargetIndex); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart index 7fa1a405e1..9916523782 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart @@ -36,10 +36,10 @@ class ReorderFlexConfig { final double draggingWidgetOpacity = 0.3; // How long an animation to reorder an element - final Duration reorderAnimationDuration = const Duration(milliseconds: 250); + final Duration reorderAnimationDuration = const Duration(milliseconds: 300); // How long an animation to scroll to an off-screen element - final Duration scrollAnimationDuration = const Duration(milliseconds: 250); + final Duration scrollAnimationDuration = const Duration(milliseconds: 300); final bool useMoveAnimation; @@ -213,8 +213,8 @@ class ReorderFlexState extends State shiftedIndex = dragState.calculateShiftedIndex(childIndex); } - Log.trace( - 'Rebuild: Column:[${dragState.id}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex'); + // Log.trace( + // 'Rebuild: Column:[${dragState.id}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex'); final currentIndex = dragState.currentIndex; final dragPhantomIndex = dragState.phantomIndex; @@ -330,6 +330,8 @@ class ReorderFlexState extends State widget.onDragStarted?.call(draggingIndex); }, onDragEnded: (dragTargetData) { + if (!mounted) return; + Log.debug( "[DragTarget]: Column:[${widget.dataSource.identifier}] end dragging"); _notifier.updateDragTargetIndex(-1); @@ -346,21 +348,21 @@ class ReorderFlexState extends State }); }, onWillAccept: (FlexDragTargetData dragTargetData) { + // Do not receive any events if the Insert item is animating. if (_animation.deleteController.isAnimating) { return false; } assert(widget.dataSource.items.length > dragTargetIndex); - if (_interceptDragTarget( - dragTargetData, - (interceptor) => interceptor.onWillAccept( + if (_interceptDragTarget(dragTargetData, (interceptor) { + interceptor.onWillAccept( context: builderContext, reorderFlexState: this, dragTargetData: dragTargetData, dragTargetId: reorderFlexItem.id, dragTargetIndex: dragTargetIndex, - ), - )) { + ); + })) { return true; } else { return handleOnWillAccept(builderContext, dragTargetIndex); @@ -524,7 +526,7 @@ class ReorderFlexState extends State // screen, then it is already on-screen. final double margin = widget.direction == Axis.horizontal ? dragState.dropAreaSize.width - : dragState.dropAreaSize.height; + : dragState.dropAreaSize.height / 2.0; if (_scrollController.hasClients) { final double scrollOffset = _scrollController.offset; final double topOffset = max( diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart index 0db70d0bae..42f356542b 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart @@ -59,12 +59,13 @@ class BoardPhantomController extends OverlapDragTargetDelegate } void columnStartDragging(String columnId) { - columnsState.setColumnIsDragging(columnId, false); + columnsState.setColumnIsDragging(columnId, true); } /// Remove the phantom in the column when the column is end dragging. void columnEndDragging(String columnId) { - columnsState.setColumnIsDragging(columnId, true); + columnsState.setColumnIsDragging(columnId, false); + if (phantomRecord == null) return; final fromColumnId = phantomRecord!.fromColumnId; @@ -73,19 +74,18 @@ class BoardPhantomController extends OverlapDragTargetDelegate columnsState.notifyDidRemovePhantom(toColumnId); } - if (columnsState.isDragging(fromColumnId) == false) { - return; + if (phantomRecord!.toColumnId == columnId) { + delegate.swapColumnItem( + fromColumnId, + phantomRecord!.fromColumnIndex, + toColumnId, + phantomRecord!.toColumnIndex, + ); + + Log.debug( + "[$BoardPhantomController] did move ${phantomRecord.toString()}"); + phantomRecord = null; } - - delegate.swapColumnItem( - fromColumnId, - phantomRecord!.fromColumnIndex, - toColumnId, - phantomRecord!.toColumnIndex, - ); - - Log.debug("[$BoardPhantomController] did move ${phantomRecord.toString()}"); - phantomRecord = null; } /// Remove the phantom in the column if it contains phantom @@ -113,7 +113,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate PhantomColumnItem(phantomContext), ); - columnsState.notifyDidInsertPhantom(toColumnId); + columnsState.notifyDidInsertPhantom(toColumnId, phantomIndex); } /// Reset or initial the [PhantomRecord] @@ -128,8 +128,9 @@ class BoardPhantomController extends OverlapDragTargetDelegate FlexDragTargetData dragTargetData, int dragTargetIndex, ) { - // Log.debug('[$BoardPhantomController] move Column:[${dragTargetData.reorderFlexId}]:${dragTargetData.draggingIndex} ' - // 'to Column:[$columnId]:$index'); + // Log.debug( + // '[$BoardPhantomController] move Column:[${dragTargetData.reorderFlexId}]:${dragTargetData.draggingIndex} ' + // 'to Column:[$columnId]:$dragTargetIndex'); phantomRecord = PhantomRecord( toColumnId: columnId, @@ -202,8 +203,23 @@ class BoardPhantomController extends OverlapDragTargetDelegate } @override - bool canMoveTo(String dragTargetId) { - return delegate.controller(dragTargetId)?.columnData.items.isEmpty ?? false; + int canMoveTo(String dragTargetId) { + // if (columnsState.isDragging(dragTargetId)) { + // return -1; + // } + + // final controller = delegate.controller(dragTargetId); + // if (controller != null) { + // return controller.columnData.items.length; + // } else { + // return 0; + // } + + if (delegate.controller(dragTargetId)?.columnData.items.isEmpty ?? false) { + return 0; + } else { + return -1; + } } } @@ -294,7 +310,7 @@ class PassthroughPhantomContext extends FakeDragTargetEventTrigger AFColumnItem get itemData => dragTargetData.reorderFlexItem as AFColumnItem; @override - VoidCallback? onInserted; + void Function(int?)? onInserted; @override VoidCallback? onDragEnded; @@ -308,6 +324,11 @@ class PassthroughPhantomContext extends FakeDragTargetEventTrigger void fakeOnDragEnded(VoidCallback callback) { onDragEnded = callback; } + + @override + void fakeOnDragStart(void Function(int? index) callback) { + onInserted = callback; + } } class PassthroughPhantomWidget extends PhantomWidget { diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart index d33b53500d..443d7fb936 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart @@ -14,7 +14,7 @@ class ColumnPhantomStateController { void addColumnListener(String columnId, PassthroughPhantomListener listener) { _stateWithId(columnId).notifier.addListener( - onInserted: (c) => listener.onInserted?.call(), + onInserted: (index) => listener.onInserted?.call(index), onDeleted: () => listener.onDragEnded?.call(), ); } @@ -24,8 +24,8 @@ class ColumnPhantomStateController { _states.remove(columnId); } - void notifyDidInsertPhantom(String columnId) { - _stateWithId(columnId).notifier.insert(); + void notifyDidInsertPhantom(String columnId, int index) { + _stateWithId(columnId).notifier.insert(index); } void notifyDidRemovePhantom(String columnId) { @@ -48,7 +48,7 @@ class ColumnState { } abstract class PassthroughPhantomListener { - VoidCallback? get onInserted; + void Function(int?)? get onInserted; VoidCallback? get onDragEnded; } @@ -57,8 +57,8 @@ class PassthroughPhantomNotifier { final removeNotifier = PhantomDeleteNotifier(); - void insert() { - insertNotifier.insert(); + void insert(int index) { + insertNotifier.insert(index); } void remove() { @@ -66,12 +66,12 @@ class PassthroughPhantomNotifier { } void addListener({ - void Function(PassthroughPhantomContext? insertedPhantom)? onInserted, + void Function(int? insertedIndex)? onInserted, void Function()? onDeleted, }) { if (onInserted != null) { insertNotifier.addListener(() { - onInserted(insertNotifier.insertedPhantom); + onInserted(insertNotifier.insertedIndex); }); } @@ -89,9 +89,11 @@ class PassthroughPhantomNotifier { } class PhantomInsertNotifier extends ChangeNotifier { + int insertedIndex = -1; PassthroughPhantomContext? insertedPhantom; - void insert() { + void insert(int index) { + insertedIndex = index; notifyListeners(); } } From d941db29a133f750583bc43fe905d7658424a6cb Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 23 Aug 2022 17:21:08 +0800 Subject: [PATCH 2/5] chore: disable children receive events under fake drag target --- .../src/widgets/reorder_flex/drag_target.dart | 29 +++++++++++++++++-- .../reorder_phantom/phantom_controller.dart | 18 ++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart index 57bd7343d9..621179455a 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart @@ -277,6 +277,31 @@ class IgnorePointerWidget extends StatelessWidget { } } +class AbsorbPointerWidget extends StatelessWidget { + final Widget? child; + final bool useIntrinsicSize; + const AbsorbPointerWidget({ + required this.child, + this.useIntrinsicSize = false, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final sizedChild = useIntrinsicSize + ? child + : SizedBox(width: 0.0, height: 0.0, child: child); + + final opacity = useIntrinsicSize ? 0.3 : 0.0; + return AbsorbPointer( + child: Opacity( + opacity: opacity, + child: sizedChild, + ), + ); + } +} + class PhantomWidget extends StatelessWidget { final Widget? child; final double opacity; @@ -442,7 +467,7 @@ class _FakeDragTargetState return SizeTransitionWithIntrinsicSize( sizeFactor: widget.deleteAnimationController, axis: Axis.vertical, - child: IgnorePointerWidget( + child: AbsorbPointerWidget( child: widget.child, ), ); @@ -450,7 +475,7 @@ class _FakeDragTargetState return SizeTransitionWithIntrinsicSize( sizeFactor: widget.insertAnimationController, axis: Axis.vertical, - child: IgnorePointerWidget( + child: AbsorbPointerWidget( useIntrinsicSize: true, child: widget.child, ), diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart index 42f356542b..45a7ce2392 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart @@ -204,16 +204,16 @@ class BoardPhantomController extends OverlapDragTargetDelegate @override int canMoveTo(String dragTargetId) { - // if (columnsState.isDragging(dragTargetId)) { - // return -1; - // } + if (columnsState.isDragging(dragTargetId)) { + return -1; + } - // final controller = delegate.controller(dragTargetId); - // if (controller != null) { - // return controller.columnData.items.length; - // } else { - // return 0; - // } + final controller = delegate.controller(dragTargetId); + if (controller != null) { + return controller.columnData.items.length; + } else { + return 0; + } if (delegate.controller(dragTargetId)?.columnData.items.isEmpty ?? false) { return 0; From 7be510fa22cd102386f05f476d3d4b50644d5d87 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 23 Aug 2022 17:44:53 +0800 Subject: [PATCH 3/5] chore: delay overlap dragtarget event --- .../appflowy_board/lib/src/utils/log.dart | 2 +- .../lib/src/widgets/board_data.dart | 2 +- .../reorder_flex/drag_target_interceptor.dart | 18 ++++++++++++------ .../src/widgets/reorder_flex/reorder_flex.dart | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart index d3b795f5f8..3d5baab30d 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart @@ -28,7 +28,7 @@ class Log { static void trace(String? message) { if (enableLog) { - debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); + // debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); } } } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart index d0d102cba3..a08bba378f 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_data.dart @@ -197,7 +197,7 @@ class AFBoardDataController extends ChangeNotifier assert(index != -1); if (index != -1) { if (index != newIndex) { - Log.debug( + Log.trace( '[$BoardPhantomController] update $columnId:$index to $columnId:$newIndex'); final item = columnDataController.removeAt(index, notify: false); columnDataController.insert(newIndex, item, notify: false); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart index 1438e396a4..d3a7e405e8 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart @@ -55,6 +55,7 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor { final String reorderFlexId; final List acceptedReorderFlexId; final OverlapDragTargetDelegate delegate; + Timer? _delayOperation; OverlappingDragTargetInterceptor({ required this.delegate, @@ -77,12 +78,17 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor { if (dragTargetId == dragTargetData.reorderFlexId) { delegate.cancel(); } else { - final index = delegate.canMoveTo(dragTargetId); - Log.trace( - '[$OverlappingDragTargetInterceptor] move to $dragTargetId at $index'); - if (index != -1) { - delegate.moveTo(dragTargetId, dragTargetData, index); - } + /// The priority of the column interactions is high than the cross column. + /// Workaround: delay 100 milliseconds to lower the cross column event priority. + _delayOperation?.cancel(); + _delayOperation = Timer(const Duration(milliseconds: 100), () { + final index = delegate.canMoveTo(dragTargetId); + if (index != -1) { + Log.trace( + '[$OverlappingDragTargetInterceptor] move to $dragTargetId at $index'); + delegate.moveTo(dragTargetId, dragTargetData, index); + } + }); } return true; diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart index 9916523782..f84fe8c991 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart @@ -437,7 +437,7 @@ class ReorderFlexState extends State /// The [willAccept] will be true if the dargTarget is the widget that gets /// dragged and it is dragged on top of the other dragTargets. /// - Log.debug( + Log.trace( '[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, dragIndex:$dragIndex, dragTargetIndex:$dragTargetIndex, count: ${widget.dataSource.items.length}'); bool willAccept = From 02e10301bf1a652ae5fd30f3c97c0897bc473ed8 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 23 Aug 2022 19:59:39 +0800 Subject: [PATCH 4/5] chore: update appflowy_board version --- frontend/app_flowy/packages/appflowy_board/CHANGELOG.md | 7 ++++++- frontend/app_flowy/packages/appflowy_board/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md b/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md index fec474244d..c4c6495533 100644 --- a/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md +++ b/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md @@ -1,5 +1,10 @@ +# 0.0.5 +* Optimize insert card animation +* Enable insert card at the end of the column +* Fix some bugs + # 0.0.4 -* fix some bugs +* Fix some bugs # 0.0.3 * Support customize UI diff --git a/frontend/app_flowy/packages/appflowy_board/pubspec.yaml b/frontend/app_flowy/packages/appflowy_board/pubspec.yaml index 962fc8be80..6bb2feabfe 100644 --- a/frontend/app_flowy/packages/appflowy_board/pubspec.yaml +++ b/frontend/app_flowy/packages/appflowy_board/pubspec.yaml @@ -1,6 +1,6 @@ name: appflowy_board description: AppFlowy board implementation. -version: 0.0.4 +version: 0.0.5 homepage: https://github.com/AppFlowy-IO/AppFlowy repository: https://github.com/AppFlowy-IO/AppFlowy/tree/main/frontend/app_flowy/packages/appflowy_board From 2152bb71882f63eb08443cd4833eec62c3c308b9 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 23 Aug 2022 20:00:07 +0800 Subject: [PATCH 5/5] chore: disable log and try to fix some weird bugs --- .../appflowy_board/lib/src/utils/log.dart | 6 +-- .../appflowy_board/lib/src/widgets/board.dart | 42 ++++++++++++------- .../widgets/board_column/board_column.dart | 11 +++-- .../src/widgets/reorder_flex/drag_state.dart | 2 +- .../src/widgets/reorder_flex/drag_target.dart | 7 ++-- .../reorder_flex/drag_target_interceptor.dart | 16 +++++++ .../widgets/reorder_flex/reorder_flex.dart | 4 +- .../reorder_phantom/phantom_controller.dart | 6 --- 8 files changed, 59 insertions(+), 35 deletions(-) diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart index 3d5baab30d..9c23060b26 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart @@ -4,9 +4,7 @@ import 'package:flutter/material.dart'; const DART_LOG = "Dart_LOG"; class Log { - // static const enableLog = bool.hasEnvironment(DART_LOG); - // static final shared = Log(); - static const enableLog = true; + static const enableLog = false; static void info(String? message) { if (enableLog) { @@ -28,7 +26,7 @@ class Log { static void trace(String? message) { if (enableLog) { - // debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); + debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); } } } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart index 20824ba6b9..e07ee39d61 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart @@ -159,7 +159,7 @@ class _BoardContentState extends State { dataSource: widget.dataController, direction: Axis.horizontal, interceptor: interceptor, - children: _buildColumns(), + children: _buildColumns(interceptor.columnKeys), ); return Stack( @@ -191,7 +191,7 @@ class _BoardContentState extends State { ); } - List _buildColumns() { + List _buildColumns(List columnKeys) { final List children = widget.dataController.columnDatas.asMap().entries.map( (item) { @@ -208,21 +208,33 @@ class _BoardContentState extends State { value: widget.dataController.columnController(columnData.id), child: Consumer( builder: (context, value, child) { + final boardColumn = AFBoardColumnWidget( + margin: _marginFromIndex(columnIndex), + itemMargin: widget.config.columnItemPadding, + headerBuilder: widget.headerBuilder, + footBuilder: widget.footBuilder, + cardBuilder: widget.cardBuilder, + dataSource: dataSource, + scrollController: ScrollController(), + phantomController: widget.phantomController, + onReorder: widget.dataController.moveColumnItem, + cornerRadius: widget.config.cornerRadius, + backgroundColor: widget.config.columnBackgroundColor, + ); + + // columnKeys + // .removeWhere((element) => element.columnId == columnData.id); + + // columnKeys.add( + // ColumnKey( + // columnId: columnData.id, + // key: boardColumn.columnGlobalKey, + // ), + // ); + return ConstrainedBox( constraints: widget.columnConstraints, - child: AFBoardColumnWidget( - margin: _marginFromIndex(columnIndex), - itemMargin: widget.config.columnItemPadding, - headerBuilder: widget.headerBuilder, - footBuilder: widget.footBuilder, - cardBuilder: widget.cardBuilder, - dataSource: dataSource, - scrollController: ScrollController(), - phantomController: widget.phantomController, - onReorder: widget.dataController.moveColumnItem, - cornerRadius: widget.config.cornerRadius, - backgroundColor: widget.config.columnBackgroundColor, - ), + child: boardColumn, ); }, ), diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart index cbc537810e..d4e5ff8800 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart @@ -87,7 +87,9 @@ class AFBoardColumnWidget extends StatefulWidget { final Color backgroundColor; - const AFBoardColumnWidget({ + final GlobalKey columnGlobalKey = GlobalKey(); + + AFBoardColumnWidget({ Key? key, this.headerBuilder, this.footBuilder, @@ -136,8 +138,8 @@ class _AFBoardColumnWidgetState extends State { draggableTargetBuilder: PhantomDraggableBuilder(), ); - final reorderFlex = ReorderFlex( - key: widget.key, + Widget reorderFlex = ReorderFlex( + key: widget.columnGlobalKey, scrollController: widget.scrollController, config: widget.config, onDragStarted: (index) { @@ -160,6 +162,9 @@ class _AFBoardColumnWidgetState extends State { children: children, ); + // reorderFlex = + // KeyedSubtree(key: widget.columnGlobalKey, child: reorderFlex); + return Container( margin: widget.margin, clipBehavior: Clip.hardEdge, diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart index 250a4eb020..592277afbc 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_state.dart @@ -132,7 +132,7 @@ class DraggingState { } void updateNextIndex(int index) { - Log.trace('$reorderFlexId updateNextIndex: $index'); + Log.debug('$reorderFlexId updateNextIndex: $index'); nextIndex = index; } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart index 621179455a..8217d2736f 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart @@ -1,4 +1,3 @@ -import 'package:appflowy_board/src/utils/log.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:provider/provider.dart'; @@ -448,9 +447,9 @@ class _FakeDragTargetState /// Start insert animation widget.insertAnimationController.forward(from: 0.0); - widget.eventTrigger.fakeOnDragStart((insertIndex) { - Log.debug("[$FakeDragTarget] on drag $insertIndex"); - }); + // widget.eventTrigger.fakeOnDragStart((insertIndex) { + // Log.trace("[$FakeDragTarget] on drag $insertIndex"); + // }); widget.eventTrigger.fakeOnDragEnded(() { WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart index d3a7e405e8..36366cd1e0 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart @@ -55,6 +55,7 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor { final String reorderFlexId; final List acceptedReorderFlexId; final OverlapDragTargetDelegate delegate; + final List columnKeys = []; Timer? _delayOperation; OverlappingDragTargetInterceptor({ @@ -87,6 +88,15 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor { Log.trace( '[$OverlappingDragTargetInterceptor] move to $dragTargetId at $index'); delegate.moveTo(dragTargetId, dragTargetData, index); + + // final columnIndex = columnKeys + // .indexWhere((element) => element.columnId == dragTargetId); + // if (columnIndex != -1) { + // final state = columnKeys[columnIndex].key.currentState; + // if (state is ReorderFlexState) { + // state.handleOnWillAccept(context, index); + // } + // } } }); } @@ -95,6 +105,12 @@ class OverlappingDragTargetInterceptor extends DragTargetInterceptor { } } +class ColumnKey { + String columnId; + GlobalKey key; + ColumnKey({required this.columnId, required this.key}); +} + abstract class CrossReorderFlexDragTargetDelegate { /// * [reorderFlexId] is the id that the [ReorderFlex] passed in. bool acceptNewDragTargetData( diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart index f84fe8c991..26b68c2304 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart @@ -213,8 +213,8 @@ class ReorderFlexState extends State shiftedIndex = dragState.calculateShiftedIndex(childIndex); } - // Log.trace( - // 'Rebuild: Column:[${dragState.id}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex'); + Log.trace( + 'Rebuild: Column:[${dragState.reorderFlexId}] ${dragState.toString()}, childIndex: $childIndex shiftedIndex: $shiftedIndex'); final currentIndex = dragState.currentIndex; final dragPhantomIndex = dragState.phantomIndex; diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart index 45a7ce2392..4dd4f05a74 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart @@ -214,12 +214,6 @@ class BoardPhantomController extends OverlapDragTargetDelegate } else { return 0; } - - if (delegate.controller(dragTargetId)?.columnData.items.isEmpty ?? false) { - return 0; - } else { - return -1; - } } }