undo 1.6.0 copy "undo: ^1.6.0" to clipboard
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:

  1. The old state (to revert to).
  2. The execute logic (to perform the change).
  3. 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.

85
likes
140
points
763
downloads

Publisher

verified publisherrodydavis.com

Weekly Downloads

A Undo/Redo Library for Flutter

Repository (GitHub)
View/report issues

Documentation

API reference

License

Apache-2.0 (license)

More

Packages that depend on undo