Fixed pagination tenders for desktop and

added new config for notification
This commit is contained in:
llsajjad
2025-09-21 14:03:32 +03:30
parent 8a289f2d05
commit 6e6f248702
15 changed files with 422 additions and 219 deletions
+207 -105
View File
@@ -7,6 +7,8 @@ import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/view_models/tenders_view_model.dart';
import 'package:tm_app/views/shared/base_button.dart';
import 'package:tm_app/views/shared/desktop_navigation_widget.dart';
import 'package:tm_app/views/shared/page_selection_dialog.dart';
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
import '../../../core/constants/common_strings.dart';
@@ -21,6 +23,7 @@ class DesktopTendersPage extends StatefulWidget {
class _DesktopTendersPageState extends State<DesktopTendersPage> {
late final TendersViewModel viewModel;
@override
void initState() {
super.initState();
@@ -49,121 +52,49 @@ class _DesktopTendersPageState extends State<DesktopTendersPage> {
backgroundColor: AppColors.backgroundColor,
body: Column(
children: [
const DesktopNavigationWidget(
currentIndex: 1, // Tenders index
),
const DesktopNavigationWidget(currentIndex: 1),
SizedBox(height: 48.0.h()),
//search box
SizedBox(
height: 48.0.h(),
width: 680,
child: TextField(
style: TextStyle(fontSize: 16.0.sp(), color: AppColors.grey0),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(
fontSize: 16.0.sp(),
color: AppColors.grey60,
),
prefixIcon: Padding(
padding: EdgeInsets.all(12.0.w()),
child: SvgPicture.asset(
AssetsManager.normalSearch,
width: 24.0.w(),
height: 24.0.h(),
),
),
filled: true,
fillColor: AppColors.grey0,
contentPadding: EdgeInsets.symmetric(
horizontal: 12.0.w(),
vertical: 12.0.h(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
borderSide: const BorderSide(
color: AppColors.mainBlue,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
borderSide: BorderSide(color: AppColors.grey40, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
borderSide: const BorderSide(
color: AppColors.grey,
width: 1.5,
),
),
),
),
),
Container(
margin: EdgeInsets.only(top: 25.0.h()),
height: 40.0.h(),
width: 680,
child: Row(
children: [
BaseButton(
width: 178.0.w(),
isEnabled: true,
onPressed: () {},
text: 'Filter',
icon: AssetsManager.filter,
iconColor: AppColors.textBlue,
backgroundColor: AppColors.primary2,
textColor: AppColors.textBlue,
),
SizedBox(width: 10.0.w()),
BaseButton(
width: 178.0.w(),
isEnabled: true,
onPressed: () {},
text: 'Sort',
icon: AssetsManager.sort,
iconColor: AppColors.textBlue,
backgroundColor: AppColors.primary2,
textColor: AppColors.textBlue,
),
],
),
),
const _SearchBox(),
const _ActionButtons(),
Expanded(
child: Consumer<TendersViewModel>(
builder: (context, viewModel, child) {
if (viewModel.isLoading) {
return const Expanded(
child: Center(
child: CircularProgressIndicator(
color: AppColors.jellyBean,
),
),
builder: (context, vm, child) {
if (vm.isLoading) {
return const Center(
child: CircularProgressIndicator(color: AppColors.jellyBean),
);
}
if (viewModel.errorMessage != null) {
return Center(child: Text(viewModel.errorMessage!));
if (vm.errorMessage != null) {
return Center(child: Text(vm.errorMessage!));
}
if ((viewModel.tendersResponse?.data?.tenders == null ||
viewModel.tendersResponse!.data!.tenders!.isEmpty) &&
viewModel.isLoading == false) {
final tenders = vm.tendersResponse?.data?.tenders ?? [];
if (tenders.isEmpty) {
return const Center(child: Text(CommonStrings.noData));
}
return SingleChildScrollView(
child: SizedBox(
width: 740,
height: 800,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 4.0.h()),
child: MainTendersSlider(
tenders: viewModel.tendersResponse?.data?.tenders ?? [],
isDesktop: true,
return Column(
children: [
Expanded(
child: SingleChildScrollView(
child: SizedBox(
width: 740,
height: 800,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 4.0.h()),
child: MainTendersSlider(
tenders: tenders,
isDesktop: true,
),
),
),
),
),
),
_DesktopPagination(
totalPages: vm.totalPages,
currentPage: vm.currentPage,
onPageSelected: vm.jumpToPage,
),
],
);
},
),
@@ -173,3 +104,174 @@ class _DesktopTendersPageState extends State<DesktopTendersPage> {
);
}
}
class _SearchBox extends StatelessWidget {
const _SearchBox();
@override
Widget build(BuildContext context) {
return SizedBox(
height: 48.0.h(),
width: 680,
child: TextField(
style: TextStyle(fontSize: 16.0.sp(), color: AppColors.grey0),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(fontSize: 16.0.sp(), color: AppColors.grey60),
prefixIcon: Padding(
padding: EdgeInsets.all(12.0.w()),
child: SvgPicture.asset(
AssetsManager.normalSearch,
width: 24.0.w(),
height: 24.0.h(),
),
),
filled: true,
fillColor: AppColors.grey0,
contentPadding: EdgeInsets.symmetric(
horizontal: 12.0.w(),
vertical: 12.0.h(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
borderSide: const BorderSide(color: AppColors.mainBlue, width: 1),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
borderSide: BorderSide(color: AppColors.grey40, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0.w()),
borderSide: const BorderSide(color: AppColors.grey, width: 1.5),
),
),
),
);
}
}
class _ActionButtons extends StatelessWidget {
const _ActionButtons();
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: 25.0.h()),
height: 40.0.h(),
width: 680,
child: Row(
children: [
BaseButton(
width: 178.0.w(),
isEnabled: true,
onPressed: () {},
text: 'Filter',
icon: AssetsManager.filter,
iconColor: AppColors.textBlue,
backgroundColor: AppColors.primary2,
textColor: AppColors.textBlue,
),
SizedBox(width: 10.0.w()),
BaseButton(
width: 178.0.w(),
isEnabled: true,
onPressed: () {},
text: 'Sort',
icon: AssetsManager.sort,
iconColor: AppColors.textBlue,
backgroundColor: AppColors.primary2,
textColor: AppColors.textBlue,
),
],
),
);
}
}
class _DesktopPagination extends StatelessWidget {
final int totalPages;
final int currentPage;
final ValueChanged<int> onPageSelected;
const _DesktopPagination({
required this.totalPages,
required this.currentPage,
required this.onPageSelected,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: 680,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 12.0.h()),
child: Row(
children: [
const Spacer(),
Text(
TendersStrings.page,
style: TextStyle(
fontSize: 13.0.sp(),
fontWeight: FontWeight.w300,
color: AppColors.grey60,
),
),
SizedBox(width: 10.0.w()),
InkWell(
onTap: () async {
final selectedPage = await showDialog<int>(
context: context,
builder: (context) =>
PageSelectionDialog(totalPages: totalPages),
);
if (selectedPage != null) {
onPageSelected(selectedPage);
}
},
child: Container(
decoration: BoxDecoration(
border: Border.all(color: AppColors.grey30, width: 1),
borderRadius: BorderRadius.circular(4),
),
child: Row(
children: [
SizedBox(width: 5.0.w()),
Text(
'$currentPage',
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.grey70,
),
),
SizedBox(width: 5.0.w()),
SvgPicture.asset(AssetsManager.arrowDownSmall),
SizedBox(width: 5.0.w()),
],
),
),
),
SizedBox(width: 5.0.w()),
Text(
TendersStrings.of,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey60,
),
),
SizedBox(width: 5.0.w()),
Text(
'$totalPages',
style: TextStyle(
fontSize: 13.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey60,
),
),
],
),
),
);
}
}