Created
May 25, 2022 13:50
-
-
Save stargazing-dino/1c40f3637dc7c4134f5d92ffa970164c to your computer and use it in GitHub Desktop.
initial attempt at undo redo state
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math' as math; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_hooks/flutter_hooks.dart'; | |
import 'package:tuple/tuple.dart'; | |
@immutable | |
class UndoRedoHandler { | |
const UndoRedoHandler({ | |
required this.resetState, | |
required this.index, | |
required this.lastIndex, | |
required this.goBack, | |
required this.goForward, | |
}); | |
final void Function() resetState; | |
final int index; | |
final int lastIndex; | |
/// Allows you to go back (undo) N steps. | |
/// Tries to go back in the history, returns true if it was possible. | |
final bool Function(int) goBack; | |
/// Allows you to go forward (redo) N steps. | |
/// Tries to go forward in the history, returns true if it was possible. | |
final bool Function(int) goForward; | |
} | |
Tuple2<ValueNotifier<T>, UndoRedoHandler> useUndoRedoState<T>( | |
T initialData, { | |
int maxHistory = 10, | |
bool Function(T a, T b)? equals, | |
}) { | |
final index = useState<int>(0); | |
final history = useValueNotifier([initialData]); | |
bool pushValue(T value) { | |
final current = history.value[index.value]; | |
if (equals != null) { | |
if (equals(current, value)) return false; | |
} else { | |
if (value == current) return false; | |
} | |
// Remove all values after the current index | |
final copy = history.value.sublist(0, index.value + 1); | |
// Trim the copy so it is only maxHistory long | |
if (copy.length > maxHistory) { | |
copy.removeRange(0, copy.length - maxHistory); | |
} | |
// Add the new value | |
copy.add(value); | |
// Update the state | |
history.value = copy; | |
index.value = copy.length - 1; | |
return true; | |
} | |
// Clear all state history | |
void resetState() { | |
index.value = 0; | |
history.value = [initialData]; | |
} | |
bool goBack(int steps) { | |
final newIndex = math.max(0, index.value - steps); | |
if (newIndex == index.value) { | |
return false; | |
} | |
index.value = newIndex; | |
return true; | |
} | |
bool goForward(int steps) { | |
final newIndex = math.min(history.value.length - 1, index.value + steps); | |
if (newIndex == index.value) { | |
return false; | |
} | |
index.value = newIndex; | |
return true; | |
} | |
return Tuple2( | |
current, | |
UndoRedoHandler( | |
resetState: resetState, | |
index: index.value, | |
lastIndex: history.value.length - 1, | |
goBack: goBack, | |
goForward: goForward, | |
), | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment