This The Bloc Provider..
class PaymentHistoryScreen extends StatefulWidget {
static const String routeName = '/payment-history';
PaymentHistoryScreen({super.key, required this.hospitalNumber});
final String hospitalNumber;
@override
State<PaymentHistoryScreen> createState() => _PaymentHistoryScreenState();
}
class _PaymentHistoryScreenState extends State<PaymentHistoryScreen> {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => PaymentHistoryBloc(getService()),
// ..add(
// PaymentHistoryGet(
// hospitalNumber: widget.hospitalNumber,
// ),
// ),
),
BlocProvider(
create: (context) => InvoiceDetailsBloc(getService()),
),
BlocProvider(
create: (context) =>
CompanyLocationBloc(getService())..add(CompanyLocationsGet()),
),
],
child: PaymentHistoryScreenTop(
hospitalNumber: widget.hospitalNumber,
),
);
}
}
TabBar Controller..
class PaymentHistoryScreenBodyState extends State<PaymentHistoryScreenBody>
with TickerProviderStateMixin {
late TabController tabviewController;
@override
void initState() {
super.initState();
tabviewController = TabController(
length: 3,
vsync: this,
initialIndex: 0,
);
TabBarView..
Expanded(
child: SizedBox(
height: 408.v,
child: TabBarView(
controller: tabviewController,
children: [
PaymentHistoryTab(
paymentHistories: state.diagnosisList,
),
PaymentHistoryTab(
paymentHistories: state.consultList,
),
PaymentHistoryTab(
paymentHistories: state.pharmacyList,
),
],
),
),
),
Bloc Code...
sealed class InvoiceDetailsEvent {}
final class InvoiceDetailsGet extends InvoiceDetailsEvent {
final String invoiceId;
final int billModuleNo;
InvoiceDetailsGet({required this.invoiceId, required this.billModuleNo});
}
sealed class InvoiceDetailsState {}
final class InvoiceDetailsInitial extends InvoiceDetailsState {}
final class InvoiceDetailsLoading extends InvoiceDetailsState {}
final class InvoiceDetailsSuccess extends InvoiceDetailsState {
final List<ItemDtls> response;
InvoiceDetailsSuccess({required this.response});
}
final class InvoiceDetailsError extends InvoiceDetailsState {
final Object error;
InvoiceDetailsError({required this.error});
}
class InvoiceDetailsBloc
extends Bloc<InvoiceDetailsEvent, InvoiceDetailsState> {
final DataRepository _dataRepository;
InvoiceDetailsBloc(this._dataRepository) : super(InvoiceDetailsInitial()) {
on<InvoiceDetailsGet>((event, emit) async {
emit(InvoiceDetailsLoading());
try {
var response = await _dataRepository.getInvoiceDetailsByInvoiceId(
invoiceId: event.invoiceId, billModuleNo: event.billModuleNo);
if (response.isNotEmpty) {
emit(InvoiceDetailsSuccess(response: response));
} else {
throw CustomException("No data found for this invoice");
}
} catch (e) {
emit(InvoiceDetailsError(error: e));
}
});
}
}
calling the bloc in this page
// ignore: must_be_immutable
class InvoicedetailslistItemWidget extends StatelessWidget {
const InvoicedetailslistItemWidget({Key? key, required this.item})
: super(
key: key,
);
final InvoiceItem item;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 6.v, vertical: 14.h),
decoration: AppDecoration.fillCyan,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 50.adaptSize,
width: 50.adaptSize,
decoration: AppDecoration.fillBlueGray,
child: CustomImageView(
svgPath: ImageConstant.imgThumbsUpPrimary,
height: 50.adaptSize,
width: 50.adaptSize,
alignment: Alignment.center,
),
),
Padding(
padding: EdgeInsets.only(left: 13.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"INVOICE ID: ${item.invoiceId ?? "N/A"}",
style: CustomTextStyles.bodySmallBlack900,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: 5.v),
Text(
"Date: ${item.invoiceDate?.toFormattedString("dd MMM yyyy") ?? "N/A"}",
style: CustomTextStyles.bodySmallBluegray300,
),
SizedBox(height: 5.v),
Text(
"Time: ${item.invoiceDateTime?.toFormattedString("hh:mm a").toLowerCase() ?? "N/A"}",
style: CustomTextStyles.bodySmallBluegray300,
),
],
),
),
BlocListener<InvoiceDetailsBloc, InvoiceDetailsState>(
listener: (context, state) async {
if (state is InvoiceDetailsSuccess) {
context.pushNamed(
ReportViewScreen.routeName,
extra: {"report": item, "data": data},
);
}
if (state is InvoiceDetailsError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.error.toString()),
),
);
}
},
child: CustomOutlinedButton(
onPressed: () async {
BlocProvider.of<InvoiceDetailsBloc>(context).add(
InvoiceDetailsGet(
invoiceId: item.invoiceId!, billModuleNo: 1));
},
height: 38.v,
width: 70.h,
text: "View ",
margin: EdgeInsets.only(
left: 22.h,
top: 11.v,
bottom: 11.v,
),
buttonStyle: CustomButtonStyles.outlinePinkTL6,
buttonTextStyle: CustomTextStyles.labelLargePrimary,
),
),
],
),
);
}
}
Here i am the calling the bloc event single time but the bloc listener listening the same success sate twice and due to that navigating the same screen twice. i am unable to debug why bloc is triggering the same state twice. how to solve this.??? note: 1.the page is under a tabbarview. 2. Also InvoicedetailslistItemWidget is building with listview builder.