Skip to content

Commit

Permalink
Refactor Bloc to extend Stream<State> (#572)
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel authored Oct 14, 2019
1 parent aabcd04 commit c9b6674
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 63 deletions.
4 changes: 2 additions & 2 deletions packages/bloc/example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ class CounterBloc extends Bloc<CounterEvent, int> {
case CounterEvent.decrement:
// Simulating Network Latency
await Future<void>.delayed(Duration(seconds: 1));
yield currentState - 1;
yield state - 1;
break;
case CounterEvent.increment:
// Simulating Network Latency
await Future<void>.delayed(Duration(milliseconds: 500));
yield currentState + 1;
yield state + 1;
break;
default:
throw Exception('unhandled event: $event');
Expand Down
32 changes: 24 additions & 8 deletions packages/bloc/lib/src/bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,42 @@ import 'package:rxdart/rxdart.dart';

/// Takes a [Stream] of [Event]s as input
/// and transforms them into a [Stream] of [State]s as output.
abstract class Bloc<Event, State> {
abstract class Bloc<Event, State> extends Stream<State> {
final PublishSubject<Event> _eventSubject = PublishSubject<Event>();

BehaviorSubject<State> _stateSubject;

/// Returns [Stream] of [State]s.
/// Usually consumed by the presentation layer.
Stream<State> get state => _stateSubject.stream;
/// Returns the current [State] of the [Bloc].
State get state => _stateSubject.value;

/// Returns the [State] before any [Event]s have been `dispatched`.
State get initialState;

/// Returns the current [State] of the [Bloc].
State get currentState => _stateSubject.value;
/// Returns whether the `Stream<State>` is a broadcast stream.
bool get isBroadcast => _stateSubject.isBroadcast;

Bloc() {
_stateSubject = BehaviorSubject<State>.seeded(initialState);
_bindStateSubject();
}

/// Adds a subscription to the `Stream<State>`.
/// Returns a [StreamSubscription] which handles events from the `Stream<State>`
/// using the provided [onData], [onError] and [onDone] handlers.
StreamSubscription<State> listen(
void onData(State value), {
Function onError,
void onDone(),
bool cancelOnError,
}) {
return _stateSubject.listen(
onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}

/// Called whenever an [Event] is dispatched to the [Bloc].
/// A great spot to add logging/analytics at the individual [Bloc] level.
void onEvent(Event event) => null;
Expand Down Expand Up @@ -136,9 +152,9 @@ abstract class Bloc<Event, State> {
return mapEventToState(currentEvent).handleError(_handleError);
})).forEach(
(State nextState) {
if (currentState == nextState || _stateSubject.isClosed) return;
if (state == nextState || _stateSubject.isClosed) return;
final transition = Transition(
currentState: currentState,
currentState: state,
event: currentEvent,
nextState: nextState,
);
Expand Down
21 changes: 12 additions & 9 deletions packages/bloc/test/bloc_delegate_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void main() {
when(delegate.onEvent(any, any)).thenReturn(null);

expectLater(
complexBloc.state,
complexBloc,
emitsInOrder(expectedStateAfterEventB),
).then((dynamic _) {
verify(
Expand Down Expand Up @@ -53,7 +53,7 @@ void main() {
when(delegate.onEvent(any, any)).thenReturn(null);

expectLater(
complexBlocA.state,
complexBlocA,
emitsInOrder(expectedStateAfterEventB),
).then((dynamic _) {
verify(
Expand All @@ -65,7 +65,7 @@ void main() {
});

expectLater(
complexBlocB.state,
complexBlocB,
emitsInOrder(expectedStateAfterEventC),
).then((dynamic _) {
verify(
Expand All @@ -91,7 +91,7 @@ void main() {
when(delegate.onEvent(any, any)).thenReturn(null);

expectLater(
complexBloc.state,
complexBloc,
emitsInOrder(expectedStateAfterEventB),
).then((dynamic _) {
verifyNever(
Expand Down Expand Up @@ -121,7 +121,7 @@ void main() {
when(delegate.onTransition(any, any)).thenReturn(null);

expectLater(
complexBloc.state,
complexBloc,
emitsInOrder(expectedStateAfterEventB),
).then((dynamic _) {
verify(
Expand Down Expand Up @@ -155,7 +155,7 @@ void main() {
when(delegate.onTransition(any, any)).thenReturn(null);

expectLater(
complexBlocA.state,
complexBlocA,
emitsInOrder(expectedStateAfterEventB),
).then((dynamic _) {
verify(
Expand All @@ -171,7 +171,7 @@ void main() {
});

expectLater(
complexBlocB.state,
complexBlocB,
emitsInOrder(expectedStateAfterEventC),
).then((dynamic _) {
verify(
Expand Down Expand Up @@ -201,7 +201,7 @@ void main() {
when(delegate.onTransition(any, any)).thenReturn(null);

expectLater(
complexBloc.state,
complexBloc,
emitsInOrder(expectedStateAfterEventB),
).then((dynamic _) {
verifyNever(
Expand Down Expand Up @@ -238,7 +238,10 @@ void main() {
errorHandled = true;
});

expectLater(_bloc.state, emitsInOrder(<int>[0])).then((dynamic _) {
expectLater(
_bloc,
emitsInOrder(<int>[0]),
).then((dynamic _) {
expect(errorHandled, isTrue);
expect(blocWithError, _bloc);
});
Expand Down
Loading

0 comments on commit c9b6674

Please sign in to comment.