added Filter and Sort dialog design in tenders page

This commit is contained in:
llsajjad
2025-09-22 17:18:41 +03:30
parent da3efc730a
commit 987f499833
6 changed files with 357 additions and 8 deletions
+34 -2
View File
@@ -12,6 +12,8 @@ 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/shared/page_selection_dialog.dart';
import 'package:tm_app/views/tenders/strings/tenders_strings.dart'; import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart'; import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart';
import 'package:tm_app/views/tenders/widgets/tenders_filter_dialog.dart';
import 'package:tm_app/views/tenders/widgets/tenders_sort_dialog.dart';
import '../../../core/constants/common_strings.dart'; import '../../../core/constants/common_strings.dart';
import '../../../core/utils/app_toast.dart'; import '../../../core/utils/app_toast.dart';
@@ -190,7 +192,22 @@ class _ActionButtons extends StatelessWidget {
BaseButton( BaseButton(
width: 178.0.w(), width: 178.0.w(),
isEnabled: true, isEnabled: true,
onPressed: () {}, onPressed: () {
showDialog(
context: context,
builder:
(_) => Dialog(
backgroundColor: AppColors.backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: const SizedBox(
width: 560,
child: TendersFilterDialog(),
),
),
);
},
text: 'Filter', text: 'Filter',
icon: AssetsManager.filter, icon: AssetsManager.filter,
iconColor: AppColors.textBlue, iconColor: AppColors.textBlue,
@@ -201,7 +218,22 @@ class _ActionButtons extends StatelessWidget {
BaseButton( BaseButton(
width: 178.0.w(), width: 178.0.w(),
isEnabled: true, isEnabled: true,
onPressed: () {}, onPressed: () {
showDialog(
context: context,
builder:
(_) => Dialog(
backgroundColor: AppColors.backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: const SizedBox(
width: 560,
child: TendersSortDialog(),
),
),
);
},
text: 'Sort', text: 'Sort',
icon: AssetsManager.sort, icon: AssetsManager.sort,
iconColor: AppColors.textBlue, iconColor: AppColors.textBlue,
+15 -1
View File
@@ -12,5 +12,19 @@ class TendersStrings {
static const String notifications = 'Notifications'; static const String notifications = 'Notifications';
static const String of = 'Of'; static const String of = 'Of';
static const String page = 'Page'; static const String page = 'Page';
static const String search = 'Search tenders...'; static const String all = 'All';
static const String read = 'Read';
static const String selectDataRange = 'Select date range';
static const String unread = 'Unread';
static const String search = 'Search';
static const String status = 'Status';
static const String confirm = 'Confirm';
static const String filter = 'Filter';
static const String endDate = 'end Date';
static const String startDate = 'Start Date';
static const String sort = 'Sort';
static const String mostOfTheTime = 'Most of the time';
static const String minimumTime = 'Minimum time';
static const String lessBudget = 'Less budget';
static const String moreBudget = 'More budget';
} }
@@ -0,0 +1,202 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/core/constants/assets.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/view_models/your_tenders_view_model.dart';
import 'package:tm_app/views/shared/base_button.dart';
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
class TendersFilterDialog extends StatelessWidget {
const TendersFilterDialog({super.key});
Widget _dateRangePill(BuildContext context) {
final viewModel = context.watch<YourTendersViewModel>();
final start = viewModel.selectedDateRange?.start;
final end = viewModel.selectedDateRange?.end;
Future<void> pick() async {
final picked = await showDateRangePicker(
context: context,
firstDate: DateTime(2020),
lastDate: DateTime(2035),
initialDateRange: viewModel.selectedDateRange,
);
if (picked != null) {
viewModel.setDateRange(picked);
}
}
return SizedBox(
width: 560,
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: pick,
child: Container(
height: 56.0.h(),
padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: AppColors.grey0,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.grey40),
),
child: Center(
child: Stack(
alignment: Alignment.center,
children: [
Align(
alignment: Alignment.center,
child: Container(
width: 1,
margin: const EdgeInsets.symmetric(vertical: 8),
color: AppColors.grey40,
),
),
Align(
alignment: Alignment.center,
child: SizedBox(
width: 26.0.w(),
height: 26.0.h(),
child: SvgPicture.asset(AssetsManager.trailingIcon),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
start == null
? TendersStrings.startDate
: viewModel.startDateFormatted,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey70,
),
),
Text(
end == null
? TendersStrings.endDate
: viewModel.endDateFormatted,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey70,
),
),
],
),
],
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Consumer<YourTendersViewModel>(
builder: (context, vm, child) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
TendersStrings.filter,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w700,
color: AppColors.grey70,
),
),
const Spacer(),
InkWell(
onTap: () => Navigator.pop(context),
child: SvgPicture.asset(
AssetsManager.closeCircle,
colorFilter: ColorFilter.mode(
AppColors.grey80,
BlendMode.srcIn,
),
width: 24.0.w(),
height: 24.0.h(),
),
),
],
),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 20.0.h()),
Text(
TendersStrings.selectDataRange,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey80,
),
),
SizedBox(height: 10.0.h()),
_dateRangePill(context),
SizedBox(height: 16.0.h()),
Text(
TendersStrings.status,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
...[
TendersStrings.all,
TendersStrings.read,
TendersStrings.unread,
].map((status) {
return RadioListTile(
value: status,
groupValue: vm.selectedStatus,
activeColor: AppColors.mainBlue,
onChanged: (value) => vm.setStatus(value!),
title: Text(
status,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey70,
),
),
);
}),
SizedBox(height: 16.0.h()),
Row(
children: [
const Spacer(),
SizedBox(
width: 156.0.w(),
child: BaseButton(
isEnabled: true,
onPressed: () {
context.pop();
vm.callWithFilter();
},
text: TendersStrings.confirm,
textColor: AppColors.textBlue,
backgroundColor: AppColors.primary2,
),
),
],
),
],
),
),
);
},
);
}
}
@@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/core/constants/assets.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/view_models/your_tenders_view_model.dart';
import 'package:tm_app/views/shared/base_button.dart';
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
class TendersSortDialog extends StatelessWidget {
const TendersSortDialog({super.key});
@override
Widget build(BuildContext context) {
return Consumer<YourTendersViewModel>(
builder: (context, vm, child) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
TendersStrings.sort,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w700,
color: AppColors.grey70,
),
),
const Spacer(),
InkWell(
onTap: () => Navigator.pop(context),
child: SvgPicture.asset(
AssetsManager.closeCircle,
colorFilter: ColorFilter.mode(
AppColors.grey80,
BlendMode.srcIn,
),
width: 24.0.w(),
height: 24.0.h(),
),
),
],
),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 20.0.h()),
...[
TendersStrings.minimumTime,
TendersStrings.mostOfTheTime,
TendersStrings.lessBudget,
TendersStrings.moreBudget,
].map((status) {
return RadioListTile(
value: status,
groupValue: vm.selectedStatus,
activeColor: AppColors.mainBlue,
onChanged: (value) => vm.setStatus(value!),
title: Text(
status,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey70,
),
),
);
}),
SizedBox(height: 16.0.h()),
Row(
children: [
const Spacer(),
SizedBox(
width: 156.0.w(),
child: BaseButton(
isEnabled: true,
onPressed: () {
context.pop();
vm.callWithFilter();
},
text: TendersStrings.confirm,
textColor: AppColors.textBlue,
backgroundColor: AppColors.primary2,
),
),
],
),
],
),
),
);
},
);
}
}
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart'; import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart';
import 'tenders_filter_dialog.dart'; import 'your_tenders_filter_dialog.dart';
enum PlatformType { mobile, tabletDesktop } enum PlatformType { mobile, tabletDesktop }
@@ -19,7 +19,7 @@ class FilterButton extends StatelessWidget {
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)), borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
), ),
builder: (_) => const TendersFilterDialog(), builder: (_) => const YourTendersFilterDialog(),
); );
} else { } else {
showDialog( showDialog(
@@ -30,7 +30,7 @@ class FilterButton extends StatelessWidget {
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
child: const TendersFilterDialog(), child: const YourTendersFilterDialog(),
), ),
); );
} }
@@ -9,8 +9,8 @@ import 'package:tm_app/view_models/your_tenders_view_model.dart';
import 'package:tm_app/views/shared/base_button.dart'; import 'package:tm_app/views/shared/base_button.dart';
import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart'; import 'package:tm_app/views/your_tenders/strings/your_tenders_strings.dart';
class TendersFilterDialog extends StatelessWidget { class YourTendersFilterDialog extends StatelessWidget {
const TendersFilterDialog({super.key}); const YourTendersFilterDialog({super.key});
Widget _dateRangePill(BuildContext context) { Widget _dateRangePill(BuildContext context) {
final viewModel = context.watch<YourTendersViewModel>(); final viewModel = context.watch<YourTendersViewModel>();