Closed II11II closed 3 months ago
import 'dart:async';
import 'package:bloc/bloc.dart';
void main() async{
final pushNotification = PushNotification();
final v1 = V1PushNotificationBloc(pushNotification: pushNotification);
v1.add(PushNotificationEvent.started());
v1.add(PushNotificationEvent.subscribe("V1PushNotificationBlocTopic"));
await Future.delayed(Duration(seconds: 1), (){
print("\n\n\n");
});
final v2 = V2PushNotificationBloc(pushNotification: pushNotification);
v2.add(PushNotificationEvent.started());
v2.add(PushNotificationEvent.subscribe("V2PushNotificationBlocTopic"));
}
class PushNotification {
Future<String> initNotification() async {
await Future.delayed(Duration(milliseconds: 200));
return "token";
}
Future<void> subscribeToTopic(String topic) async {
await Future.delayed(Duration(milliseconds: 200));
print("PushNotification.subscribeToTopic($topic) is called");
}
Future<void> unsubscribeFromTopic(String topic) async {
await Future.delayed(Duration(milliseconds: 200));
print("PushNotification.unsubscribeFromTopic($topic) is called");
}
}
EventTransformer<Event> sequential<Event>() {
return (events, mapper) => events.asyncExpand(mapper);
}
sealed class PushNotificationEvent {
const factory PushNotificationEvent.started() = _Started;
const factory PushNotificationEvent.subscribe(String topicType) = _Subscribe;
const factory PushNotificationEvent.unsubscribe(String topicType) =
_Unsubscribe;
}
class _Started implements PushNotificationEvent {
const _Started();
}
class _Subscribe implements PushNotificationEvent {
final String topicType;
const _Subscribe(this.topicType);
}
class _Unsubscribe implements PushNotificationEvent {
final String topicType;
const _Unsubscribe(this.topicType);
}
sealed class PushNotificationState {
const factory PushNotificationState.initial() = _Initial;
const factory PushNotificationState.granted({required String token}) =
_Granted;
const factory PushNotificationState.denied() = _Denied;
}
class _Initial implements PushNotificationState {
const _Initial();
}
class _Granted implements PushNotificationState {
final String token;
const _Granted({required this.token});
}
class _Denied implements PushNotificationState {
const _Denied();
}
class V1PushNotificationBloc
extends Bloc<PushNotificationEvent, PushNotificationState> {
V1PushNotificationBloc({required PushNotification pushNotification})
: _pushNotification = pushNotification,
super(const PushNotificationState.initial()) {
on<_Started>(_onStarted, transformer: sequential());
on<_Subscribe>(_onSubscribe, transformer: sequential());
on<_Unsubscribe>(_onUnsubscribe, transformer: sequential());
}
final PushNotification _pushNotification;
FutureOr<void> _onStarted(
_Started event, Emitter<PushNotificationState> emit) async {
print(
"V1PushNotificationBloc._onStarted is called-The current state is PushNotificationState.initial");
String token = await _pushNotification.initNotification();
emit(PushNotificationState.granted(token: token));
print(
"V1PushNotificationBloc._onStarted is called-The current state is PushNotificationState.granted");
}
FutureOr<void> _onSubscribe(
_Subscribe event, Emitter<PushNotificationState> emit) =>
switch (state) {
final _Granted grantedState => (_Granted grantedState) async {
await _pushNotification.subscribeToTopic(event.topicType);
print(
"V1PushNotificationBloc._onSubscribe is called-Topic type: ${event.topicType}-The current state is granted");
}(grantedState),
_ => () {
print(
"V1PushNotificationBloc._onSubscribe is called-Topic type: ${event.topicType}-The current state is initial");
}()
};
FutureOr<void> _onUnsubscribe(
_Unsubscribe event, Emitter<PushNotificationState> emit) =>
switch (state) {
final _Granted grantedState => (_Granted grantedState) async {
await _pushNotification.unsubscribeFromTopic(event.topicType);
print(
"V1PushNotificationBloc._onUnsubscribe is called-Topic type: ${event.topicType}-The current state is granted");
}(grantedState),
_ => () {
print(
"V1PushNotificationBloc._onUnsubscribe is called-Topic type: ${event.topicType}-The current state is initial");
}()
};
}
class V2PushNotificationBloc
extends Bloc<PushNotificationEvent, PushNotificationState> {
V2PushNotificationBloc({required PushNotification pushNotification})
: _pushNotification = pushNotification,
super(const PushNotificationState.initial()) {
on<PushNotificationEvent>(
(event, emit) => switch (event) {
_Started() => _onStarted(event, emit),
_Subscribe() => _onSubscribe(event, emit),
_Unsubscribe() => _onUnsubscribe(event, emit),
},
transformer: sequential());
}
final PushNotification _pushNotification;
FutureOr<void> _onStarted(
_Started event, Emitter<PushNotificationState> emit) async {
print(
"V2PushNotificationBloc._onStarted is called-The current state is PushNotificationState.initial");
String token = await _pushNotification.initNotification();
emit(PushNotificationState.granted(token: token));
print(
"V2PushNotificationBloc._onStarted is called-The current state is PushNotificationState.granted");
}
FutureOr<void> _onSubscribe(
_Subscribe event, Emitter<PushNotificationState> emit) =>
switch (state) {
final _Granted grantedState => (_Granted grantedState) async {
await _pushNotification.subscribeToTopic(event.topicType);
print(
"V2PushNotificationBloc._onSubscribe is called-Topic type: ${event.topicType}-The current state is granted");
}(grantedState),
_ => () {
print(
"V2PushNotificationBloc._onSubscribe is called-Topic type: ${event.topicType}-The current state is initial");
}()
};
FutureOr<void> _onUnsubscribe(
_Unsubscribe event, Emitter<PushNotificationState> emit) =>
switch (state) {
final _Granted grantedState => (_Granted grantedState) async {
await _pushNotification.unsubscribeFromTopic(event.topicType);
print(
"V2PushNotificationBloc._onUnsubscribe is called-Topic type: ${event.topicType}-The current state is granted");
}(grantedState),
_ => () {
print(
"V2PushNotificationBloc._onUnsubscribe is called-Topic type: ${event.topicType}-The current state is initial");
}()
};
}
/// Output:
// V1PushNotificationBloc._onStarted is called-The current state is PushNotificationState.initial
// V1PushNotificationBloc._onSubscribe is called-Topic type: V1PushNotificationBlocTopic-The current state is initial
// V1PushNotificationBloc._onStarted is called-The current state is PushNotificationState.granted
//
//
//
//
// V2PushNotificationBloc._onStarted is called-The current state is PushNotificationState.initial
// V2PushNotificationBloc._onStarted is called-The current state is PushNotificationState.granted
// PushNotification.subscribeToTopic(V2PushNotificationBlocTopic) is called
// V2PushNotificationBloc._onSubscribe is called-Topic type: V2PushNotificationBlocTopic-The current state is granted
Hi @II11II 👋 Thanks for opening an issue!
This is working as expected. Transformers only apply to the event handler that they are applied to. If you want all events to be sequential, then you need to create a single event handler like so:
sealed class CounterEvent {}
final class Increment extends CounterEvent {}
final class Decrement extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<CounterEvent>(
(event, emit) {
return switch (event) {
Increment() => emit(state + 1),
Decrement() => emit(state - 1),
};
},
transformer: sequential(),
);
}
}
Hope that helps! Closing for now 👍
Description V1PushNotificationBloc jumps to another event processing while the first is awaited
Steps To Reproduce
Expected Behavior V1PushNotificationBloc has to proceed with each event sequentially
Actual Behavior V1PushNotificationBloc does not proceed with each event sequentially
Screenshots