I've gone though some answers already, and doing the stuff that's mentioned overthere but nothing is working. I'm using cubit/state arhic. for my project. And here's the flow:
State class
@immutable
class SastaWalletBalanceState extends Equatable {
static bool match(SastaWalletState a, SastaWalletState b) =>
a.balance != b.balance;
final num? data;
final String? message;
SastaWalletBalanceState({
this.data,
this.message,
});
@override
List<Object?> get props => [
this.data,
this.message,
];
}
@immutable
class SastaWalletBalanceDefault extends SastaWalletBalanceState {}
@immutable
class SastaWalletBalanceLoading extends SastaWalletBalanceState {
SastaWalletBalanceLoading() : super();
}
@immutable
class SastaWalletBalanceSuccess extends SastaWalletBalanceState {
SastaWalletBalanceSuccess({num? data}) : super(data: data);
}
@immutable
class SastaWalletBalanceFailed extends SastaWalletBalanceState {
SastaWalletBalanceFailed({String? message}) : super(message: message);
}
Cubit function
Future<void> getBalance() async {
emit(state.copyWith(
balance: SastaWalletBalanceLoading(),
));
try {
final data = await repo.getBalance();
emit(state.copyWith(
balance: SastaWalletBalanceSuccess(data: data),
));
} catch (e) {
emit(state.copyWith(
balance: SastaWalletBalanceFailed(message: e.toString()),
));
}
}
UI part
Here's the problem, the MultiBlocListener, all other BlocListener are working fine except the one using this state, although I'm getting data from cubit, and from API.
...rest of the code
return MultiBlocListener(
listeners: [
BlocListener<SastaWalletCubit, SastaWalletState>(
listenWhen: STWalletInitSessionState.match,
listener: (context, state) async {
final otpAlreadySent =
state.initSession is STWalletInitSessionFailed &&
state.initSession!.message!.contains('already sent');
final message = state.initSession?.message?.split(': ').lastOrNull;
if (otpAlreadySent) {
buttonLabel = 'Cancel';
stCubit.getBalance();
stateProvider.setStWallet(true);
SnackBars.e(context, message!);
}
if (state.initSession is STWalletInitSessionFailed &&
!otpAlreadySent) {
buttonLabel = 'Use';
stateProvider.setStWallet(false);
stateProvider.setPartialPayment(false);
SnackBars.e(context, message!);
}
// If wallet session is already initiated it will contain a specific message
// In this case, make the get_balance call
else if (state.initSession is STWalletInitSessionSuccess &&
state.initSession!.data!.message!
.contains('A session had already been started.')) {
stCubit.getBalance();
stateProvider.setStWallet(true);
}
// Initiate session first time or if session has expired
else if (state.initSession is STWalletInitSessionSuccess ||
otpAlreadySent) {
final dsmState = DSMProvider.state(context);
dsmState.setDurationOTP(context, duration: otpDuration!);
dsmState.startOtpTimer();
final validated = await showModalBottomSheet<bool?>(
context: context,
isDismissible: false,
enableDrag: false,
backgroundColor: Colors.transparent,
builder: (context) {
return const _OTPModal();
},
);
// Incase of validation, make get_balance call
if (validated != null && validated) {
stCubit.getBalance();
buttonLabel = 'Cancel';
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
stateProvider.setStWallet(true);
});
} else {
stateProvider.setStWallet(false);
stateProvider.setPartialPayment(false);
}
}
},
),
BlocListener<SastaWalletCubit, SastaWalletState>(
listenWhen: STWalletValidateSessionState.match,
listener: (context, state) {
if (state.validateSessionState is STWalletValidateSessionFailed) {
buttonLabel = 'Use';
stateProvider.setStWallet(false);
stateProvider.setPartialPayment(false);
}
},
),
BlocListener<SastaWalletCubit, SastaWalletState>(
listenWhen: SastaWalletBalanceState.match,
listener: (context, state) {
print('----- balance listener -----');
print(state.balance);
if (state.balance is SastaWalletBalanceSuccess) { <--- THIS IS NOT PRINTING
print('--- balance success -----');
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (_) {
return ListenableProvider.value(
value: stateProvider,
builder: (context, child) {
return DSMBottomPriceWidgetAfterBooking(
walletBalanceCall: true,
order: order,
payNow: !stateProvider.isPartialPaymentViaWallet
? PayNow.visible
: PayNow.hidden,
payNowCall: () {
final walletProvider = bookingCubit
.state.paymentProvider!.data!
.where((element) => element.code!.contains(
DSMPaymentProviderMapping.stWallet))
.first;
final walletCode =
walletProvider.methods!.first.code;
stateProvider.setPaymentMethod(
walletProvider.methods!.first);
bookingCubit.paymentTransaction(
walletCode,
order.orderId,
promoCode: {},
);
},
isExpanded: true,
);
},
);
});
}
},
)
],
//// .... rest of the code
There was something wrong with a
ChangeNotifierthat keeps on rebuilding the screen and hence the listener was not getting a chance to handle the success state.Moral of story: Always check if your current screen is rebuilding without any reason or not.