Undo/Redo¶
NeatUndoRedoNotifier provides a simple way to add history support to your state. It maintains a history stack and a redo stack, allowing you to move backwards and forwards through state changes.
Usage¶
- Mix in
NeatUndoRedoNotifier: Add the mixin to your notifier. - Call
setupUndoRedo(): Initialize history in the constructor. - Use
undo()andredo(): Trigger transitions as needed. - Check
canUndoandcanRedo: Useful for enabling/disabling UI buttons.
class DrawingNotifier extends NeatNotifier<List<Offset>, void> with NeatUndoRedoNotifier<List<Offset>, void> {
DrawingNotifier() : super([]) {
setupUndoRedo(maxHistory: 50);
}
void addPoint(Offset point) {
value = List.from(value)..add(point);
}
}
Example¶
import 'package:flutter/material.dart';
import 'package:neat_state/neat_state.dart';
class DrawingNotifier extends NeatNotifier<List<Offset>, void>
with NeatUndoRedoNotifier<List<Offset>, void> {
DrawingNotifier() : super([]) {
setupUndoRedo();
}
void addPoint(Offset point) => value = List.from(value)..add(point);
void clear() => value = [];
}
void main() => runApp(const MaterialApp(home: UndoRedoDemo()));
class UndoRedoDemo extends StatelessWidget {
const UndoRedoDemo({super.key});
@override
Widget build(BuildContext context) {
return NeatState(
create: (_) => DrawingNotifier(),
builder: (context, points, _) {
final notifier = context.read<DrawingNotifier>();
return Scaffold(
appBar: AppBar(
title: const Text('Undo/Redo Canvas'),
actions: [
IconButton(
icon: const Icon(Icons.undo),
onPressed: notifier.canUndo ? notifier.undo : null,
),
IconButton(
icon: const Icon(Icons.redo),
onPressed: notifier.canRedo ? notifier.redo : null,
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: notifier.clear,
),
],
),
body: GestureDetector(
onPanUpdate: (details) => notifier.addPoint(details.localPosition),
child: CustomPaint(
painter: SimplePainter(points),
size: Size.infinite,
),
),
);
},
);
}
}
class SimplePainter extends CustomPainter {
final List<Offset> points;
SimplePainter(this.points);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..strokeWidth = 4.0
..strokeCap = StrokeCap.round;
for (int i = 0; i < points.length - 1; i++) {
canvas.drawLine(points[i], points[i + 1], paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}