diff --git a/lib/views/tenders/pages/d_tenders_page.dart b/lib/views/tenders/pages/d_tenders_page.dart index 49d2b22..c56b886 100644 --- a/lib/views/tenders/pages/d_tenders_page.dart +++ b/lib/views/tenders/pages/d_tenders_page.dart @@ -185,6 +185,7 @@ class _ActionButtons extends StatelessWidget { @override Widget build(BuildContext context) { + final viewModel = context.read(); return Container( margin: EdgeInsets.only(top: 25.0.h()), height: 40.0.h(), @@ -203,9 +204,16 @@ class _ActionButtons extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), - child: const SizedBox( + child: SizedBox( width: 560, - child: TendersFilterDialog(), + child: TendersFilterDialog( + viewModel: viewModel, + onFilterChanged: (dateRange, status) { + viewModel.setDateRange(dateRange); + viewModel.setStatus(status!); + viewModel.callWithSortAndStatus(); + }, + ), ), ), ); @@ -229,9 +237,15 @@ class _ActionButtons extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), - child: const SizedBox( + child: SizedBox( width: 560, - child: TendersSortDialog(), + child: TendersSortDialog( + viewModel: viewModel, + onConfirm: (sort) { + viewModel.setSort(sort); + viewModel.callWithSortAndStatus(); + }, + ), ), ), ); diff --git a/lib/views/tenders/widgets/tenders_filter_dialog.dart b/lib/views/tenders/widgets/tenders_filter_dialog.dart index 144b5ac..b45d0e9 100644 --- a/lib/views/tenders/widgets/tenders_filter_dialog.dart +++ b/lib/views/tenders/widgets/tenders_filter_dialog.dart @@ -1,7 +1,7 @@ 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:intl/intl.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'; @@ -10,194 +10,234 @@ import 'package:tm_app/views/tenders/strings/tenders_strings.dart'; import '../../../view_models/tenders_view_model.dart'; -class TendersFilterDialog extends StatelessWidget { - const TendersFilterDialog({super.key}); +class TendersFilterDialog extends StatefulWidget { + final TendersViewModel viewModel; + final Function(DateTimeRange? dateRange, String? status) onFilterChanged; + const TendersFilterDialog({ + required this.viewModel, + required this.onFilterChanged, + super.key, + }); - Widget _dateRangePill(BuildContext context) { - final viewModel = context.watch(); - final start = viewModel.selectedDateRange?.start; - final end = viewModel.selectedDateRange?.end; + @override + State createState() => _TendersFilterDialogState(); +} - Future pick() async { - final picked = await showDateRangePicker( - context: context, - firstDate: DateTime(2020), - lastDate: DateTime(2035), - initialDateRange: viewModel.selectedDateRange, - ); - if (picked != null) { - viewModel.setDateRange(picked); - } - } +class _TendersFilterDialogState extends State { + DateTimeRange? dateRange; + String? status = TendersStrings.all; - 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, - ), - ), - ], - ), - ], - ), - ), - ), - ), + final _fmt = DateFormat('yyyy/MM/dd'); + + String get startDateFormatted => + dateRange?.start != null ? _fmt.format(dateRange!.start) : 'YYYY/MM/DD'; + + String get endDateFormatted => + dateRange?.end != null ? _fmt.format(dateRange!.end) : 'YYYY/MM/DD'; + + String get startDateUnix => + dateRange?.start != null + ? (dateRange!.start.millisecondsSinceEpoch ~/ 1000).toString() + : ''; + + String get endDateUnix => + dateRange?.end != null + ? (dateRange!.end.millisecondsSinceEpoch ~/ 1000).toString() + : ''; + + @override + void initState() { + super.initState(); + dateRange = widget.viewModel.selectedDateRange; + status = _mapApiValueToDisplayString(widget.viewModel.selectedStatus); + } + + String _mapApiValueToDisplayString(String apiValue) { + final mapping = { + 'All': TendersStrings.all, + 'Read': TendersStrings.read, + 'Unread': TendersStrings.unread, + }; + return mapping[apiValue] ?? TendersStrings.all; + } + + Future pick() async { + final picked = await showDateRangePicker( + context: context, + firstDate: DateTime(2000), + lastDate: DateTime(2050), + initialDateRange: dateRange, ); + if (picked != null) { + dateRange = picked; + setState(() {}); + } } @override Widget build(BuildContext context) { - return Consumer( - builder: (context, vm, child) { - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( 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, + TendersStrings.filter, 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, + fontSize: 20.0.sp(), + fontWeight: FontWeight.w700, 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, - ), + const Spacer(), + InkWell( + onTap: () => Navigator.pop(context), + child: SvgPicture.asset( + AssetsManager.closeCircle, + colorFilter: ColorFilter.mode( + AppColors.grey80, + BlendMode.srcIn, ), - ); - }), - SizedBox(height: 16.0.h()), - Row( - children: [ - const Spacer(), - SizedBox( - width: 156.0.w(), - child: BaseButton( - isEnabled: true, - onPressed: () { - context.pop(); - vm.callWithSortAndStatus(); - }, - text: TendersStrings.confirm, - textColor: AppColors.textBlue, - backgroundColor: AppColors.primary2, - ), - ), - ], + 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()), + 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( + dateRange?.start == null + ? TendersStrings.startDate + : startDateFormatted, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), + Text( + dateRange?.end == null + ? TendersStrings.endDate + : endDateFormatted, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + 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: this.status, + activeColor: AppColors.mainBlue, + onChanged: + (value) => setState(() { + this.status = 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(); + widget.onFilterChanged(dateRange, status); + }, + text: TendersStrings.confirm, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary2, + ), + ), + ], + ), + ], + ), + ), ); } } diff --git a/lib/views/tenders/widgets/tenders_sort_dialog.dart b/lib/views/tenders/widgets/tenders_sort_dialog.dart index c5ffe88..8b9edae 100644 --- a/lib/views/tenders/widgets/tenders_sort_dialog.dart +++ b/lib/views/tenders/widgets/tenders_sort_dialog.dart @@ -1,7 +1,6 @@ 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'; @@ -10,91 +9,108 @@ import 'package:tm_app/views/tenders/strings/tenders_strings.dart'; import '../../../view_models/tenders_view_model.dart'; -class TendersSortDialog extends StatelessWidget { - const TendersSortDialog({super.key}); +class TendersSortDialog extends StatefulWidget { + const TendersSortDialog({ + required this.viewModel, + required this.onConfirm, + super.key, + }); + final TendersViewModel viewModel; + final ValueChanged onConfirm; + + @override + State createState() => _TendersSortDialogState(); +} + +class _TendersSortDialogState extends State { + String sort = ''; + + @override + void initState() { + super.initState(); + sort = widget.viewModel.selectedSort; + } @override Widget build(BuildContext context) { - return Consumer( - builder: (context, vm, child) { - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( 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(), - ), - ), - ], + Text( + TendersStrings.sort, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w700, + color: AppColors.grey70, + ), ), - SizedBox(height: 16.0.h()), - Divider(color: AppColors.grey20), - SizedBox(height: 20.0.h()), - ...[ - TendersStrings.minimumTime, - TendersStrings.mostOfTheTime, - ].map((status) { - return RadioListTile( - value: status, - groupValue: vm.selectedSort, - activeColor: AppColors.mainBlue, - onChanged: (value) => vm.setSort(value!), - title: Text( - status, - style: TextStyle( - fontSize: 16.0.sp(), - fontWeight: FontWeight.w400, - color: AppColors.grey70, - ), + const Spacer(), + InkWell( + onTap: () => Navigator.pop(context), + child: SvgPicture.asset( + AssetsManager.closeCircle, + colorFilter: ColorFilter.mode( + AppColors.grey80, + BlendMode.srcIn, ), - ); - }), - SizedBox(height: 16.0.h()), - Row( - children: [ - const Spacer(), - SizedBox( - width: 156.0.w(), - child: BaseButton( - isEnabled: true, - onPressed: () { - context.pop(); - vm.callWithSortAndStatus(); - }, - text: TendersStrings.confirm, - textColor: AppColors.textBlue, - backgroundColor: AppColors.primary2, - ), - ), - ], + 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].map(( + status, + ) { + return RadioListTile( + value: status, + groupValue: sort, + activeColor: AppColors.mainBlue, + onChanged: + (value) => setState(() { + sort = 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(); + widget.onConfirm(sort); + }, + text: TendersStrings.confirm, + textColor: AppColors.textBlue, + backgroundColor: AppColors.primary2, + ), + ), + ], + ), + ], + ), + ), ); } }