diff --git a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board.dart b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board.dart index f425bcd556..c3bbe9824f 100644 --- a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board.dart +++ b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board.dart @@ -122,16 +122,14 @@ class BoardContent extends StatefulWidget { } class _BoardContentState extends State { - final GlobalKey _columnContainerOverlayKey = - GlobalKey(debugLabel: '$BoardContent overlay key'); + final GlobalKey _columnContainerOverlayKey = GlobalKey(debugLabel: '$BoardContent overlay key'); late BoardOverlayEntry _overlayEntry; @override void initState() { _overlayEntry = BoardOverlayEntry( builder: (BuildContext context) { - List children = - widget.dataController.columnDatas.map((columnData) { + List children = widget.dataController.columnDatas.map((columnData) { return _buildColumn( columnData.id, widget.dataController.columnIds, diff --git a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board_column/data_controller.dart b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board_column/data_controller.dart index d8442563ed..0eda4f3cc6 100644 --- a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board_column/data_controller.dart +++ b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/board_column/data_controller.dart @@ -1,3 +1,5 @@ +import 'dart:collection'; + import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import '../../utils/log.dart'; @@ -8,22 +10,26 @@ abstract class ColumnItem extends ReoderFlexItem { @override String toString() { - return id; + if (isPhantom) { + return 'phantom:$id'; + } else { + return id; + } } } class BoardColumnData extends ReoderFlexItem with EquatableMixin { @override final String id; - final List items; + final List _items; BoardColumnData({ required this.id, - required this.items, - }); + required List items, + }) : _items = items; @override - List get props => [id, ...items]; + List get props => [id, ..._items]; @override String toString() { @@ -31,8 +37,7 @@ class BoardColumnData extends ReoderFlexItem with EquatableMixin { } } -class BoardColumnDataController extends ChangeNotifier - with EquatableMixin, ReoderFlextDataSource { +class BoardColumnDataController extends ChangeNotifier with EquatableMixin, ReoderFlextDataSource { final BoardColumnData columnData; BoardColumnDataController({ @@ -42,10 +47,12 @@ class BoardColumnDataController extends ChangeNotifier @override List get props => columnData.props; - ColumnItem removeAt(int index) { + ColumnItem removeAt(int index, {bool notify = true}) { Log.debug('[$BoardColumnDataController] $columnData remove item at $index'); - final item = columnData.items.removeAt(index); - notifyListeners(); + final item = columnData._items.removeAt(index); + if (notify) { + notifyListeners(); + } return item; } @@ -53,31 +60,29 @@ class BoardColumnDataController extends ChangeNotifier if (fromIndex == toIndex) { return; } - Log.debug( - '[$BoardColumnDataController] $columnData move item from $fromIndex to $toIndex'); - final item = columnData.items.removeAt(fromIndex); - columnData.items.insert(toIndex, item); + Log.debug('[$BoardColumnDataController] $columnData move item from $fromIndex to $toIndex'); + final item = columnData._items.removeAt(fromIndex); + columnData._items.insert(toIndex, item); notifyListeners(); } void insert(int index, ColumnItem item, {bool notify = true}) { - Log.debug('[$BoardColumnDataController] $columnData insert item at $index'); - columnData.items.insert(index, item); + Log.debug('[$BoardColumnDataController] $columnData insert $item at $index'); + columnData._items.insert(index, item); if (notify) { notifyListeners(); } } void replace(int index, ColumnItem item) { - Log.debug( - '[$BoardColumnDataController] $columnData replace item at $index'); - columnData.items.removeAt(index); - columnData.items.insert(index, item); + final removedItem = columnData._items.removeAt(index); + columnData._items.insert(index, item); + Log.debug('[$BoardColumnDataController] $columnData replace $removedItem with $item at $index'); notifyListeners(); } @override - List get items => columnData.items; + List get items => UnmodifiableListView(columnData._items); @override String get identifier => columnData.id; diff --git a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_state.dart b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_state.dart index f7b174ebee..1de8b843a0 100644 --- a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_state.dart +++ b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_state.dart @@ -22,14 +22,14 @@ class FlexDragTargetData extends DragTargetData { final String dragTargetId; - ReoderFlexItem get reorderFlexItem => - draggingReorderFlex.itemAtIndex(draggingIndex); + final ReoderFlexItem reorderFlexItem; String get reorderFlexId => draggingReorderFlex.reorderFlexId; FlexDragTargetData({ required this.dragTargetId, required this.draggingIndex, + required this.reorderFlexItem, required this.state, required this.draggingReorderFlex, }); @@ -85,12 +85,10 @@ class DraggingState { if (_draggingFeedbackSize == null) { return Size.zero; } - return _draggingFeedbackSize! + - const Offset(_dropAreaMargin, _dropAreaMargin); + return _draggingFeedbackSize! + const Offset(_dropAreaMargin, _dropAreaMargin); } - void startDragging(Widget draggingWidget, int draggingWidgetIndex, - Size? draggingWidgetSize) { + void startDragging(Widget draggingWidget, int draggingWidgetIndex, Size? draggingWidgetSize) { /// assert(draggingWidgetIndex >= 0); diff --git a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_target_inteceptor.dart b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_target_inteceptor.dart index 09a8e2b064..b1f933f577 100644 --- a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_target_inteceptor.dart +++ b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/drag_target_inteceptor.dart @@ -25,8 +25,7 @@ abstract class ReorderFlexDragTargetInterceptor { abstract class OverlapReorderFlexDragTargetDelegate {} -class OverlapReorderFlexDragTargetInteceptor - extends ReorderFlexDragTargetInterceptor { +class OverlapReorderFlexDragTargetInteceptor extends ReorderFlexDragTargetInterceptor { final String reorderFlexId; final List acceptedReorderFlexId; final OverlapReorderFlexDragTargetDelegate delegate; @@ -71,8 +70,7 @@ abstract class CrossReorderFlexDragTargetDelegate { ); } -class CrossReorderFlexDragTargetInterceptor - extends ReorderFlexDragTargetInterceptor { +class CrossReorderFlexDragTargetInterceptor extends ReorderFlexDragTargetInterceptor { final String reorderFlexId; final List acceptedReorderFlexIds; final CrossReorderFlexDragTargetDelegate delegate; @@ -104,14 +102,12 @@ class CrossReorderFlexDragTargetInterceptor @override void onAccept(FlexDragTargetData dragTargetData) { - Log.trace( - '[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on onAccept'); + Log.trace('[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on onAccept'); } @override void onLeave(FlexDragTargetData dragTargetData) { - Log.trace( - '[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on leave'); + Log.trace('[$CrossReorderFlexDragTargetInterceptor] Column$reorderFlexId on leave'); } @override @@ -134,7 +130,7 @@ class CrossReorderFlexDragTargetInterceptor dragTargetIndex, ); - reorderFlexState.onWillAccept( + reorderFlexState.handleOnWillAccept( context, dragTargetData.draggingIndex, dragTargetIndex, diff --git a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/reorder_flex.dart b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/reorder_flex.dart index b1d3c59a9f..242bd77785 100644 --- a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/reorder_flex.dart +++ b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/flex/reorder_flex.dart @@ -13,8 +13,7 @@ typedef OnDragEnded = void Function(); typedef OnReorder = void Function(int fromIndex, int toIndex); typedef OnDeleted = void Function(int deletedIndex); typedef OnInserted = void Function(int insertedIndex); -typedef OnReveivePassedInPhantom = void Function( - FlexDragTargetData dragTargetData, int phantomIndex); +typedef OnReveivePassedInPhantom = void Function(FlexDragTargetData dragTargetData, int phantomIndex); abstract class ReoderFlextDataSource { String get identifier; @@ -78,8 +77,7 @@ class ReorderFlex extends StatefulWidget with DraggingReorderFlex { } } -class ReorderFlexState extends State - with ReorderFlexMinxi, TickerProviderStateMixin { +class ReorderFlexState extends State with ReorderFlexMinxi, TickerProviderStateMixin { /// Controls scrolls and measures scroll progress. late ScrollController _scrollController; ScrollPosition? _attachedScrollPosition; @@ -115,9 +113,7 @@ class ReorderFlexState extends State _attachedScrollPosition = null; } - _scrollController = widget.scrollController ?? - PrimaryScrollController.of(context) ?? - ScrollController(); + _scrollController = widget.scrollController ?? PrimaryScrollController.of(context) ?? ScrollController(); if (_scrollController.hasClients) { _attachedScrollPosition = Scrollable.of(context)?.position; @@ -239,9 +235,7 @@ class ReorderFlexState extends State ]); } else if (childIndex == dragPhantomIndex) { return _buildDraggingContainer( - children: shiftedIndex <= childIndex - ? [dragTarget, disappearSpace] - : [disappearSpace, dragTarget]); + children: shiftedIndex <= childIndex ? [dragTarget, disappearSpace] : [disappearSpace, dragTarget]); } } @@ -262,9 +256,7 @@ class ReorderFlexState extends State ]); } else if (childIndex == dragPhantomIndex) { return _buildDraggingContainer( - children: shiftedIndex >= childIndex - ? [disappearSpace, dragTarget] - : [dragTarget, disappearSpace]); + children: shiftedIndex >= childIndex ? [disappearSpace, dragTarget] : [dragTarget, disappearSpace]); } } @@ -290,21 +282,22 @@ class ReorderFlexState extends State Widget child, int dragTargetIndex, ) { - final ReoderFlexItem item = widget.dataSource.items[dragTargetIndex]; + final ReoderFlexItem reorderFlexItem = widget.dataSource.items[dragTargetIndex]; return ReorderDragTarget( dragTargetData: FlexDragTargetData( draggingIndex: dragTargetIndex, + reorderFlexItem: reorderFlexItem, state: dragState, draggingReorderFlex: widget, - dragTargetId: item.id, + dragTargetId: reorderFlexItem.id, ), onDragStarted: (draggingWidget, draggingIndex, size) { - Log.debug("Column${widget.dataSource.identifier} start dragging"); + Log.debug("[DragTarget] Column${widget.dataSource.identifier} start dragging"); _startDragging(draggingWidget, draggingIndex, size); widget.onDragStarted?.call(draggingIndex); }, onDragEnded: (dragTargetData) { - Log.debug("Column${widget.dataSource.identifier} end dragging"); + Log.debug("[DragTarget]: Column${widget.dataSource.identifier} end dragging"); setState(() { _onReordered( @@ -317,22 +310,21 @@ class ReorderFlexState extends State }, onWillAccept: (FlexDragTargetData dragTargetData) { assert(widget.dataSource.items.length > dragTargetIndex); - Log.debug( - '[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, count: ${widget.dataSource.items.length}'); + if (_interceptDragTarget( dragTargetData, (interceptor) => interceptor.onWillAccept( context: builderContext, reorderFlexState: this, dragTargetData: dragTargetData, - dragTargetId: item.id, + dragTargetId: reorderFlexItem.id, dragTargetIndex: dragTargetIndex, ), )) { return true; } else { final dragIndex = dragTargetData.draggingIndex; - return onWillAccept(builderContext, dragIndex, dragTargetIndex); + return handleOnWillAccept(builderContext, dragIndex, dragTargetIndex); } }, onAccept: (dragTargetData) { @@ -394,11 +386,14 @@ class ReorderFlexState extends State }); } - bool onWillAccept(BuildContext context, int? dragIndex, int childIndex) { + bool handleOnWillAccept(BuildContext context, int? dragIndex, int childIndex) { /// The [willAccept] will be true if the dargTarget is the widget that gets /// dragged and it is dragged on top of the other dragTargets. - bool willAccept = - dragState.dragStartIndex == dragIndex && dragIndex != childIndex; + /// + Log.trace( + '[$ReorderDragTarget] ${widget.dataSource.identifier} on will accept, count: ${widget.dataSource.items.length}'); + + bool willAccept = dragState.dragStartIndex == dragIndex && dragIndex != childIndex; setState(() { if (willAccept) { int shiftedIndex = dragState.calculateShiftedIndex(childIndex); @@ -425,8 +420,7 @@ class ReorderFlexState extends State } Widget _wrapScrollView({required Widget child}) { - if (widget.scrollController != null && - PrimaryScrollController.of(context) == null) { + if (widget.scrollController != null && PrimaryScrollController.of(context) == null) { return child; } else { return SingleChildScrollView( @@ -480,14 +474,12 @@ class ReorderFlexState extends State void _scrollTo(BuildContext context) { if (_scrolling) return; final RenderObject contextObject = context.findRenderObject()!; - final RenderAbstractViewport viewport = - RenderAbstractViewport.of(contextObject)!; + final RenderAbstractViewport viewport = RenderAbstractViewport.of(contextObject)!; // 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 // screen, then it is already on-screen. - final double margin = widget.direction == Axis.horizontal - ? dragState.dropAreaSize.width - : dragState.dropAreaSize.height; + final double margin = + widget.direction == Axis.horizontal ? dragState.dropAreaSize.width : dragState.dropAreaSize.height; if (_scrollController.hasClients) { final double scrollOffset = _scrollController.offset; final double topOffset = max( @@ -498,8 +490,7 @@ class ReorderFlexState extends State _scrollController.position.maxScrollExtent, viewport.getOffsetToReveal(contextObject, 1.0).offset + margin, ); - final bool onScreen = - scrollOffset <= topOffset && scrollOffset >= bottomOffset; + final bool onScreen = scrollOffset <= topOffset && scrollOffset >= bottomOffset; // If the context is off screen, then we request a scroll to make it visible. if (!onScreen) { diff --git a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/phantom/phantom_controller.dart b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/phantom/phantom_controller.dart index 65c3cfbe16..b7074ed01a 100644 --- a/frontend/app_flowy/packages/flowy_board/lib/src/widgets/phantom/phantom_controller.dart +++ b/frontend/app_flowy/packages/flowy_board/lib/src/widgets/phantom/phantom_controller.dart @@ -14,8 +14,7 @@ mixin ColumnDataPhantomMixim { BoardColumnDataController? get; } -class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate - with CrossReorderFlexDragTargetDelegate { +class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate with CrossReorderFlexDragTargetDelegate { final BoardPhantomControllerDelegate delegate; PhantomRecord? phantomRecord; @@ -64,22 +63,12 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate if (columnsState.isDragging(phantomRecord!.fromColumnId) == false) { return; } - - Log.debug("[$BoardPhantomController] move ${phantomRecord.toString()}"); - - final item = delegate - .controller(phantomRecord!.fromColumnId) - ?.removeAt(phantomRecord!.fromColumnIndex); - + final item = delegate.controller(phantomRecord!.fromColumnId)?.removeAt(phantomRecord!.fromColumnIndex); assert(item != null); - assert(delegate - .controller(phantomRecord!.toColumnId) - ?.items[phantomRecord!.toColumnIndex] is PhantomColumnItem); - - delegate - .controller(phantomRecord!.toColumnId) - ?.replace(phantomRecord!.toColumnIndex, item!); + assert(delegate.controller(phantomRecord!.toColumnId)?.items[phantomRecord!.toColumnIndex] is PhantomColumnItem); + delegate.controller(phantomRecord!.toColumnId)?.replace(phantomRecord!.toColumnIndex, item!); + Log.debug("[$BoardPhantomController] did move ${phantomRecord.toString()}"); phantomRecord = null; } @@ -88,28 +77,22 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate FlexDragTargetData dragTargetData, int phantomIndex, ) { - final items = delegate.controller(toColumnId)?.items; - if (items == null) { - return; - } + final columnDataController = delegate.controller(toColumnId); + final index = columnDataController?.items.indexWhere((item) => item.isPhantom); + if (index == null) return; - final index = items.indexWhere((item) => item.isPhantom); assert(index != -1); if (index != -1) { if (index != phantomIndex) { - Log.debug( - '[$BoardPhantomController] move phantom $toColumnId:$index to $toColumnId:$phantomIndex'); - final item = items.removeAt(index); - items.insert(phantomIndex, item); + // Log.debug('[$BoardPhantomController] update $toColumnId:$index to $toColumnId:$phantomIndex'); + final item = columnDataController!.removeAt(index, notify: false); + columnDataController.insert(phantomIndex, item, notify: false); } } } void _removePhantom(String columnId) { - final index = delegate - .controller(columnId) - ?.items - .indexWhere((item) => item.isPhantom); + final index = delegate.controller(columnId)?.items.indexWhere((item) => item.isPhantom); if (index == null) return; @@ -139,15 +122,11 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate dragTargetData: dragTargetData, ); columnsState.addColumnListener(toColumnId, phantomContext); - - Log.debug( - '[$BoardPhantomController] Column$toColumnId insert phantom at $phantomIndex'); - delegate - .controller(toColumnId) - ?.insert(phantomIndex, PhantomColumnItem(phantomContext)); + Log.debug('$phantomContext'); + delegate.controller(toColumnId)?.insert(phantomIndex, PhantomColumnItem(phantomContext)); WidgetsBinding.instance.addPostFrameCallback((_) { - Future.delayed(const Duration(microseconds: 100), () { + Future.delayed(const Duration(milliseconds: 00), () { columnsState.notifyDidInsertPhantom(toColumnId); }); }); @@ -158,9 +137,8 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate FlexDragTargetData dragTargetData, int index, ) { - 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:$index'); phantomRecord = PhantomRecord( toColumnId: columnId, @@ -169,11 +147,11 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate fromColumnId: dragTargetData.reorderFlexId, fromColumnIndex: dragTargetData.draggingIndex, ); + Log.debug('[$BoardPhantomController] will move: $phantomRecord'); } @override - bool acceptNewDragTargetData( - String reorderFlexId, FlexDragTargetData dragTargetData, int index) { + bool acceptNewDragTargetData(String reorderFlexId, FlexDragTargetData dragTargetData, int index) { if (phantomRecord == null) { _updatePhantomRecord(reorderFlexId, dragTargetData, index); _insertPhantom(reorderFlexId, dragTargetData, index); @@ -181,8 +159,6 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate } final isNewDragTarget = phantomRecord!.toColumnId != reorderFlexId; - Log.debug( - '[$BoardPhantomController] Set inserted column id: $reorderFlexId, is new target: $isNewDragTarget'); if (isNewDragTarget) { /// Remove the phantom in the previous column. _removePhantom(phantomRecord!.toColumnId); @@ -196,8 +172,7 @@ class BoardPhantomController extends OverlapReorderFlexDragTargetDelegate } @override - void updateDragTargetData( - String reorderFlexId, FlexDragTargetData dragTargetData, int index) { + void updateDragTargetData(String reorderFlexId, FlexDragTargetData dragTargetData, int index) { phantomRecord?.updateInsertedIndex(index); assert(phantomRecord != null); @@ -228,34 +203,29 @@ class PhantomRecord { if (fromColumnIndex == index) { return; } - Log.info( - '[$PhantomRecord] Update Column$fromColumnId remove position to $index'); + Log.debug('[$PhantomRecord] Update Column$fromColumnId remove position to $index'); fromColumnIndex = index; } void updateInsertedIndex(int index) { if (toColumnIndex == index) { - Log.info( - '[$PhantomRecord] Column$toColumnId toColumnIndex: $toColumnIndex, index: $index'); return; } - Log.info( - '[$PhantomRecord] Update Column$toColumnId phantom position to $index'); + Log.debug('[$PhantomRecord] Column$toColumnId update position $toColumnIndex -> $index'); toColumnIndex = index; } @override String toString() { - return '$fromColumnId:$fromColumnIndex to $toColumnId:$toColumnIndex'; + return 'Column$fromColumnId:$fromColumnIndex to Column$toColumnId:$toColumnIndex'; } } class PhantomColumnItem extends ColumnItem { final PassthroughPhantomContext phantomContext; - PhantomColumnItem(PassthroughPhantomContext insertedPhantom) - : phantomContext = insertedPhantom; + PhantomColumnItem(PassthroughPhantomContext insertedPhantom) : phantomContext = insertedPhantom; @override bool get isPhantom => true; @@ -265,9 +235,8 @@ class PhantomColumnItem extends ColumnItem { Size? get feedbackSize => phantomContext.feedbackSize; - Widget get draggingWidget => phantomContext.draggingWidget == null - ? const SizedBox() - : phantomContext.draggingWidget!; + Widget get draggingWidget => + phantomContext.draggingWidget == null ? const SizedBox() : phantomContext.draggingWidget!; } class PassthroughPhantomContext extends FakeDragTargetEventTrigger