This commit is contained in:
amirrezaghabeli
2025-08-06 08:31:47 +03:30
11 changed files with 534 additions and 16 deletions
+432
View File
@@ -0,0 +1,432 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:tm_app/core/constants/assets.dart';
import 'package:tm_app/core/constants/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/login/widgets/login_button.dart';
class TenderDetailScreen extends StatelessWidget {
const TenderDetailScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(60),
child: AppBar(
backgroundColor: Colors.white,
elevation: 0,
titleSpacing: 0,
leading: IconButton(
icon: SvgPicture.asset(
AssetsManager.arrowLeft,
height: 24.0.w(),
width: 24.0.w(),
),
onPressed: () => Navigator.pop(context),
),
title: const Text(
'Tender Detail',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w600),
),
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
border: Border.all(width: 0.5, color: AppColors.grey50),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'2025-05-21',
style: TextStyle(
color: AppColors.grey60,
fontWeight: FontWeight.w400,
fontSize: 12.0.sp(),
),
),
StatusTag(
text: 'Open',
textColor: AppColors.cyanTeal,
backgroundColor: AppColors.cyanAqua,
),
],
),
SizedBox(height: 12.0.h()),
Text(
'Operation, support and further development of open e-platform Operation, support and further development of open e-platform',
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w600,
fontSize: 18.0.sp(),
),
),
SizedBox(height: 10.0.h()),
Divider(),
SizedBox(height: 5.0.h()),
infoItem('ID', 'JNDFKMDV-100-JF'),
deadlineItem(
title: 'Deadline',
approvalText: 'For approval',
approvalDate: '2025-05-21',
submissionText: 'For submission',
submissionDate: '2025-05-21',
),
infoItem('Client', 'Procurement Notice Procurement Notice'),
infoItem('Delivery Locations', 'Norrbotten County'),
infoItem('Reference Number', 'KLF 2025/120'),
Padding(
padding: const EdgeInsets.symmetric(vertical: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 45.0.h(),
child: Text(
'Reference Number',
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w600,
fontSize: 16.0.sp(),
),
),
),
Row(
children: [
SvgPicture.asset(
AssetsManager.location,
height: 20.0.h(),
width: 20.0.w(),
),
SizedBox(width: 4.0.w()),
Text(
'UK',
style: TextStyle(
color: AppColors.grey70,
fontSize: 14.0.sp(),
fontWeight: FontWeight.w400,
),
),
SizedBox(width: 4.0.w()),
Image.asset(
AssetsManager.seFlag,
height: 20.0.h(),
width: 20.0.w(),
),
],
),
SizedBox(height: 8.0.h()),
],
),
),
SizedBox(height: 16.0.h()),
Text(
'Locations',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0.sp(),
),
),
SizedBox(height: 8.0.h()),
const Text(
'Luleå Municipality is procuring on behalf of Norrbottens e-board (all municipalities in Norrbotten).\n\n'
'The procurement includes operation, support, and further development of the existing open e-platform.\n\n'
'No additional information, amendments, or answers to questions will be provided after June 16.\n\n'
'0 additional information, amendments, or answers to questions will be provided after June 16.\n\n'
'0 additional information, amendments, or answers to questions will be provided after June 16 website: www.tenders.com\n\n'
'Lorem ipsum is amet\n\n'
'Luleå Municipality is procuring on behalf of Norrbottens e-board (all municipalities in Norrbotten).\n\n'
'The procurement includes operation, support, and further development of the existing open e-platform.\n\n'
'No additional information, amendments, or answers to questions will be provided after June 16.\n\n'
'0 additional information, amendments, or answers to questions will be provided after June 16.\n\n'
'0 additional information, amendments, or answers to questions will be provided after June 16.',
style: TextStyle(height: 1.5),
),
SizedBox(height: 16.0.h()),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset(AssetsManager.export),
SizedBox(height: 6.0.h()),
Text(
'PDF , Document',
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
),
],
),
],
),
),
SizedBox(height: 24.0.h()),
ResumeMatchCard(),
SizedBox(height: 24.0.h()),
Column(
children: [
BaseButton(
isEnabled: true,
text: 'Submit',
backgroundColor: AppColors.lightBlue,
textColor: AppColors.mainBlue,
onPressed: () {},
),
SizedBox(height: 16.0.h()),
BaseButton(
isEnabled: true,
text: 'reject',
borderColor: AppColors.red10,
textColor: AppColors.red10,
backgroundColor: Colors.white,
borderWidth: 1,
onPressed: () {},
),
SizedBox(height: 16.0.h()),
],
),
],
),
),
),
);
}
Widget deadlineItem({
required String title,
required String approvalText,
required String approvalDate,
required String submissionText,
required String submissionDate,
}) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 45.0.h(),
child: Text(
title,
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w600,
fontSize: 16.0.sp(),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
approvalText,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
Text(
approvalDate,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
],
),
SizedBox(height: 4.0.h()),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
submissionText,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
Text(
submissionDate,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
],
),
SizedBox(height: 8.0.h()),
Divider(),
],
),
);
}
Widget infoItem(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 45.0.h(),
child: Text(
title,
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w600,
fontSize: 16.0.sp(),
),
),
),
Text(
value,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
SizedBox(height: 8.0.h()),
Divider(),
],
),
);
}
}
class ResumeMatchCard extends StatelessWidget {
const ResumeMatchCard({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColors.paleOrange,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Match with your profile',
style: TextStyle(
fontSize: 12.0.sp(),
color: Colors.black87,
fontWeight: FontWeight.w400,
),
),
Text(
'75%',
style: TextStyle(
fontSize: 12.0.sp(),
fontWeight: FontWeight.w600,
color: AppColors.jellyBean,
),
),
],
),
SizedBox(height: 6.0.h()),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value: 0.75,
backgroundColor: AppColors.grey20,
valueColor: AlwaysStoppedAnimation<Color>(AppColors.jellyBean),
minHeight: 6,
),
),
SizedBox(height: 16.0.h()),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.warning_rounded, color: Colors.red),
SizedBox(width: 8.0.w()),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Incomplete Resume Information',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16.0.sp(),
color: Colors.black87,
),
),
SizedBox(height: 4.0.h()),
Text(
'No experience in e-platform development',
style: TextStyle(
fontSize: 14.0.sp(),
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
],
),
),
],
),
],
),
);
}
}
class StatusTag extends StatelessWidget {
final String text;
final Color textColor;
final Color backgroundColor;
const StatusTag({
required this.text,
required this.textColor,
required this.backgroundColor,
super.key,
});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.0.w(), vertical: 6.0.h()),
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(8),
),
child: Text(
text,
style: TextStyle(
color: textColor,
fontWeight: FontWeight.w500,
fontSize: 14.0.sp(),
),
),
);
}
}
+1 -1
View File
@@ -83,7 +83,7 @@ class _LoginScreenState extends State<LoginScreen> {
),
SizedBox(height: 32.0.h()),
LoginButton(
BaseButton(
isEnabled: _isLoginEnabled,
onPressed: _isLoginEnabled ? () {} : null,
),
+34 -11
View File
@@ -1,17 +1,30 @@
import 'package:flutter/material.dart';
import '../../../core/constants/colors.dart';
import '../../../core/constants/strings.dart';
import '../../../core/utils/size_config.dart';
class LoginButton extends StatelessWidget {
class BaseButton extends StatelessWidget {
final bool isEnabled;
final VoidCallback? onPressed;
final String? text;
final Color? textColor;
final Color? backgroundColor;
final Color? borderColor;
final double? borderWidth;
final double? borderRadius;
final double? elevation;
const LoginButton({
super.key,
const BaseButton({
required this.isEnabled,
required this.onPressed,
this.text,
this.textColor,
this.backgroundColor,
this.borderColor,
this.borderWidth,
this.borderRadius,
this.elevation,
super.key,
});
@override
@@ -20,19 +33,29 @@ class LoginButton extends StatelessWidget {
width: double.infinity,
height: 55.0.h(),
child: ElevatedButton(
onPressed: onPressed,
onPressed: isEnabled ? onPressed : null,
style: ElevatedButton.styleFrom(
backgroundColor: isEnabled ? AppColors.mainBlue : Colors.grey[300],
foregroundColor: Colors.white,
backgroundColor: backgroundColor ??
(isEnabled ? AppColors.mainBlue : Colors.grey[300]),
foregroundColor: textColor ?? Colors.white,
elevation: elevation ?? 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28.0.w()),
borderRadius: BorderRadius.circular(borderRadius ?? 28.0.w()),
side: BorderSide(
color: borderColor ?? Colors.transparent,
width: borderWidth ?? 0,
),
),
),
child: Text(
AppStrings.loginButton,
style: TextStyle(fontSize: 16.0.sp(), fontWeight: FontWeight.bold),
text ?? AppStrings.loginButton,
style: TextStyle(
fontSize: 16.0.sp(),
fontWeight: FontWeight.bold,
color: textColor ?? Colors.white,
),
),
),
);
}
}
}