Add clock asset and enhance meeting time dialogs

- Added a new clock icon asset to the AssetsManager.
- Updated MeetingTimeBottomSheet and MeetingTimeDialog to include a close button for better user experience.
- Introduced MeetingTimeSuccessfulRegisteredBottomSheet and MeetingTimeSuccessfulRegisteredDialog for confirming meeting time registration.
- Refactored submission dialogs to improve layout and interaction consistency.
This commit is contained in:
amirrezaghabeli
2025-10-27 13:22:51 +03:30
parent b801d75f99
commit de659ca9cf
11 changed files with 599 additions and 138 deletions
@@ -39,4 +39,7 @@ class TenderDetailsStrings {
'Last day to prepare proposal is ';
static const String meetingTimeSuccessfullySet =
'meeting time successfully set';
static const String requestSuccessfullyRegistered =
'Your request has been successfully registered.';
static const String confirmAndClose = 'Confirm and close';
}
@@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:tm_app/core/utils/size_config.dart';
import '../../../core/routes/app_routes.dart';
import '../../../core/theme/colors.dart';
import '../strings/tender_details_strings.dart';
import 'meeting_time_successful_registered_bottom_sheet.dart';
class MeetingTimeBottomSheet extends StatefulWidget {
const MeetingTimeBottomSheet({required this.onConfirm, super.key});
@@ -41,13 +41,38 @@ class _MeetingTimeBottomSheetState extends State<MeetingTimeBottomSheet> {
),
child: Column(
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
InkWell(
onTap: () {
context.pop();
},
splashColor: Colors.transparent,
child: Container(
width: 24.0.w(),
height: 24.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: AppColors.grey60, width: 2.0),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: AppColors.grey60,
size: 16.0,
),
),
),
],
),
SizedBox(height: 15.0.h()),
ListView.builder(
@@ -75,9 +100,14 @@ class _MeetingTimeBottomSheetState extends State<MeetingTimeBottomSheet> {
SizedBox(height: 8.0.h()),
InkWell(
onTap: () {
widget.onConfirm(type);
// widget.onConfirm(type);
context.pop();
const CompletionOfDocumentsRouteData().push(context);
showModalBottomSheet(
context: context,
builder: (context) {
return const MeetingTimeSuccessfulRegisteredBottomSheet();
},
);
},
child: Container(
width: double.infinity,
@@ -1,12 +1,11 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/view_models/auth_view_model.dart';
import 'package:tm_app/views/detail/strings/tender_details_strings.dart';
import 'meeting_time_successful_registered_dialog.dart';
class MeetingTimeDialog extends StatefulWidget {
const MeetingTimeDialog({required this.onConfirm, super.key});
final ValueChanged<String> onConfirm;
@@ -29,7 +28,6 @@ class _MeetingTimeDialogState extends State<MeetingTimeDialog> {
@override
Widget build(BuildContext context) {
final userRole = context.watch<AuthViewModel>().userRole;
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
@@ -40,7 +38,7 @@ class _MeetingTimeDialogState extends State<MeetingTimeDialog> {
child: Wrap(
children: [
Container(
// width: double.infinity,
width: 560.0,
padding: EdgeInsets.fromLTRB(
24.0.w(),
24.0.h(),
@@ -54,15 +52,45 @@ class _MeetingTimeDialogState extends State<MeetingTimeDialog> {
),
child: Column(
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
InkWell(
onTap: () {
context.pop();
},
splashColor: Colors.transparent,
child: Container(
width: 24.0.w(),
height: 24.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColors.grey60,
width: 2.0,
),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: AppColors.grey60,
size: 16.0,
),
),
),
],
),
SizedBox(height: 15.0.h()),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 8.0.h()),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
@@ -86,32 +114,37 @@ class _MeetingTimeDialogState extends State<MeetingTimeDialog> {
),
SizedBox(height: 8.0.h()),
SizedBox(height: 8.0.h()),
Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
widget.onConfirm(type);
context.pop();
userRole == Role.admin
? const CompletionOfDocumentsRouteData().push(context)
: const FinalCompletionOfDocumentsRouteData().push(
context,
);
},
child: Container(
width: double.infinity,
height: 56.0.h(),
decoration: BoxDecoration(
color: AppColors.primary20,
borderRadius: BorderRadius.circular(100),
),
alignment: Alignment.center,
child: Text(
TenderDetailsStrings.apply,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.mainBlue,
Align(
alignment: Alignment.centerRight,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(100),
onTap: () {
// widget.onConfirm(type);
context.pop();
showDialog(
context: context,
builder: (context) {
return const MeetingTimeSuccessfulRegisteredDialog();
},
);
},
child: Container(
width: 150,
height: 56.0.h(),
decoration: BoxDecoration(
color: AppColors.primary20,
borderRadius: BorderRadius.circular(100),
),
alignment: Alignment.center,
child: Text(
TenderDetailsStrings.apply,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.mainBlue,
),
),
),
),
@@ -0,0 +1,190 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:tm_app/core/constants/assets.dart';
import 'package:tm_app/core/routes/app_routes.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/login/widgets/widgets.dart';
import '../../../core/utils/app_toast.dart';
import '../strings/tender_details_strings.dart';
class MeetingTimeSuccessfulRegisteredBottomSheet extends StatelessWidget {
const MeetingTimeSuccessfulRegisteredBottomSheet({super.key});
@override
Widget build(BuildContext context) {
return Wrap(
children: [
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(
horizontal: 24.0.w(),
vertical: 24.0.h(),
),
decoration: BoxDecoration(
color: AppColors.backgroundColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0),
topRight: Radius.circular(16.0),
),
),
alignment: Alignment.center,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
InkWell(
onTap: () {
context.pop();
},
splashColor: Colors.transparent,
child: Container(
width: 24.0.w(),
height: 24.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: AppColors.grey60, width: 2.0),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: AppColors.grey60,
size: 16.0,
),
),
),
],
),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 24.0.h()),
Container(
width: 64.0.w(),
height: 64.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.green30,
),
alignment: Alignment.center,
child: Icon(Icons.check, color: AppColors.white, size: 32.0),
),
SizedBox(height: 40.0.h()),
Text(
TenderDetailsStrings.requestSuccessfullyRegistered,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.grey80,
),
),
SizedBox(height: 40.0.h()),
Container(
width: double.infinity,
height: 66.0.h(),
decoration: BoxDecoration(
color: AppColors.green0,
borderRadius: BorderRadius.circular(4),
border: Border.all(color: AppColors.green10),
),
alignment: Alignment.center,
child: Row(
children: [
SizedBox(width: 16.0.w()),
Container(
width: 32.0.w(),
height: 32.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColors.green30,
width: 2.0.w(),
),
),
alignment: Alignment.center,
child: Icon(
Icons.check,
color: AppColors.green30,
size: 16.0,
),
),
SizedBox(width: 12.0.w()),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.grey80,
),
),
SizedBox(height: 8.0.h()),
Row(
children: [
SvgPicture.asset(AssetsManager.clock),
SizedBox(width: 4.0.w()),
Text(
'Sat 2025-06-14',
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey60,
),
),
SizedBox(width: 12.0.w()),
SvgPicture.asset(AssetsManager.calendar),
SizedBox(width: 4.0.w()),
Text(
'12:00',
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey60,
),
),
],
),
],
),
],
),
),
SizedBox(height: 24.0.h()),
BaseButton(
isEnabled: true,
width: double.infinity,
height: 56.0.h(),
onPressed: () {
AppToast.success(
context,
TenderDetailsStrings.meetingTimeSuccessfullySet,
);
const CompletionOfDocumentsRouteData().push(context);
},
textColor: AppColors.primaryColor,
backgroundColor: AppColors.primary20,
text: TenderDetailsStrings.confirmAndClose,
),
SizedBox(height: 24.0.h()),
],
),
),
],
);
}
}
@@ -0,0 +1,205 @@
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/utils/size_config.dart';
import '../../../core/constants/assets.dart';
import '../../../core/routes/app_routes.dart';
import '../../../core/theme/colors.dart';
import '../../../core/utils/app_toast.dart';
import '../../../view_models/auth_view_model.dart';
import '../../shared/base_button.dart';
import '../strings/tender_details_strings.dart';
class MeetingTimeSuccessfulRegisteredDialog extends StatelessWidget {
const MeetingTimeSuccessfulRegisteredDialog({super.key});
@override
Widget build(BuildContext context) {
final userRole = context.watch<AuthViewModel>().userRole;
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide.none,
),
insetPadding: const EdgeInsets.symmetric(horizontal: 150),
child: Wrap(
children: [
Container(
width: 550,
padding: EdgeInsets.symmetric(
horizontal: 24.0.w(),
vertical: 24.0.h(),
),
decoration: BoxDecoration(
color: AppColors.backgroundColor,
borderRadius: BorderRadius.circular(16),
),
alignment: Alignment.center,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
InkWell(
onTap: () {
context.pop();
},
splashColor: Colors.transparent,
child: Container(
width: 24.0.w(),
height: 24.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColors.grey60,
width: 2.0,
),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: AppColors.grey60,
size: 16.0,
),
),
),
],
),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 24.0.h()),
Container(
width: 64.0.w(),
height: 64.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColors.green30,
),
alignment: Alignment.center,
child: Icon(Icons.check, color: AppColors.white, size: 32.0),
),
SizedBox(height: 40.0.h()),
Text(
TenderDetailsStrings.requestSuccessfullyRegistered,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.grey80,
),
),
SizedBox(height: 40.0.h()),
Container(
width: double.infinity,
height: 66.0.h(),
decoration: BoxDecoration(
color: AppColors.green0,
borderRadius: BorderRadius.circular(4),
border: Border.all(color: AppColors.green10),
),
alignment: Alignment.center,
child: Row(
children: [
SizedBox(width: 16.0.w()),
Container(
width: 32.0.w(),
height: 32.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColors.green30,
width: 2.0.w(),
),
),
alignment: Alignment.center,
child: Icon(
Icons.check,
color: AppColors.green30,
size: 16.0,
),
),
SizedBox(width: 12.0.w()),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
TenderDetailsStrings.meetingTime,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.grey80,
),
),
SizedBox(height: 8.0.h()),
Row(
children: [
SvgPicture.asset(AssetsManager.clock),
SizedBox(width: 4.0.w()),
Text(
'Sat 2025-06-14',
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey60,
),
),
SizedBox(width: 12.0.w()),
SvgPicture.asset(AssetsManager.calendar),
SizedBox(width: 4.0.w()),
Text(
'12:00',
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
color: AppColors.grey60,
),
),
],
),
],
),
],
),
),
SizedBox(height: 24.0.h()),
BaseButton(
isEnabled: true,
width: double.infinity,
height: 56.0.h(),
onPressed: () {
context.pop();
AppToast.success(
context,
TenderDetailsStrings.meetingTimeSuccessfullySet,
);
userRole == Role.admin
? const CompletionOfDocumentsRouteData().push(context)
: const FinalCompletionOfDocumentsRouteData().push(
context,
);
},
textColor: AppColors.primaryColor,
backgroundColor: AppColors.primary20,
text: TenderDetailsStrings.confirmAndClose,
),
SizedBox(height: 24.0.h()),
],
),
),
],
),
);
}
}
@@ -88,11 +88,11 @@ class _TenderDetailActionsState extends State<TenderDetailActions> {
builder: (_) {
return MeetingTimeBottomSheet(
onConfirm: (value) {
AppToast.success(
context,
TenderDetailsStrings
.meetingTimeSuccessfullySet,
);
// AppToast.success(
// context,
// TenderDetailsStrings
// .meetingTimeSuccessfullySet,
// );
},
);
},
@@ -225,13 +225,7 @@ class _TenderDetailActionsState extends State<TenderDetailActions> {
context: context,
builder: (context) {
return MeetingTimeDialog(
onConfirm: (value) {
AppToast.success(
context,
TenderDetailsStrings
.meetingTimeSuccessfullySet,
);
},
onConfirm: (value) {},
);
},
);
@@ -27,7 +27,7 @@ class _SelectSubmissionBottomSheetState
Container(
width: double.infinity,
// height: 272.0.h(),
padding: EdgeInsets.fromLTRB(24.0.w(), 12.0.h(), 24.0.w(), 33.0.h()),
padding: EdgeInsets.fromLTRB(24.0.w(), 24.0.h(), 24.0.w(), 33.0.h()),
decoration: BoxDecoration(
color: AppColors.backgroundColor,
borderRadius: const BorderRadius.only(
@@ -37,23 +37,41 @@ class _SelectSubmissionBottomSheetState
),
child: Column(
children: [
Align(
alignment: AlignmentDirectional.centerStart,
child: IconButton(
onPressed: () {
context.pop();
},
icon: const Icon(Icons.close),
),
),
Text(
CommonStrings.selectSubmission,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
CommonStrings.selectSubmission,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
InkWell(
onTap: () {
context.pop();
},
splashColor: Colors.transparent,
child: Container(
width: 24.0.w(),
height: 24.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: AppColors.grey60, width: 2.0),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: AppColors.grey60,
size: 16.0,
),
),
),
],
),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 8.0.h()),
_submissionType(
title: CommonStrings.selfApply,
+35 -60
View File
@@ -33,15 +33,43 @@ class _SelectSubmissionDialogState extends State<SelectSubmissionDialog> {
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
CommonStrings.selectSubmission,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
CommonStrings.selectSubmission,
style: TextStyle(
fontSize: 20.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.grey70,
),
),
InkWell(
onTap: () {
context.pop();
},
splashColor: Colors.transparent,
child: Container(
width: 24.0.w(),
height: 24.0.w(),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: AppColors.grey60, width: 2.0),
),
alignment: Alignment.center,
child: Icon(
Icons.close,
color: AppColors.grey60,
size: 16.0,
),
),
),
],
),
SizedBox(height: 16.0.h()),
Divider(color: AppColors.grey20),
SizedBox(height: 8.0.h()),
_submissionType(
title: CommonStrings.selfApply,
@@ -68,59 +96,6 @@ class _SelectSubmissionDialogState extends State<SelectSubmissionDialog> {
child: Row(
children: [
const Spacer(),
// InkWell(
// onTap: () {
// context.pop();
// },
// child: Container(
// width: 150,
// height: 56.0,
// decoration: BoxDecoration(
// color: AppColors.red10,
// borderRadius: BorderRadius.circular(100),
// ),
// alignment: Alignment.center,
// child: Text(
// CommonStrings.cancel,
// style: TextStyle(
// fontSize: 14.0.sp(),
// fontWeight: FontWeight.w500,
// color: AppColors.red20,
// ),
// ),
// ),
// ),
InkWell(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
onTap: () {
context.pop();
},
child: Container(
width: 150,
height: 56.0,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(100),
border: Border.all(
color: AppColors.errorColor,
width: 2.0,
),
),
alignment: Alignment.center,
child: Text(
CommonStrings.cancel,
style: TextStyle(
fontSize: 14.0.sp(),
fontWeight: FontWeight.w500,
color: AppColors.errorColor,
),
),
),
),
SizedBox(width: 10.0.w()),
InkWell(
onTap: () {
widget.onConfirm(type);