Added detailst design

This commit is contained in:
llsajjad
2025-08-06 08:06:27 +03:30
parent 9f6c458e15
commit ca818379ad
11 changed files with 455 additions and 16 deletions
+2
View File
@@ -17,4 +17,6 @@ class AssetsManager {
static const location = 'assets/icons/location.svg';
static const arrowCircleLeft = 'assets/icons/arrow-circle-left.svg';
static const arrowCircleRight = 'assets/icons/arrow-circle-right.svg';
static const arrowLeft = 'assets/svgs/arrow_left.svg';
static const export = 'assets/svgs/export.svg';
}
+7 -1
View File
@@ -20,15 +20,21 @@ class AppColors {
static const Color successColor = Color(0xFF28A745);
static const Color errorColor = Color(0xFFDC3545);
static const Color warningColor = Color(0xFFFFC107);
static const Color jellyBean = Color(0xFF34BCCB);
static const Color grey = Color(0xFF555555);
static const Color grey50 = Color(0xFF9E9E9E);
static const Color grey60 = Color(0xFF777777);
static const Color grey70 = Color(0xFF444444);
static const Color grey80 = Color(0xFF222222);
static const Color grey10 = Color(0xFFF4F4F4);
static const Color grey20 = Color(0xFFE3E3E3);
static const Color grey0 = Color(0xFFFCFCFC);
static const Color backgroundColor = Color(0xFFFFFFFF);
static const Color borderColor = Color(0xFFE1E1E1);
static const Color primary2 = Color(0xFFE5EFFF);
static const Color paleOrange = Color(0xFFfff7ee);
static const Color red10 = Color(0xFFC02525);
static const Color lightBlue = Color(0xFFe8ecfc);
static const Color cyanAqua = Color(0xFFd6f4f8);
static const Color cyanTeal = Color(0xFF24A6B4);
}
+2 -3
View File
@@ -1,8 +1,7 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:tm_app/views/detail/detail_screen.dart';
import '../../views/home/home_screen.dart';
import '../../views/login/login_screen.dart';
import '../../views/profile/profile_screen.dart';
import '../../views/tenders/tenders_screen.dart';
import 'app_shell_screen.dart';
@@ -31,7 +30,7 @@ class LoginScreenRoute extends GoRouteData with _$LoginScreenRoute {
@override
Widget build(BuildContext context, GoRouterState state) {
return const LoginScreen();
return const TenderDetailScreen();
}
}
+356
View File
@@ -0,0 +1,356 @@
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'),
infoItem(
'Deadline',
'For approval: 2025-05-21\nFor submission: 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 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,
),
),
),
);
}
}
}