undo 1.6.0
undo: ^1.6.0 copied to clipboard
A Undo/Redo Library for Flutter
undo #
A clean, robust, and easy-to-use Undo/Redo library for Dart and Flutter. It leverages the Command Pattern to manage state changes, allowing you to easily roll back or replay actions in your application.
Features #
- 🔄 Undo/Redo: Simple stack-based undo/redo history.
- 📦 Batched Changes: Group multiple changes into a single undoable action (e.g., a multi-field form update).
- 🎨 Flexible: Works with any architecture (ChangeNotifier, Bloc, Riverpod, etc.).
- ⚡ Lightweight: Minimal overhead, zero dependencies.
Installation #
Add dependencies to your pubspec.yaml:
dependencies:
undo: ^1.6.0
Run pub get or flutter pub get.
Usage #
Basic Usage #
Create a ChangeStack to manage your changes. A Change consists of:
- The old state (to revert to).
- The execute logic (to perform the change).
- The undo logic (to revert the change).
import 'package:undo/undo.dart';
void main() {
final changes = ChangeStack();
var count = 0;
// Perform a change
changes.add(
Change<int>(
count, // Old value (0)
() => count++, // Execute: increment
(oldVal) => count = oldVal, // Undo: set back to old val
description: 'Increment count',
),
);
print(count); // 1
// Undo the change
changes.undo();
print(count); // 0
// Redo the change
changes.redo();
print(count); // 1
}
Working with Objects #
When modifying objects, capture the specific field value before the change so you can restore it.
class User {
String name = 'John';
}
void main() {
final user = User();
final changes = ChangeStack();
// Capture the OLD name before changing it
final oldName = user.name;
changes.add(
Change<String>(
oldName,
() => user.name = 'Jane', // New name
(val) => user.name = val, // Restore old name
description: 'Update name',
),
);
print(user.name); // Jane
changes.undo();
print(user.name); // John
}
SimpleStack (Quick Start) #
SimpleStack is a wrapper around ChangeStack that makes it easier to track a single state object. It's great for simple use cases.
final stack = SimpleStack<int>(0); // Initial state is 0
// Modifying state automatically creates a change history
stack.modify(1);
print(stack.state); // 1
stack.undo();
print(stack.state); // 0
Grouping Changes #
Sometimes you want multiple operations to be undone as a single step. Use addGroup (or manual group logic in 1.6.0+).
changes.add(
Change.group([
Change(
user.firstName,
() => user.firstName = 'Jane',
(val) => user.firstName = val,
),
Change(
user.lastName,
() => user.lastName = 'Doe',
(val) => user.lastName = val,
),
]),
);
Flutter Integration #
ChangeStack works seamlessly with ChangeNotifier to rebuild your UI when undo/redo state changes.
class MyController extends ChangeNotifier {
final ChangeStack _changes = ChangeStack();
int _count = 0;
int get count => _count;
bool get canUndo => _changes.canUndo;
bool get canRedo => _changes.canRedo;
void increment() {
_changes.add(
Change<int>(
_count,
() {
_count++;
notifyListeners();
},
(oldVal) {
_count = oldVal;
notifyListeners();
},
),
);
}
void undo() {
_changes.undo();
notifyListeners();
}
void redo() {
_changes.redo();
notifyListeners();
}
}
See the example folder for a complete Flutter Todo List application.