Skip to content

Instantly share code, notes, and snippets.

@nhaarman
Created March 7, 2018 13:54
Show Gist options
  • Save nhaarman/e1e9bc34134a11b92c40c5f455e87d60 to your computer and use it in GitHub Desktop.
Save nhaarman/e1e9bc34134a11b92c40c5f455e87d60 to your computer and use it in GitHub Desktop.
Simple Rx undo/redo stream
fun <T, R> Observable<Command<T>>.undoRedo(initialValue: R, accumulator: (R, T) -> R): Observable<R> {
return this
.scan(UndoRedoStack.create<T>()) { stack, command ->
when (command) {
is Command.Do -> stack.push(command.action)
is Command.Undo -> stack.undo()
is Command.Redo -> stack.redo()
}
}
.map { stack ->
stack.actions.fold(initialValue, accumulator)
}
}
@Suppress("unused")
sealed class Command<out T> {
data class Do<T>(val action: T) : Command<T>()
object Undo : Command<Nothing>()
object Redo : Command<Nothing>()
}
private class UndoRedoStack<T> private constructor(
private val _actions: Stack<T>,
private val undoneEvents: Stack<T>
) {
val actions: List<T> get() = _actions
fun push(action: T): UndoRedoStack<T> {
_actions.push(action)
undoneEvents.clear()
return this
}
fun undo(): UndoRedoStack<T> {
if (_actions.isNotEmpty()) {
undoneEvents.push(_actions.pop())
}
return this
}
fun redo(): UndoRedoStack<T> {
if (undoneEvents.isNotEmpty()) {
_actions.push(undoneEvents.pop())
}
return this
}
companion object {
fun <T> create() = UndoRedoStack<T>(Stack(), Stack())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment