feat: redo

This commit is contained in:
Vincent Chan 2022-07-21 20:07:51 +08:00
parent 7ae153f5da
commit a120853d06
3 changed files with 54 additions and 2 deletions

View file

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

View file

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

View file

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