This is a simple and powerful Dart package that provides easy-to-use undo and redo functionality with additional convenience methods. Whether you're working with simple primitives or complex objects, this package helps you implement undo/redo effortlessly.
Android | iOS | MacOS | Web | Linux | Windows |
---|---|---|---|---|---|
β | β | β | β | β | β |
Explore the live web demo to see the package in action
In the pubspec.yaml
of your flutter project, add the following dependency:
dependencies:
...
undo_redo: <latest>
Import it:
import 'package:undo_redo/undo_redo.dart';
Managing state changes with primitive types is straightforward:
final UndoRedoManager<int> _undoRedoManager = UndoRedoManager<int>();
@override
void initState() {
_undoRedoManager.initialize(0); // Initial state
super.initState();
}
void _incrementCounter() {
_counter++;
_undoRedoManager.captureState(_counter); // Capture the new state
setState(() {});
}
// Undo the last action
int? undoData = _undoRedoManager.undo();
// Redo the last undone action
int? redoData = _undoRedoManager.redo();
// Reset to the initial state
int? initialData = _undoRedoManager.clearHistory();
// Check if an undo is possible
bool canUndo = _undoRedoManager.canUndo();
// Check if a redo is possible
bool canRedo = _undoRedoManager.canRedo();
When working with non-primitive types such as objects or collections, you must use a deep copy to ensure that state changes are independent
//This refers to the same memory location(s)
List<int> ages = originalAges;
//This a deep copy and not the same reference in memory
List<int> ages = List.from(originalAges);
Extend the Cloneable
class to provide a deep copy method:
class Staff extends Cloneable<Staff> {
String name;
List<int> ratings;
@override
Staff clone() {
return Staff(
name: name,
ratings: List.from(ratings),
);
}
}
Use the CloneableMixin
if you are already extending a class:
class Staff extends People with CloneableMixin<Staff> {
...
}
Now, you can manage undo/redo for complex objects:
final UndoRedoManager<Staff> _undoRedoManager = UndoRedoManager<Staff>();
Staff _staff = Staff(name: 'Foo Bar', ratings: [2, 3, 5]);
@override
void initState() {
_undoRedoManager.initialize(_staff.clone()); // Capture the initial state
super.initState();
}
void _onValueChange() {
_undoRedoManager.captureState(_staff.clone()); // Capture the new state
setState(() {});
}
// Undo the last action
void undo() {
var undoData = _undoRedoManager.undo();
if (undoData != null) {
_staff = undoData.clone(); // Restore to the previous state
}
}
Contributions are welcome! Please feel free to submit a pull request or report issues on the package's GitHub