Undo/Redo for Flutter and Dart

Overview

undo

Buy Me A Coffee Donate github pages tests GitHub stars undo

An undo redo library for Dart/Flutter. Forked from here and updated for Flutter. Demo can be viewed here.

Usage

Create an ChangeStack to store changes

import 'package:undo/undo.dart';
	
var changes = new ChangeStack();

Add new undo, redo commands using ChangeStack.add(). When a change is added, it calls the change's execute() method. Use Change() for simple inline changes.

var count = 0;
	
changes.add(
  new Change(count, () => count++, (val) => count = val);
  name: "Increase"
);

Use Change() when changing a field on an object. This will store the field's old value so it can be reverted.

var person = new Person()
    ..firstName = "John"
    ..lastName = "Doe";

changes.add(
  new Change(
    person.firstName, 
    () => person.firstName = "Jane",
    (oldValue) = person.firstName = oldValue
  )
)

Undo a change with undo().

print(person.firstName); // Jane
changes.undo();
print(person.firstName); // John

Redo the change with redo().

changes.redo();
print(person.firstName); // Jane

Simple Stack Example

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  SimpleStack _controller;

  @override
  void initState() {
    _controller = SimpleStack<int>(
      0,
      onUpdate: (val) {
        if (mounted)
          setState(() {
            print('New Value -> $val');
          });
      },
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final count = _controller.state;
    return Scaffold(
      appBar: AppBar(
        title: Text('Undo/Redo Example'),
      ),
      body: Center(
        child: Text('Count: $count'),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          children: <Widget>[
            IconButton(
              icon: Icon(Icons.arrow_back),
              onPressed: !_controller.canUndo
                  ? null
                  : () {
                      if (mounted)
                        setState(() {
                          _controller.undo();
                        });
                    },
            ),
            IconButton(
              icon: Icon(Icons.arrow_forward),
              onPressed: !_controller.canRedo
                  ? null
                  : () {
                      if (mounted)
                        setState(() {
                          _controller.redo();
                        });
                    },
            ),
          ],
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
      floatingActionButton: FloatingActionButton(
        heroTag: ValueKey('add_button'),
        child: Icon(Icons.add),
        onPressed: () {
          _controller.modify(count + 1);
        },
      ),
    );
  }
}
Comments
  • Why use async function rather than sync ?

    Why use async function rather than sync ?

    https://github.com/rodydavis/undo/blob/e3b21e2ebe15c462919a3fab5373540de8d27791/lib/src/undo_stack.dart#L89

    with redo and undo functions being async function, will it be ok to invoke them inside setState((){}) ?

    opened by Quanhua-Guan 4
  • Can't undo first item in history

    Can't undo first item in history

    Since the update to undo 1.3.0+1 I cannot undo the first element in the history. The status of the property canUndo is false although the history list still contains an element.

    screenshot-undo

    As you can see in the screenshot of the watch _history has one element but canUndo is false and calling the function undo dose not work. it works as expectet in version 1.1.0+1

    opened by SergeBerwert 3
  • Doubling group changes

    Doubling group changes

    Hello. There is a bag: My situation:

        var changes = ChangeStack();
        var a = 0;
        var change = Change.inline(() => a++, () => a--);
    
        changes.group();
        changes.add(change);
        print(a); // 1
        changes.add(change);
        print(a); // 2
        changes.commit();
        print(a); // 4
    

    Situation in your example:

    count = 0;
    
    changes.group();
    
    var increase = new Change.inline(() => count++, () => count--);
    changes.add(increase);
    changes.add(increase);
    
    changes.commit();
    print(count); // 2
    
    changes.undo();
    print(count); // 0
    

    Plugin: undo 1.1.0+1

    opened by brun0xon 2
  • Fix issue can't undo first item in history

    Fix issue can't undo first item in history

    Try to fix issue #3 It works well and I don't see any issue like the comment:

      /// Can undo the previous change. If the history is equal to 1 this you cannot undo to null.
      bool get canUndo => _history.isNotEmpty && _history.length > 1;
    
    opened by ductranit 1
  • [Feature] Allow access to changes undos and redos.

    [Feature] Allow access to changes undos and redos.

    I am working on an Editor-like app, and I want to show actions history with a description, so I suggest making a getters from the _history and _redos variables.

    opened by salah-rashad 0
  • feature request: optionally cancelling adding to the stack

    feature request: optionally cancelling adding to the stack

    Sometimes, a user does an operation that triggers a function, but the operation turns out to be invalid, and state is unchanged (at least, as far as a user can tell).

    For example, in my application, items can be added in arbitrary positions on a canvas, but they are only valid depending on specific rules. Because I need to loop over a prohibitively large amount of objects, I am reluctant to do a verification pass, then an update pass; I do both at the same time. So the function is what goes in Undo's execute, whether it leads to a meaningful change or not.

    In those cases, enabling the undo button is confusing, and pressing it does nothing that the user can see or care about.

    if the line https://github.com/rodydavis/undo/blob/master/lib/src/undo_stack.dart#L20 allowed the following:

      void add<T>(Change<T> change) {
        final bool? response = change.execute();
        if(response == false){ 
          return;
         }
        _history.addLast([change]);
        _moveForward();
      }
    

    Then one could optionally return false from the execute function, which would solve my problem.

    Line https://github.com/rodydavis/undo/blob/master/lib/src/undo_stack.dart#L88 would need to be changed thusly:

    final bool? Function() _execute;
    

    ~~None of those changes break any backwards compatibility~~, and they make things more convenient.

    Passing lambdas works, but typed named void functions don't, so it is backward compatibility breaking. dynamic works, I'm not acquainted with Dart enough to know if something else works better.

    Then, one could write:

    changes.add(Change(
      data, 
      (){
         try{
          attemptInsertData();
          return true;
         }catch(e){
          return false;
        }
      }, 
      (old) => data = old
      ));
    

    If you like this change, I can create a PR.

    opened by Xananax 1
Owner
Rody Davis
Developer Advocate for @material-components at @Google
Rody Davis
Been together app with undo button

been_together_undo A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you start

Nguyễn Đức Mạnh 5 Nov 24, 2021
A discord bot, made with Dart, which lets you run your own pure Dart code snippets directly via a discord ping, and get the output in an instant.

A discord bot, made with Dart, which lets you run your own pure Dart code snippets directly via a discord ping, and get the output in an instant.

Anikate De 3 Oct 21, 2022
A Dart library for creating a Dart object to represent directory trees.

Directory Tree A Dart library for creating a Dart object to represent directory trees. Getting Started Import and initialize package import 'package:d

Chiziaruhoma Ogbonda 5 Dec 1, 2021
A collection of Dart code samples by Dart DevRel

Dart samples A collection of Dart programs that illustrate features and best practices. For a list of community-maintained projects, see Awesome Dart.

Dart 458 Dec 30, 2022
Expenses tracker built with Flutter and Dart making use of Provider, Intl, Syncfusion Flutter Datepicker and more

expense_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if t

Atuoha Anthony 2 Dec 10, 2022
A fast and space efficient library to deal with data in Dart, Flutter and the web.

Dart Data Dart Data is a fast and space efficient library to deal with data in Dart, Flutter and the web. As of today this mostly includes data struct

Lukas Renggli 14 Nov 4, 2022
A API integrated 5 day weather forecast and prediction application created using flutter framework and Dart language.

A API integrated 5 day weather forecast and prediction application created using flutter framework and Dart language. This API used here is OPEN WEATHER API, which specializes in predicting the weather of any city in this world.

Nitin Verma 0 Dec 26, 2021
Stream Feed official Flutter SDK. Build your own feed experience using Dart and Flutter.

Official Flutter packages for Stream Activity Feeds The official Dart client for Stream Activity Feeds, a service for building activity feed applicati

Stream 67 Sep 26, 2022
Pensil Community official Flutter SDK. Build your own community experience using Dart and Flutter.

Official flutter package for Pensil The official Dart client for Pensil communities, a service for building communites applications. This library can

Pensil Inc 6 Oct 6, 2022
A multiplatform Dart movie app with 40% of code sharing between Flutter and the Web.

A multiplatform Dart movie app with 40% of code sharing between Flutter and the Web.

Iiro Krankka 3.4k Dec 30, 2022
GChat is a chatting application developed using Flutter(Dart) and firebase for 2 users. Trying to Develop an application that does not sell your data with whatsapp rolling out its privacy policy updates.

Gchat - The Chatting Application A Flutter project for chatting. I used Android Studio and you can you any editor of your choice for ex: VS Code, Inte

Sanchaksh Kaul 6 Nov 6, 2022
Software of Application using Dart, Flutter, Kotlin,Swift,Objective-C, and NodeJS

TouchMe-MobileApp-Dart-And-Flutter Description Software of Application using Dart, Flutter and Kotlin. Installation Using Dart 2.13.1, Flutter 2.2.1,

Daniel Arturo Alejo Alvarez 7 Nov 9, 2021
Routinger is a task scheduler app that is made to make you a better person at no extra cost. The code is open-source. Dart language and Flutter framework are used extensively.

Routinger This is a simple app that will allow you to schedule your tasks, create a simple to-do, and also make recurring tasks. The app ends you noti

Routinger 16 Dec 17, 2022
An open source task manager (todo list) app, developed using Dart language and Flutter framework.

Tasker An open source task manager (todo list) app, developed using Dart language and Flutter framework. Screenrecords     Screenshots                

Erfan Rahmati 42 Dec 29, 2022
The Fuse Wallet is a cross platform Ethereum wallet written in Dart and built on Flutter.

Fuse Wallet The Fuse Wallet is a cross platform Ethereum wallet written in Dart and built on Flutter. It's runninng on the Fuse network, but can be pl

null 4 Nov 9, 2022
🚀 Full-Stack Flutter application, encoded using Dart. Utilizes native device features 📷 and stores user data on a local SQFLite database. ✔

great_places_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started

Soumyadeep Das 2 Jan 24, 2022
This Dart package will utilize the plugin, google_mobile_ads, so to quickly and easily implement ads into a Flutter app.

Ads to your App in a Snap! This Dart package will utilize the plugin, google_mobile_ads, so to quickly and easily implement ads into a Flutter app

Andrious Solutions Ltd. 58 Sep 11, 2022
A cross platform todo list app using flutter and dart programming language

Flutter Todos A cross platform todo list app using flutter and dart programming language. In this application, I used SQLite3 to persist data. The app

Mahmud Ahsan 61 Dec 29, 2022
🌍 Full-stack travel app using Flutter, Dart and Geolocation service. Map updates 🗺 along with map markers based on location filters 📌

Tripscape ?? Built With Frontend Flutter Dart Backend & Libraries Geolocator Google Maps Flutter Provider API Places API Google Maps API Places Autoco

Soumyadeep Das 3 Nov 23, 2022