state_machina 1.1.9

  • Readme
  • Changelog
  • Example
  • Installing
  • new60

State Machina [steyt mah-kuh-nuh] 🤖 #

A super simple, zero dependency, tiny state machine for Flutter and other Dart apps.

Basic Usage #

import 'package:state_machina/state_machina.dart';

// Define your states and events in a couple of handy enums for easy reference:
enum States { enteringEmail, sendingEmail, success }
enum Events { editEmail, sendEmail, sentEmail, failedToSendEmail }

// Create a state machine like so:
var state = StateMachine({
  States.editingEmail: {Events.sendEmail: States.sendingEmail},
  States.sendingEmail: {
    Events.sentEmail: States.success,
    Events.failedToSendEmail: States.error,
  },
  States.success: {}, // This is a terminal state--no other states can be entered once we get here ☠️
  States.error: {Events.editEmail: States.editingEmail}
});

Now you can read the current state:

// in some Flutter widget
if (state.current == States.success) return SuccessMessage()

And send events:

// somewhere in your Flutter app...
RaisedButton(
  onPressed: () async {
    try {
      setState(() {
        state.send(Events.sendEmail);
      });

      await _sendEmail();

      setState(() {
        state.send(Events.sentEmail);
      });
    } catch (e) {
      state.send(Events.failedToSendEmail);
    }
  },
  child: const Text('Submit')
)
  • You may pass an optional initialState as the second argument. If not, the initial state defaults to the key of the first entry in the state map.
  • Runtime exceptions will be thrown if you pass in an invalid state map (unreachable states, next states that don't exist) or an invalid initial state, or if you send an event that doesn't exist in the state map.
  • The type of individual states can be anything: String, int, object. You simply have to ensure that your state map is valid (you'll get helpful error messages if it isn't).
  • You could also store your states and events in classes, if desired:
class States {
  static final String enteringEmail = 'enteringEmail';
  static final String sendingEmail = 'sendingEmail';
  static final String success = 'success';
}

And for that matter, nothing is stopping you from passing in literal values:

var state = StateMachine({
  'editingEmail': {'sendEmail': 'sendingEmail'},
  'sendingEmail': {
    'sentEmail': 'success',
    'failedToSendEmail': 'error',
  },
  'success': {},
  'error': {'editEmail': 'editingEmail'}
});

Typically, strings or enums are the most useful types for the primitive keys and values in your state map.

Listeners #

Listeners can be registered and will be called every time send is called, after send resolves the event and updates the current state. Listeners receive the current state, previous state, and event that triggered the listener:

  state.addListener((current, previous, event) {
    // Do some cool stuff here
  })

Changelog #

1.1.9 #

  • Remove usage of dart:mirrors to check for enums since that can't run in flutter 😱

1.1.8 #

  • Add listeners 🎧

1.1.7 #

  • Add an example

1.1.6 #

  • Add dartdoc documentation ✍️

1.1.5 #

  • Update README. Also, retroactively bump minor because 1.0.4 should have been a minor to 1.1.3, which would have landed this at 1.1.4 😊

1.0.5 #

  • The mysterious missing version. This makes the pub tool happy 🤫

1.0.4 #

  • Add events! We can create full-fledged finite state machines now 🥳

1.0.3 #

  • Support using enums (or anything you want) to define states

1.0.2 #

  • Update README

1.0.1 #

  • Update README

1.0.0 #

  • Initial version 🚀

example/main.dart

import 'package:state_machina/state_machina.dart';

enum States { editingEmail, sendingEmail, success, error }
enum Events { editEmail, sendEmail, sentEmail, failedToSendEmail }

var stateMap = {
  States.editingEmail: {Events.sendEmail: States.sendingEmail},
  States.sendingEmail: {
    Events.sentEmail: States.success,
    Events.failedToSendEmail: States.error,
  },
  States.success: {},
  States.error: {Events.editEmail: States.editingEmail}
};

void main() {
  var state = StateMachine(stateMap);

  print('state.current: ${state.current}\n'); // States.editingEmail

  var stateWithCustomInitialState = StateMachine(stateMap, States.sendingEmail);

  print(
      'stateWithCustomInitialState.current: ${stateWithCustomInitialState.current}\n'); // States.sendingEmail

// Back to our first state machine...
  print('Sending event ${Events.sendEmail} to "state"\n');
  state.send(Events.sendEmail);

  print('state.current: ${state.current}'); // States.sendingEmail
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  state_machina: ^1.1.9

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:state_machina/state_machina.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
21
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
60
Learn more about scoring.

We analyzed this package on Mar 30, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.0 <3.0.0
Dev dependencies
test 1.14.1