Browse Source

chore: fix insert animation

appflowy 2 years ago
parent
commit
aec5c3e807

+ 2 - 2
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

+ 9 - 4
frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart

@@ -26,13 +26,18 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
     List<AFColumnItem> 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: <AFColumnItem>[
-      // 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: <AFColumnItem>[]);
@@ -93,7 +98,7 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
       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),
         ),
       );

+ 4 - 4
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');
     }
   }
 }

+ 2 - 1
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);
       }

+ 3 - 3
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;
   }
 

+ 8 - 2
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<DragTargeMovePlaceholder> {
 }
 
 abstract class FakeDragTargetEventTrigger {
+  void fakeOnDragStart(void Function(int?) callback);
   void fakeOnDragEnded(VoidCallback callback);
 }
 
@@ -421,6 +423,10 @@ class _FakeDragTargetState<T extends DragTargetData>
     /// 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);

+ 19 - 3
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<String> 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<String> 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);

+ 12 - 10
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<ReorderFlex>
         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<ReorderFlex>
         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<ReorderFlex>
         });
       },
       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<ReorderFlex>
     // 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(

+ 41 - 20
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;
-    }
-
-    delegate.swapColumnItem(
-      fromColumnId,
-      phantomRecord!.fromColumnIndex,
-      toColumnId,
-      phantomRecord!.toColumnIndex,
-    );
+    if (phantomRecord!.toColumnId == columnId) {
+      delegate.swapColumnItem(
+        fromColumnId,
+        phantomRecord!.fromColumnIndex,
+        toColumnId,
+        phantomRecord!.toColumnIndex,
+      );
 
-    Log.debug("[$BoardPhantomController] did move ${phantomRecord.toString()}");
-    phantomRecord = null;
+      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 {

+ 11 - 9
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();
   }
 }