Undo snapshot state changes in Compose.

Overview

compose-undo Maven Central

Track changes to any snapshot state object and restore state from any point in the past.

Usage

implementation 'com.zachklipp.compose-undo:statehistory:{version}'

The simplest way to get started is to use the WithStateHistory composable:

@Composable
fun App() {
    WithStateHistory { history ->
        var text by remember { mutableStateOf(TextFieldValue("")) }.trackStateChanges()
        TextField(text, onValueChange = { text = it })

        Button(onClick { history.undo() }) {
            Text("Undo")
        }
    }
}

The key is to call trackStateChanges on every snapshot state object you want to track. If you're creating state objects outside a composition, call StateHistory.startTrackingState yourself.

Advanced usage

The main API is the StateHistory class. See its kdoc for more detailed information.

Demo

This repo includes a demo app you can run and tinker with if you fork the repo. Here's a little preview:

compose-undo-demo.mp4

How it works

StateHistory keeps a set of all the state objects that were registered on it. It registers an apply listener to the snapshot system, and any time a snapshot is applied to the global snapshot it checks if any of the objects changed by that snapshot are being tracked. For every tracked changed object, it makes a copy of its latest state record. It collects all changes to tracked objects in a map (called a "frame"), then when saveFrame is called, it pushes that map onto the list of frames that represents the history.

When asked to restore states to a particular frame, it goes through every tracked state object and searches the frame list from the requested frame to find the latest frame that captured a change to that object. It then asks the snapshot system for a writable record for that object and copies the saved record back into the writable record, effectively setting the state object's value.

This is a very unconventional and probably unsupported use case of the StateObject and StateRecord APIs, but it allows the library to support any type of state object, even custom third-party ones. The actual implementation for saving and restoring state values looks something like this (stateObject is a StateObject):

// Save a state object's current value
val savedRecord = stateObject.firstStateRecord.create()
stateObject.firstStateRecord.withCurrent { currentRecord ->
    savedRecord.assign(currentRecord)
}

// Restore the value
stateObject.firstStateRecord.writable(stateObject) {
    assign(savedRecord)
}
You might also like...
Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.
Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.

Learn Jetpack Compose for Android by Examples. Learn how to use Jetpack Compose for Android App Development. Android’s modern toolkit for building native UI.

A Kotlin library to use Jetpack Compose in Android and iOS. Allow to write UI for both in Kotin. Still experimental as many compose features are not yet available.
A Kotlin library to use Jetpack Compose in Android and iOS. Allow to write UI for both in Kotin. Still experimental as many compose features are not yet available.

Multiplatform Compose A Kotlin library to use Jetpack Compose in Android and iOS. Allow to write UI for both in Kotin. Still experimental as many comp

K5-compose is a sketchy port of p5.js for Jetpack Compose
K5-compose is a sketchy port of p5.js for Jetpack Compose

k5-compose k5-compose is a sketchy port of P5.js for Jetpack Compose Desktop. This library provides you a playground to play with your sketches so you

Jetpack Compose based project, used to stress-testing compose features / integrations and explore non-trivial functionality

Project containing Jetpack Compose samples For pagination & network images it uses CATAAS. Known issues Navigation-Compose Issue with fast tapping on

Pokedex Compose is an independent re-write of a demo application by the name of Pokedex, but written in jetpack compose.
Pokedex Compose is an independent re-write of a demo application by the name of Pokedex, but written in jetpack compose.

Pokedex Compose Pokedex Compose is an independent re-write of a similar project by the name of Pokedex. I am recreating the UI but I am doing it using

Jetpack-Compose-Demo - Instagram Profile UI using Jetpack Compose
Jetpack-Compose-Demo - Instagram Profile UI using Jetpack Compose

Jetpack-Compose-Demo Instagram Profile UI using Jetpack Compose

Compose-Instagram-Profile-UI - Instagram profile screen UI using android jetpack compose
Compose-Instagram-Profile-UI - Instagram profile screen UI using android jetpack compose

Compose-Intsgram-Profile-UI Instagram profile screen UI using android jetpack co

List-programminglanguage-compose - Simple implementation of a list of programming languages using LazyColumn and Coil in Jetpack Compose Jetpack-compose-animations-examples - Cool animations implemented with Jetpack compose
Jetpack-compose-animations-examples - Cool animations implemented with Jetpack compose

Jetpack-compose-animations-examples This repository consists of 4 animations: St

Owner
Zach Klippenstein
Engineer at Google, previously Square, Amazon. Opinions my own.
Zach Klippenstein
A flexible theme provider for Jetpack Compose. Supports dynamic theme changes and saving theme preference.

JetTheme JetTheme is a flexible theme provider for Jetpack Compose. Change the theme and recompose the UI dynamically. Save theme preference to local

Mao Yufeng 48 Oct 19, 2022
This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Compose.

JetBMICalculator This is a sample app(For beginners - App #2) built using Jetpack Compose. It demonstrates the concept of State Hoisting in Jetpack Co

BHAVNA THACKER 3 Dec 31, 2022
🚀📱💖Animated LazyColumn/Row changes scale/color with animation and have a current selected item like a Pager. An elegant alternative for selecting from a list

Compose AnimatedList Animated infinite and finite LazyRow and LazyColumn with scale and color animations on scroll change based on how far they are to

Smart Tool Factory 47 Nov 16, 2022
A lightweight state management library for Compose Multiplatform.

Staccato A lightweight state management library for Compose Multiplatform. The term staccato (pronounced "stuh-caw-toe") means detached, or separated,

Marcello Galhardo 5 Oct 31, 2021
Using State in Jetpack Compose Codelab

Using State in Jetpack Compose Codelab This folder contains the source code for the Using State in Jetpack Compose codelab. In this codelab, you will

Jose Javier 0 Nov 17, 2021
Android Clean Architecture That Screams (MVVM + JetPack Compose UI + Flow + State)

Android Clean Architecture That Screams (MVVM + JetPack Compose UI + Flow + State)

Praveen Sharma 9 May 11, 2022
Compose-buttons - A set of Loading animations used in Buttons to convey a "loading" state after the button is clicked.

Loading Buttons A set of Loading animations used in Buttons to convey a "loading" state after the button is clicked. A simple demo application that sh

Brad Ball 16 Jul 5, 2022
Field state manager and basic set of validation, fields

Compose Forms Field state manager and basic set of validation, fields

Vitaliy Zarubin 9 Jan 4, 2022
Jetpack Compose Boids | Flocking Insect 🐜. bird or Fish simulation using Jetpack Compose Desktop 🚀, using Canvas API 🎨

?? ?? ?? Compose flocking Ants(boids) ?? ?? ?? Jetpack compose Boids | Flocking Insect. bird or Fish simulation using Jetpack Compose Desktop ?? , usi

Chetan Gupta 38 Sep 25, 2022
A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Why Not Compose! A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Md. Mahmudul Hasan Shohag 186 Jan 1, 2023