|
@@ -6,6 +6,9 @@ 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';
|
|
|
|
|
|
|
|
+/// This class contains operations to committed by users.
|
|
|
|
+/// If a [HistoryItem] is not sealed, operations can be added sequentially.
|
|
|
|
+/// Otherwise, the operations should be added to a new [HistoryItem].
|
|
class HistoryItem extends LinkedListEntry<HistoryItem> {
|
|
class HistoryItem extends LinkedListEntry<HistoryItem> {
|
|
final List<Operation> operations = [];
|
|
final List<Operation> operations = [];
|
|
Selection? beforeSelection;
|
|
Selection? beforeSelection;
|
|
@@ -18,6 +21,8 @@ class HistoryItem extends LinkedListEntry<HistoryItem> {
|
|
_sealed = true;
|
|
_sealed = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bool get sealed => _sealed;
|
|
|
|
+
|
|
add(Operation op) {
|
|
add(Operation op) {
|
|
operations.add(op);
|
|
operations.add(op);
|
|
}
|
|
}
|
|
@@ -26,10 +31,6 @@ class HistoryItem extends LinkedListEntry<HistoryItem> {
|
|
operations.addAll(iterable);
|
|
operations.addAll(iterable);
|
|
}
|
|
}
|
|
|
|
|
|
- bool get sealed {
|
|
|
|
- return _sealed;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
Transaction toTransaction(EditorState state) {
|
|
Transaction toTransaction(EditorState state) {
|
|
final builder = TransactionBuilder(state);
|
|
final builder = TransactionBuilder(state);
|
|
for (var i = operations.length - 1; i >= 0; i--) {
|
|
for (var i = operations.length - 1; i >= 0; i--) {
|
|
@@ -67,24 +68,22 @@ class FixedSizeStack {
|
|
return last;
|
|
return last;
|
|
}
|
|
}
|
|
|
|
|
|
- HistoryItem get last {
|
|
|
|
- return _list.last;
|
|
|
|
- }
|
|
|
|
|
|
+ HistoryItem get last => _list.last;
|
|
|
|
|
|
- bool get isEmpty {
|
|
|
|
- return _list.isEmpty;
|
|
|
|
- }
|
|
|
|
|
|
+ bool get isEmpty => _list.isEmpty;
|
|
|
|
|
|
- bool get isNonEmpty {
|
|
|
|
- return _list.isNotEmpty;
|
|
|
|
- }
|
|
|
|
|
|
+ bool get isNonEmpty => _list.isNotEmpty;
|
|
}
|
|
}
|
|
|
|
|
|
class UndoManager {
|
|
class UndoManager {
|
|
- final undoStack = FixedSizeStack(20);
|
|
|
|
- final redoStack = FixedSizeStack(20);
|
|
|
|
|
|
+ final FixedSizeStack undoStack;
|
|
|
|
+ final FixedSizeStack redoStack;
|
|
EditorState? state;
|
|
EditorState? state;
|
|
|
|
|
|
|
|
+ UndoManager([int stackSize = 20])
|
|
|
|
+ : undoStack = FixedSizeStack(stackSize),
|
|
|
|
+ redoStack = FixedSizeStack(stackSize);
|
|
|
|
+
|
|
HistoryItem getUndoHistoryItem() {
|
|
HistoryItem getUndoHistoryItem() {
|
|
if (undoStack.isEmpty) {
|
|
if (undoStack.isEmpty) {
|
|
final item = HistoryItem();
|
|
final item = HistoryItem();
|
|
@@ -101,11 +100,15 @@ class UndoManager {
|
|
}
|
|
}
|
|
|
|
|
|
undo() {
|
|
undo() {
|
|
|
|
+ final s = state;
|
|
|
|
+ if (s == null) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
final historyItem = undoStack.pop();
|
|
final historyItem = undoStack.pop();
|
|
if (historyItem == null) {
|
|
if (historyItem == null) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- final transaction = historyItem.toTransaction(state!);
|
|
|
|
- state!.apply(transaction, const ApplyOptions(noLog: true));
|
|
|
|
|
|
+ final transaction = historyItem.toTransaction(s);
|
|
|
|
+ s.apply(transaction, const ApplyOptions(recordUndo: false));
|
|
}
|
|
}
|
|
}
|
|
}
|