GitXplorerGitXplorer
g

state_machina

public
5 stars
1 forks
0 issues

Commits

List of commits on branch master.
Verified
58e6d463a4b29921ff5dd63ca8d03bf7e56af481

Merge pull request #1 from qb20nh/null-safety

ggranmoe committed 2 years ago
Unverified
d25299f294089c3723e104358383a44e88871da0

migrate to null safety

qqb20nh committed 2 years ago
Unverified
b9ebdfd921f37361d75300fde635dc6a73c76fe0

Remove usage of dart:mirrors to check for enums since that isn't supported in flutter right now

ggranmoe committed 5 years ago
Unverified
021821d2978245abb6c89912d584d600c5fdadb8

Add listeners, add check for string or enum, add tests and docs for both

ggranmoe committed 5 years ago
Unverified
7d1d55a7f140227d60665fe1c484aea1a20a2e08

Add an example

ggranmoe committed 5 years ago
Unverified
0ce8eebce986d5b92e4d2f98cfd8d2904aba3b74

Add docs using dartdoc

ggranmoe committed 5 years ago

README

The README file for this repository.

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
  })