Browse Source

Merge pull request #668 from AppFlowy-IO/feat/redo

Feat: redo
Nathan.fooo 2 years ago
parent
commit
d71d954330

+ 14 - 1
frontend/app_flowy/packages/flowy_editor/example/lib/plugin/text_node_widget.dart

@@ -43,6 +43,7 @@ class __TextNodeWidgetState extends State<_TextNodeWidget>
   TextNode get node => widget.node as TextNode;
   EditorState get editorState => widget.editorState;
   bool _metaKeyDown = false;
+  bool _shiftKeyDown = false;
 
   TextInputConnection? _textInputConnection;
 
@@ -79,6 +80,7 @@ class __TextNodeWidgetState extends State<_TextNodeWidget>
   }
 
   KeyEventResult _onKey(FocusNode focusNode, RawKeyEvent event) {
+    debugPrint('key: $event');
     if (event is RawKeyDownEvent) {
       final sel = _globalSelectionToLocal(node, editorState.cursorSelection);
       if (event.logicalKey == LogicalKeyboardKey.backspace) {
@@ -90,14 +92,25 @@ class __TextNodeWidgetState extends State<_TextNodeWidget>
       } else if (event.logicalKey == LogicalKeyboardKey.metaLeft ||
           event.logicalKey == LogicalKeyboardKey.metaRight) {
         _metaKeyDown = true;
+      } else if (event.logicalKey == LogicalKeyboardKey.shiftLeft ||
+          event.logicalKey == LogicalKeyboardKey.shiftRight) {
+        _shiftKeyDown = true;
       } else if (event.logicalKey == LogicalKeyboardKey.keyZ && _metaKeyDown) {
-        editorState.undoManager.undo();
+        if (_shiftKeyDown) {
+          editorState.undoManager.redo();
+        } else {
+          editorState.undoManager.undo();
+        }
       }
     } else if (event is RawKeyUpEvent) {
       if (event.logicalKey == LogicalKeyboardKey.metaLeft ||
           event.logicalKey == LogicalKeyboardKey.metaRight) {
         _metaKeyDown = false;
       }
+      if (event.logicalKey == LogicalKeyboardKey.shiftLeft ||
+          event.logicalKey == LogicalKeyboardKey.shiftRight) {
+        _shiftKeyDown = false;
+      }
     }
     return KeyEventResult.ignored;
   }

+ 8 - 0
frontend/app_flowy/packages/flowy_editor/lib/editor_state.dart

@@ -10,8 +10,10 @@ class ApplyOptions {
   /// whether the transaction should be recorded into
   /// the undo stack.
   final bool recordUndo;
+  final bool recordRedo;
   const ApplyOptions({
     this.recordUndo = true,
+    this.recordRedo = false,
   });
 }
 
@@ -57,6 +59,12 @@ class EditorState {
       }
       undoItem.afterSelection = transaction.afterSelection;
       _debouncedSealHistoryItem();
+    } else if (options.recordRedo) {
+      final redoItem = HistoryItem();
+      redoItem.addAll(transaction.operations);
+      redoItem.beforeSelection = transaction.beforeSelection;
+      redoItem.afterSelection = transaction.afterSelection;
+      undoManager.redoStack.push(redoItem);
     }
   }
 

+ 32 - 1
frontend/app_flowy/packages/flowy_editor/lib/undo_manager.dart

@@ -5,6 +5,7 @@ import 'package:flowy_editor/operation/operation.dart';
 import 'package:flowy_editor/operation/transaction_builder.dart';
 import 'package:flowy_editor/operation/transaction.dart';
 import 'package:flowy_editor/editor_state.dart';
+import 'package:flutter/foundation.dart';
 
 /// This class contains operations committed by users.
 /// If a [HistoryItem] is not sealed, operations can be added sequentially.
@@ -68,6 +69,10 @@ class FixedSizeStack {
     return last;
   }
 
+  clear() {
+    _list.clear();
+  }
+
   HistoryItem get last => _list.last;
 
   bool get isEmpty => _list.isEmpty;
@@ -92,6 +97,7 @@ class UndoManager {
     }
     final last = undoStack.last;
     if (last.sealed) {
+      redoStack.clear();
       final item = HistoryItem();
       undoStack.push(item);
       return item;
@@ -100,6 +106,7 @@ class UndoManager {
   }
 
   undo() {
+    debugPrint('undo');
     final s = state;
     if (s == null) {
       return;
@@ -109,6 +116,30 @@ class UndoManager {
       return;
     }
     final transaction = historyItem.toTransaction(s);
-    s.apply(transaction, const ApplyOptions(recordUndo: false));
+    s.apply(
+        transaction,
+        const ApplyOptions(
+          recordUndo: false,
+          recordRedo: true,
+        ));
+  }
+
+  redo() {
+    debugPrint('redo');
+    final s = state;
+    if (s == null) {
+      return;
+    }
+    final historyItem = redoStack.pop();
+    if (historyItem == null) {
+      return;
+    }
+    final transaction = historyItem.toTransaction(s);
+    s.apply(
+        transaction,
+        const ApplyOptions(
+          recordUndo: true,
+          recordRedo: false,
+        ));
   }
 }