8000 feat(flutter_bloc): support listener current state by zbarbuto · Pull Request #4405 · felangel/bloc · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat(flutter_bloc): support listener current state #4405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion packages/flutter_bloc/lib/src/bloc_listener.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ typedef BlocListenerCondition<S> = bool Function(S previous, S current);
/// )
/// ```
/// {@endtemplate}
///
/// {@template bloc_listener_start_with_current_state}
/// By default, the [listener] will only be called on new state emissions from
/// the bloc. If you want to call the listener with the current state
/// immediately, set [startWithCurrentState] to true.
/// Note that [listenWhen] is not called for the current state (as there is no
/// previous state to compare to).
///
/// ```dart
/// // Default behavior
/// BlocListener<BlocA, BlocAState>(
/// listener: (context, state) {
/// // this is only called when BlocA emits new states
/// },
/// )
///
/// BlocListener<BlocA, BlocAState>(
/// startWithCurrentState: true,
/// listener: (context, state) {
/// // this is now called immediately with BlocA's current state
/// // in addition to new emissions
/// },
/// )
/// ```
/// {@endtemplate}
class BlocListener<B extends StateStreamable<S>, S>
extends BlocListenerBase<B, S> {
/// {@macro bloc_listener}
Expand All @@ -83,13 +108,15 @@ class BlocListener<B extends StateStreamable<S>, S>
Key? key,
B? bloc,
BlocListenerCondition<S>? listenWhen,
bool startWithCurrentState = false,
Widget? child,
}) : super(
key: key,
child: child,
listener: listener,
bloc: bloc,
listenWhen: listenWhen,
startWithCurrentState: startWithCurrentState,
);
}

Expand All @@ -109,6 +136,7 @@ abstract class BlocListenerBase<B extends StateStreamable<S>, S>
this.bloc,
this.child,
this.listenWhen,
this.startWithCurrentState = false,
}) : super(key: key, child: child);

/// The widget which will be rendered as a descendant of the
Expand All @@ -127,6 +155,9 @@ abstract class BlocListenerBase<B extends StateStreamable<S>, S>
/// {@macro bloc_listener_listen_when}
final BlocListenerCondition<S>? listenWhen;

/// {@macro bloc_listener_start_with_current_state}
final bool startWithCurrentState;

@override
SingleChildState<BlocListenerBase<B, S>> createState() =>
_BlocListenerBaseState<B, S>();
Expand All @@ -142,6 +173,14 @@ abstract class BlocListenerBase<B extends StateStreamable<S>, S>
'listenWhen',
listenWhen,
),
)
..add(
FlagProperty(
'startWithCurrentState',
value: startWithCurrentState,
ifTrue: 'with current state',
ifFalse: 'without current state',
),
);
}
}
Expand Down Expand Up @@ -209,8 +248,20 @@ class _BlocListenerBaseState<B extends StateStreamable<S>, S>
super.dispose();
}

Stream<T> _startWithValue<T>(
T value,
Stream<T> originalStream,
) async* {
yield value;
yield* originalStream;
}

void _subscribe() {
_subscription = _bloc.stream.listen((state) {
final stream = widget.startWithCurrentState
? _startWithValue(_bloc.state, _bloc.stream)
: _bloc.stream;

_subscription = stream.listen((state) {
if (!mounted) return;
if (widget.listenWhen?.call(_previousState, state) ?? true) {
widget.listener(context, state);
Expand Down
47 changes: 47 additions & 0 deletions packages/flutter_bloc/test/bloc_listener_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,52 @@ void main() {
expect(states, expectedStates);
});

testWidgets(
'calls listener with initial state when startWithCurrentState is true',
(tester) async {
final counterCubit = CounterCubit();
final states = <int>[];
const expectedStates = [0];
await tester.pumpWidget(
BlocListener<CounterCubit, int>(
bloc: counterCubit,
startWithCurrentState: true,
listener: (_, state) {
states.add(state);
},
child: const SizedBox(),
),
);

await tester.pump();

expect(states, expectedStates);
});

testWidgets(
'calls listener when further states emitted when startWithCurrentState '
'is true', (tester) async {
final counterCubit = CounterCubit();
final states = <int>[];
const expectedStates = [0, 1];
await tester.pumpWidget(
BlocListener<CounterCubit, int>(
bloc: counterCubit,
startWithCurrentState: true,
listener: (_, state) {
states.add(state);
},
child: const SizedBox(),
),
);

await tester.pump();
counterCubit.increment();
await tester.pump();

expect(states, expectedStates);
});

testWidgets('overrides debugFillProperties', (tester) async {
final builder = DiagnosticPropertiesBuilder();

Expand All @@ -528,6 +574,7 @@ void main() {
"bloc: Instance of 'CounterCubit'",
'has listener',
'has listenWhen',
'without current state',
],
);
});
Expand Down
0