state_graph_bloc 1.0.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 73

state_graph_bloc #

State Graph Builder for Dart. Allows to define states, their transitions and side effects in a result of incoming events.

Inspired by Tinder's state machine Kotlin DSL. Based on awesome BLoC package.

Usage #

StateGraphBloc is just a subclass of Bloc from bloc package which overrides mapEventToState function to use graph map.

Read more about bloc package and how to use it at bloc homepage. To use it with flutter, consider also flutter_bloc.

class DummyBloc extends StateGraphBloc<DummyEvent, DummyState> {
  @override
  DummyState get initialState => StateInitialising();

  @override
  StateGraph<DummyEvent, DummyState> buildGraph() =>
      StateGraph<DummyEvent, DummyState>(
        {
          StateInitialising: {
            LoadEvent: transitionWithSideEffect(
              (state, event) => StateLoading(),
              (state, event) {
                // There could be some async loading. Use [launchFuture] or [launchStream]
                // to fire async processing and properly handle bloc closing.
                add(LoadingCompletedEvent());
              },
            ),
          },
          StateLoading: {
            LoadingCompletedEvent: transition((state, _) => StateReady(0)),
          },
          StateReady: {
            IncrementEvent: transition(
              (state, event) => StateReady((state as StateReady).counter + 1),
            ),
            // Test global event override.
            RestartEvent: transition((state, _) => StateReady(0)),
          },
        },
        {
          RestartEvent: transition((state, event) {
            return StateInitialising();
          })
        },
      );

  // Bind some variables based on [state].
  Stream<bool> isLoading() => bindState((state) {
        if (state is StateLoading) {
          return true;
        } else {
          return false;
        }
      });
}

Samples #

You can experiment with sample application hosted here: https://gitlab.com/marcin.jelenski/bloc-showcase

Also test directory contains all State Graph Bloc use cases.

[1.0.0] - 8.05.2020 #

  • Update bloc dependency to 4.0.0.

[0.1.0+2] - 2.12.2019 #

  • Wider dependencies.

[0.1.0+1] - 1.12.2019 #

  • Promote to 0.1.0.

[0.0.8] - 1.12.2019 #

  • Fix side effect call issue.

[0.0.7] - 1.12.2019 #

  • Fix dynamic cast bug.

[0.0.6] - 1.12.2019 #

  • Improved state and event cast.

[0.0.5] - 28.11.2019 #

  • Repair api doc sample.

[0.0.4] - 28.11.2019 #

  • Update description.

[0.0.3] - 28.11.2019 #

  • Add example.

[0.0.2] - 28.11.2019 #

  • Update readme.

[0.0.1] - 23.11.2019 #

  • Initial release.

example/main.dart

import 'package:state_graph_bloc/state_graph_bloc.dart';

// Enumerate states.

abstract class DummyState {}

class StateInitialising extends DummyState {
  @override
  bool operator ==(Object other) => hashCode == other.hashCode;

  @override
  int get hashCode => runtimeType.hashCode;
}

class StateLoading extends DummyState {
  @override
  bool operator ==(Object other) => hashCode == other.hashCode;

  @override
  int get hashCode => runtimeType.hashCode;
}

class StateReady extends DummyState {
  StateReady(this.counter);

  final int counter;

  @override
  bool operator ==(Object other) => hashCode == other.hashCode;

  @override
  int get hashCode => runtimeType.hashCode ^ counter.hashCode;
}

// Enumerate events

abstract class DummyEvent {}

class LoadEvent extends DummyEvent {}

class LoadingCompletedEvent extends DummyEvent {}

class LoadingErrorEvent extends DummyEvent {}

class IncrementEvent extends DummyEvent {}

class SideEffectCauseEvent extends DummyEvent {}

class RestartEvent extends DummyEvent {}

// Define bloc with graph transitions

class DummyBloc extends StateGraphBloc<DummyEvent, DummyState> {

  // Create "single live events".
  SingleLiveEventSubject<String> _actionEvent;
  Stream<SingleLiveEvent<String>> action;

  DummyBloc() {
    _actionEvent = singleLiveEventSubject();
    action = _actionEvent.stream;
  }


  @override
  DummyState get initialState => StateInitialising();

  @override
  StateGraph<DummyEvent, DummyState> buildGraph() =>
      StateGraph<DummyEvent, DummyState>(
        {
          StateInitialising: {
            LoadEvent: transitionWithSideEffect(
              (state, event) => StateLoading(),
              (state, event) {
                // Call single live events
                _actionEvent.add("sample-event-data");
                // Add events as a side effects
                add(LoadingCompletedEvent());
              },
            ),
          },
          StateLoading: {
            LoadingCompletedEvent: transition((state, event) => StateReady(0)),
          },
          StateReady: {
            IncrementEvent: transition(
              (StateReady state, event) => StateReady(state.counter + 1),
            ),
            // Test global event override.
            RestartEvent: transition((state, event) => StateReady(0)),
          },
        },
        {
          RestartEvent: transition((state, event) {
            return StateInitialising();
          })
        },
      );

  Stream<bool> isLoading() => bindState((state) {
        if (state is StateLoading) {
          return true;
        } else {
          return false;
        }
      });
}

// Listen to BLoC state.

void main() {
  final bloc = DummyBloc();

  // Access current state.
  bloc.state;

  // Listen to bloc (stream) updates.
  bloc.listen((state) => print("On state change"));

  // Listen to bloc field updates.
  bloc
      .isLoading()
      .listen((isLoading) => print("Is currently loading: $isLoading"));

  // Listen to bloc single live events.
  // Call `use` to consume and  receive event data.
  bloc.action.listen((event) {
    event.use((it) => print("Event received: $it"));
  });

  // Add events.
  bloc.add(LoadEvent());
}

Use this package as a library

1. Depend on it

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


dependencies:
  state_graph_bloc: ^1.0.0

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_graph_bloc/state_graph_bloc.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
51
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
73
Learn more about scoring.

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

  • Dart: 2.8.4
  • pana: 0.13.13

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (bloc).

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.2 <3.0.0
bloc ^4.0.0 4.0.0 5.0.0
rxdart ^0.24.0 0.24.1
Transitive dependencies
meta 1.1.8
Dev dependencies
bloc_test ^5.1.0
effective_dart ^1.1.0
mockito ^4.1.1
test ^1.3.0