From 8dea38b3a6d4ef57353b6f5837f4ce06f158ca9d Mon Sep 17 00:00:00 2001 From: venbaittech Date: Thu, 17 Jul 2025 11:04:11 +0530 Subject: [PATCH] CHANGE_PAGINATION --- lib/Screens/allTrips/list_all_plans.dart | 510 ++++++++++++----------- lib/Screens/plans/list_plans.dart | 284 +++++++------ lib/utils/pagination.dart | 247 ++++++++--- 3 files changed, 622 insertions(+), 419 deletions(-) diff --git a/lib/Screens/allTrips/list_all_plans.dart b/lib/Screens/allTrips/list_all_plans.dart index 85008e4..9e0598e 100644 --- a/lib/Screens/allTrips/list_all_plans.dart +++ b/lib/Screens/allTrips/list_all_plans.dart @@ -292,7 +292,8 @@ class _ListAllPlansState extends State { Future _showDetails(id) async { _listDialogShown = true; - final String apiUrldata = '$apiUrl/api/plans/get_plan_approval_status?plan_id=$id'; + final String apiUrldata = + '$apiUrl/api/plans/get_plan_approval_status?plan_id=$id'; final String? token = await getToken(); String label = ""; List> approverData = []; @@ -313,7 +314,9 @@ class _ListAllPlansState extends State { if (response.statusCode == 200) { final data = json.decode(response.body); label = data['data']['model_heading'] ?? ""; - approverData = List>.from(data['data']['approver_data'] ?? []); + approverData = List>.from( + data['data']['approver_data'] ?? [], + ); } else { print('Failed to load'); label = "Error - Failed to load data"; @@ -326,70 +329,101 @@ class _ListAllPlansState extends State { showDialog( context: context, - builder: (context) => AlertDialog( - title: Text( - label, - style: GoogleFonts.poppins( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - overflow: TextOverflow.ellipsis, - ), - content: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (approverData.isNotEmpty) - SizedBox( - height: 250, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - columns: [ - // DataColumn(label: Text('S.No', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Approver ID', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Status', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), - ], - rows: approverData.asMap().entries.map((entry) { - final index = entry.key + 1; - final item = entry.value; - - final approverIdKey = item.keys.firstWhere((k) => k.endsWith('_id'), orElse: () => ''); - final statusKey = item.keys.firstWhere((k) => k.endsWith('_status'), orElse: () => ''); - - final approverId = item[approverIdKey]?.toString() ?? '-'; - final statusText = item[statusKey]?.toString() ?? 'Unknown'; - - return DataRow( - cells: [ - // DataCell(Text('$index')), - // DataCell(SizedBox(width: 120, child: Text(approverId, overflow: TextOverflow.ellipsis))), - DataCell(SizedBox(child: Text(statusText, overflow: TextOverflow.ellipsis))), + builder: + (context) => AlertDialog( + title: Text( + label, + style: GoogleFonts.poppins( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + overflow: TextOverflow.ellipsis, + ), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (approverData.isNotEmpty) + SizedBox( + height: 250, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + columns: [ + // DataColumn(label: Text('S.No', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Approver ID', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), + DataColumn( + label: Text( + 'Status', + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ), ], - ); - }).toList(), + rows: + approverData.asMap().entries.map((entry) { + final index = entry.key + 1; + final item = entry.value; + + final approverIdKey = item.keys.firstWhere( + (k) => k.endsWith('_id'), + orElse: () => '', + ); + final statusKey = item.keys.firstWhere( + (k) => k.endsWith('_status'), + orElse: () => '', + ); + + final approverId = + item[approverIdKey]?.toString() ?? '-'; + final statusText = + item[statusKey]?.toString() ?? 'Unknown'; + + return DataRow( + cells: [ + // DataCell(Text('$index')), + // DataCell(SizedBox(width: 120, child: Text(approverId, overflow: TextOverflow.ellipsis))), + DataCell( + SizedBox( + child: Text( + statusText, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ) + else + Text( + "-- no data. --", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w300, ), ), - ), - ) - else - Text("-- no data. --", style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w300)), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + _listDialogShown = false; + }, + child: Text("Close"), + ), ], ), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _listDialogShown = false; - }, - child: Text("Close"), - ), - ], - ), ); } @@ -934,36 +968,37 @@ class _ListAllPlansState extends State { ), ), ), - DataCell(GestureDetector( - onTap: () => _showDetails(plan.planId), - child: - Container( - width: - double - .infinity, // Set your desired fixed size (equal width and height) - height: 25, - alignment: Alignment.center, - decoration: BoxDecoration( - color: getStatusColor( - plan.statusValue, - ), - borderRadius: BorderRadius.circular( - 10, - ), - ), - child: Text( - plan.statusValue, - textAlign: TextAlign.center, - style: TextStyle( - color: getStatusTextColor( + DataCell( + GestureDetector( + onTap: () => _showDetails(plan.planId), + child: Container( + width: + double + .infinity, // Set your desired fixed size (equal width and height) + height: 25, + alignment: Alignment.center, + decoration: BoxDecoration( + color: getStatusColor( plan.statusValue, ), - fontSize: 12, - fontFamily: "Inter", - fontWeight: FontWeight.w400, + borderRadius: BorderRadius.circular( + 10, + ), + ), + child: Text( + plan.statusValue, + textAlign: TextAlign.center, + style: TextStyle( + color: getStatusTextColor( + plan.statusValue, + ), + fontSize: 12, + fontFamily: "Inter", + fontWeight: FontWeight.w400, + ), ), ), - ),), + ), ), DataCell( Row( @@ -1156,33 +1191,34 @@ class _ListAllPlansState extends State { Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [GestureDetector( - onTap: () => _showDetails(plan.planId), - child: - Container( - padding: EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: getStatusColor( - plan.statusValue, + children: [ + GestureDetector( + onTap: + () => _showDetails(plan.planId), + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, ), - borderRadius: BorderRadius.circular( - 8, - ), - ), - child: Text( - plan.statusValue, - style: TextStyle( - color: getStatusTextColor( + decoration: BoxDecoration( + color: getStatusColor( plan.statusValue, ), - fontSize: 10, - fontWeight: FontWeight.w600, + borderRadius: + BorderRadius.circular(8), + ), + child: Text( + plan.statusValue, + style: TextStyle( + color: getStatusTextColor( + plan.statusValue, + ), + fontSize: 10, + fontWeight: FontWeight.w600, + ), ), ), - ),), + ), ], ), Column( @@ -1204,139 +1240,137 @@ class _ListAllPlansState extends State { ), itemBuilder: (context) => [ - CustomPopupMenuEntry( - child: Container( - padding: - EdgeInsets.symmetric( - horizontal: 8, - vertical: 8, - ), - child: Row( - mainAxisSize: - MainAxisSize.min, - mainAxisAlignment: - MainAxisAlignment - .center, - children: [ - IconButton( - icon: Icon( - Icons - .remove_red_eye, - color: Color( - 0xFF475569, + CustomPopupMenuEntry( + child: Container( + padding: + EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, ), - size: 18, - ), - tooltip: - 'View The Trip Details', - onPressed: () { - Navigator.pop( - context, - ); // Close popup manually - ApiService.viewPlan( - context, - plan.planId, - isViewMode: - true, - ); - }, - ), - if (plan.statusValue == - "Pending Approval" || - plan.statusValue == - "Partially Approved") - IconButton( - icon: Image.asset( - 'assets/images/IconsImg/edit.png', - width: 20, - height: 15, - ), - tooltip: - 'Edit The Trip Details', - onPressed: () { - Navigator.pop( - context, - ); - ApiService.viewPlan( - context, - plan.planId, - isViewMode: - false, - ); - }, - ), - IconButton( - icon: Icon( - Icons - .cancel_rounded, - size: 18, - ), - tooltip: - 'Cancellation The Trip Details', - onPressed: () { - Navigator.pop( - context, - ); - deletePlan( - plan.planId, - ); - }, - ), - IconButton( - icon: Icon( - Icons.download, - color: Color( - 0xFF114D8B, - ), - size: 18, - ), - tooltip: - 'Download The PDF', - onPressed: () { - Navigator.pop( - context, - ); - apiService - .getPdfDownload( - plan.planId, - ); - }, - ), - IconButton( - icon: const Icon( - Icons.comment, - color: Color( - 0xFF475569, - ), - size: 11, - ), - tooltip: - 'Trip Comments', - onPressed: () { - showDialog( - context: - context, - builder: - ( - context, - ) => CommentModalList( - // planId: plan.planId, - planId: - plan.planId - .toString(), - layoutColorForUser: - layoutColor!, - role: - "Admin", + child: Row( + mainAxisSize: + MainAxisSize.min, + mainAxisAlignment: + MainAxisAlignment + .center, + children: [ + IconButton( + icon: Icon( + Icons + .remove_red_eye, + color: Color( + 0xFF475569, + ), + size: 18, ), - ); - }, + tooltip: + 'View The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); // Close popup manually + ApiService.viewPlan( + context, + plan.planId, + isViewMode: true, + ); + }, + ), + if (plan.statusValue == + "Pending Approval" || + plan.statusValue == + "Partially Approved") + IconButton( + icon: Image.asset( + 'assets/images/IconsImg/edit.png', + width: 20, + height: 15, + ), + tooltip: + 'Edit The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); + ApiService.viewPlan( + context, + plan.planId, + isViewMode: + false, + ); + }, + ), + IconButton( + icon: Icon( + Icons + .cancel_rounded, + size: 18, + ), + tooltip: + 'Cancellation The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); + deletePlan( + plan.planId, + ); + }, + ), + IconButton( + icon: Icon( + Icons.download, + color: Color( + 0xFF114D8B, + ), + size: 18, + ), + tooltip: + 'Download The PDF', + onPressed: () { + Navigator.pop( + context, + ); + apiService + .getPdfDownload( + plan.planId, + ); + }, + ), + IconButton( + icon: const Icon( + Icons.comment, + color: Color( + 0xFF475569, + ), + size: 11, + ), + tooltip: + 'Trip Comments', + onPressed: () { + showDialog( + context: context, + builder: + ( + context, + ) => CommentModalList( + // planId: plan.planId, + planId: + plan.planId + .toString(), + layoutColorForUser: + layoutColor!, + role: + "Admin", + ), + ); + }, + ), + ], ), - ], + ), ), - ), - ), - ], + ], ), ], ), diff --git a/lib/Screens/plans/list_plans.dart b/lib/Screens/plans/list_plans.dart index 5d5a02a..10e0735 100644 --- a/lib/Screens/plans/list_plans.dart +++ b/lib/Screens/plans/list_plans.dart @@ -425,7 +425,8 @@ class _ListPlansState extends State { Future _showDetails(id) async { _listDialogShown = true; - final String apiUrldata = '$apiUrl/api/plans/get_plan_approval_status?plan_id=$id'; + final String apiUrldata = + '$apiUrl/api/plans/get_plan_approval_status?plan_id=$id'; final String? token = await getToken(); String label = ""; List> approverData = []; @@ -446,7 +447,9 @@ class _ListPlansState extends State { if (response.statusCode == 200) { final data = json.decode(response.body); label = data['data']['model_heading'] ?? ""; - approverData = List>.from(data['data']['approver_data'] ?? []); + approverData = List>.from( + data['data']['approver_data'] ?? [], + ); } else { print('Failed to load'); label = "Error - Failed to load data"; @@ -459,70 +462,101 @@ class _ListPlansState extends State { showDialog( context: context, - builder: (context) => AlertDialog( - title: Text( - label, - style: GoogleFonts.poppins( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - overflow: TextOverflow.ellipsis, - ), - content: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (approverData.isNotEmpty) - SizedBox( - height: 250, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: DataTable( - columns: [ - // DataColumn(label: Text('S.No', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), - // DataColumn(label: Text('Approver ID', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), - DataColumn(label: Text('Status', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), - ], - rows: approverData.asMap().entries.map((entry) { - final index = entry.key + 1; - final item = entry.value; - - final approverIdKey = item.keys.firstWhere((k) => k.endsWith('_id'), orElse: () => ''); - final statusKey = item.keys.firstWhere((k) => k.endsWith('_status'), orElse: () => ''); - - final approverId = item[approverIdKey]?.toString() ?? '-'; - final statusText = item[statusKey]?.toString() ?? 'Unknown'; - - return DataRow( - cells: [ - // DataCell(Text('$index')), - // DataCell(SizedBox(width: 120, child: Text(approverId, overflow: TextOverflow.ellipsis))), - DataCell(SizedBox(child: Text(statusText, overflow: TextOverflow.ellipsis))), + builder: + (context) => AlertDialog( + title: Text( + label, + style: GoogleFonts.poppins( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + overflow: TextOverflow.ellipsis, + ), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (approverData.isNotEmpty) + SizedBox( + height: 250, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + columns: [ + // DataColumn(label: Text('S.No', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), + // DataColumn(label: Text('Approver ID', style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w600))), + DataColumn( + label: Text( + 'Status', + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ), ], - ); - }).toList(), + rows: + approverData.asMap().entries.map((entry) { + final index = entry.key + 1; + final item = entry.value; + + final approverIdKey = item.keys.firstWhere( + (k) => k.endsWith('_id'), + orElse: () => '', + ); + final statusKey = item.keys.firstWhere( + (k) => k.endsWith('_status'), + orElse: () => '', + ); + + final approverId = + item[approverIdKey]?.toString() ?? '-'; + final statusText = + item[statusKey]?.toString() ?? 'Unknown'; + + return DataRow( + cells: [ + // DataCell(Text('$index')), + // DataCell(SizedBox(width: 120, child: Text(approverId, overflow: TextOverflow.ellipsis))), + DataCell( + SizedBox( + child: Text( + statusText, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ); + }).toList(), + ), + ), + ), + ) + else + Text( + "-- no data. --", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w300, ), ), - ), - ) - else - Text("-- no data. --", style: GoogleFonts.poppins(fontSize: 14, fontWeight: FontWeight.w300)), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + _listDialogShown = false; + }, + child: Text("Close"), + ), ], ), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _listDialogShown = false; - }, - child: Text("Close"), - ), - ], - ), ); } @@ -1074,52 +1108,52 @@ class _ListPlansState extends State { DataCell( GestureDetector( onTap: () => _showDetails(plan.planId), - child: - Container( - width: - double - .infinity, // Set your desired fixed size (equal width and height) - height: 25, - alignment: Alignment.center, - decoration: BoxDecoration( - color: getStatusColor( - plan.statusValue, - ), - // color: plan.statusValue == - // "Partially Approved" - // ? Colors.yellow.shade100 - // : plan.statusValue == "Approved" - // ? Colors.green.shade100 - // : plan.statusValue == "Completed" - // ? Colors.green.shade500 - // : plan.statusValue == "Rejected" - // ? Colors.red.shade100 - // : Colors.grey.shade100, - borderRadius: BorderRadius.circular( - 10, - ), - ), - child: Text( - plan.statusValue, - textAlign: TextAlign.center, - style: TextStyle( - color: getStatusTextColor( + child: Container( + width: + double + .infinity, // Set your desired fixed size (equal width and height) + height: 25, + alignment: Alignment.center, + decoration: BoxDecoration( + color: getStatusColor( plan.statusValue, ), - // color: (plan.statusValue == - // "Partially Approved" || - // plan.statusValue == "Approved" || - // plan.statusValue == "Rejected") - // ? Colors.black - // : plan.statusValue == "Completed" - // ? Colors.white - // : Colors.grey, - fontSize: 12, - fontFamily: "Inter", - fontWeight: FontWeight.w400, + // color: plan.statusValue == + // "Partially Approved" + // ? Colors.yellow.shade100 + // : plan.statusValue == "Approved" + // ? Colors.green.shade100 + // : plan.statusValue == "Completed" + // ? Colors.green.shade500 + // : plan.statusValue == "Rejected" + // ? Colors.red.shade100 + // : Colors.grey.shade100, + borderRadius: BorderRadius.circular( + 10, + ), + ), + child: Text( + plan.statusValue, + textAlign: TextAlign.center, + style: TextStyle( + color: getStatusTextColor( + plan.statusValue, + ), + // color: (plan.statusValue == + // "Partially Approved" || + // plan.statusValue == "Approved" || + // plan.statusValue == "Rejected") + // ? Colors.black + // : plan.statusValue == "Completed" + // ? Colors.white + // : Colors.grey, + fontSize: 12, + fontFamily: "Inter", + fontWeight: FontWeight.w400, + ), ), ), - ),), + ), ), DataCell( Row( @@ -1355,29 +1389,34 @@ class _ListPlansState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [GestureDetector( - onTap: () => _showDetails(plan.planId), - child: - Container( - padding: EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: getStatusColor(plan.statusValue), - borderRadius: BorderRadius.circular(8), - ), - child: Text( - plan.statusValue, - style: TextStyle( - color: getStatusTextColor( + children: [ + GestureDetector( + onTap: () => _showDetails(plan.planId), + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: getStatusColor( plan.statusValue, ), - fontSize: 10, - fontWeight: FontWeight.w600, + borderRadius: BorderRadius.circular( + 8, + ), + ), + child: Text( + plan.statusValue, + style: TextStyle( + color: getStatusTextColor( + plan.statusValue, + ), + fontSize: 10, + fontWeight: FontWeight.w600, + ), ), ), - ),), + ), // PlanPopupMenu( // plan: plan, // deletePlan: deletePlan, @@ -1663,6 +1702,7 @@ class _ListPlansState extends State { // ) // : buildMobileCardView(paginatedPlans), ), + PaginationControls( currentPage: currentPage, itemsPerPage: itemsPerPage, diff --git a/lib/utils/pagination.dart b/lib/utils/pagination.dart index 56644fd..6290fee 100644 --- a/lib/utils/pagination.dart +++ b/lib/utils/pagination.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; class PaginationControls extends StatelessWidget { final int currentPage; @@ -20,33 +21,99 @@ class PaginationControls extends StatelessWidget { @override Widget build(BuildContext context) { - int totalPages = (totalItems / itemsPerPage).ceil(); + // int totalPages = (totalItems / itemsPerPage).ceil(); + final int totalPages = (totalItems / itemsPerPage).ceil(); + + // return Row( + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // Padding( + // padding: const EdgeInsets.symmetric(vertical: 12), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // DropdownButton( + // value: itemsPerPage, + // items: + // [5, 10, 15, 20, 50].map((int value) { + // return DropdownMenuItem( + // value: value, + // child: Text( + // ' $value ', + // style: GoogleFonts.poppins(fontSize: 15), + // ), + // ); + // }).toList(), + // onChanged: (newValue) { + // if (newValue != null) { + // onItemsPerPageChanged(newValue); + // onPageChanged(1); // reset to first page + // } + // }, + // ), + // IconButton( + // onPressed: + // currentPage > 1 + // ? () => onPageChanged(currentPage - 1) + // : null, + // icon: Icon(Icons.chevron_left), + // ), + // for (int i = 1; i <= totalPages - 1; i++) + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 4), + // child: ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: + // currentPage == i - 1 ? activeColor : Colors.grey[300], + // foregroundColor: + // currentPage == i - 1 ? Colors.white : Colors.black, + // minimumSize: Size(36, 36), + // padding: EdgeInsets.zero, + // ), + // onPressed: () => onPageChanged(i - 1), + // child: Text(i.toString()), + // ), + // ), + // IconButton( + // onPressed: + // currentPage < totalPages - 1 + // ? () => onPageChanged(currentPage + 1) + // : null, + // icon: Icon(Icons.chevron_right), + // ), + // ], + // ), + // ), + // ], + // ); return Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Text( - 'Items per page:', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w400, - color: Colors.black87, - fontFamily: "Inter", - ), - ), - SizedBox(width: 8), + // Text( + // 'Items per page:', + // style: TextStyle( + // fontSize: 12, + // fontWeight: FontWeight.w400, + // color: Colors.black87, + // fontFamily: "Inter", + // ), + // ), + // SizedBox(width: 8), DropdownButton( value: itemsPerPage, - items: [10, 20, 50, 100] - .map((value) => DropdownMenuItem( - value: value, - child: Text('$value', - style: TextStyle( - fontSize: 12, - fontFamily: "Inter", - )), - )) - .toList(), + items: + [10, 20, 50, 100] + .map( + (value) => DropdownMenuItem( + value: value, + child: Text( + '$value', + style: TextStyle(fontSize: 12, fontFamily: "Inter"), + ), + ), + ) + .toList(), onChanged: (value) { if (value != null) { onItemsPerPageChanged(value); @@ -66,51 +133,113 @@ class PaginationControls extends StatelessWidget { onPressed: currentPage > 0 ? () => onPageChanged(currentPage - 1) : null, ), + + // SingleChildScrollView( + // scrollDirection: Axis.horizontal, + // child: Row( + // children: List.generate(totalPages, (index) { + // print("totalPagesList - $totalPages"); + // // Only show 2 pages: currentPage and currentPage + 1 + // if (index == currentPage || index == currentPage + 1) { + // return Padding( + // padding: const EdgeInsets.symmetric(horizontal: 4), + // child: ElevatedButton( + // onPressed: () => onPageChanged(index), + // style: ElevatedButton.styleFrom( + // backgroundColor: + // currentPage == index + // ? activeColor + // : Colors.grey[300]!, + // minimumSize: Size(30, 30), + // padding: EdgeInsets.zero, + // ), + // child: Text( + // '${index + 1}', + // style: TextStyle( + // fontSize: 12, + // fontFamily: "Inter", + // color: + // currentPage == index ? Colors.white : Colors.black, + // ), + // ), + // ), + // ); + // } else { + // return SizedBox.shrink(); // Don't show other pages + // } + // }), + // ), + // ), SingleChildScrollView( scrollDirection: Axis.horizontal, - child: Row( - children: List.generate( - totalPages, - (index) { - // Only show 2 pages: currentPage and currentPage+1 - if (index == currentPage || index == currentPage + 1) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: ElevatedButton( - onPressed: () => onPageChanged(index), - style: ElevatedButton.styleFrom( - backgroundColor: currentPage == index - ? activeColor - : Colors.grey[300]!, - minimumSize: Size(30, 30), - padding: EdgeInsets.zero, - ), - child: Text( - '${index + 1}', - style: TextStyle( - fontSize: 12, - fontFamily: "Inter", - color: currentPage == index - ? Colors.white - : Colors.black, - ), - ), - ), - ); - } else { - return SizedBox.shrink(); // Don't show other pages - } - }, - ), - ), + child: Row(children: _buildPageButtons()), ), + IconButton( icon: Icon(Icons.arrow_forward_ios, size: 10), - onPressed: (currentPage + 1) * itemsPerPage < totalItems - ? () => onPageChanged(currentPage + 1) - : null, + onPressed: + (currentPage + 1) * itemsPerPage < totalItems + ? () => onPageChanged(currentPage + 1) + : null, ), ], ); } + + List _buildPageButtons() { + final int totalPages = (totalItems / itemsPerPage).ceil(); + List buttons = []; + + // Always show first page + buttons.add(_buildPageButton(0)); + + // Add left ellipsis if needed + if (currentPage > 2) { + buttons.add(_buildEllipsis()); + } + + // Add previous, current, next page if in range + for (int i = currentPage - 1; i <= currentPage + 1; i++) { + if (i > 0 && i < totalPages - 1) { + buttons.add(_buildPageButton(i)); + } + } + + // Add right ellipsis if needed + if (currentPage < totalPages - 3) { + buttons.add(_buildEllipsis()); + } + + // Always show last page + if (totalPages > 1) { + buttons.add(_buildPageButton(totalPages - 1)); + } + + return buttons; + } + + Widget _buildPageButton(int pageIndex) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: ElevatedButton( + onPressed: () => onPageChanged(pageIndex), + style: ElevatedButton.styleFrom( + backgroundColor: + currentPage == pageIndex ? activeColor : Colors.grey[300], + foregroundColor: + currentPage == pageIndex ? Colors.white : Colors.black, + minimumSize: Size(36, 36), + padding: EdgeInsets.zero, + ), + child: Text('${pageIndex + 1}'), + ), + ); + } + + Widget _buildEllipsis() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: Text('...', style: TextStyle(fontSize: 16)), + ); + } }