added 3 screen mod to detail

This commit is contained in:
llsajjad
2025-08-09 07:54:53 +03:30
parent 9e5e25f784
commit 111c332f74
14 changed files with 815 additions and 422 deletions
@@ -0,0 +1,67 @@
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/strings.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
class TenderDetailDesktopScreen extends StatelessWidget {
const TenderDetailDesktopScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBar(context),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: SizedBox(
width: 740,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TenderDetailHeader(isBig: true,),
SizedBox(height: 24.0.h()),
const TenderDetailCard(),
SizedBox(height: 24.0.h()),
TenderDetailActions(),
],
),
),
),
),
),
);
}
PreferredSizeWidget _buildAppBar(BuildContext context) {
return 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: Text(
AppStrings.tenderDetailTitle,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 20.0.sp(),
),
),
),
);
}
}
@@ -0,0 +1,62 @@
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/strings.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
class TenderDetailMobileScreen extends StatelessWidget {
const TenderDetailMobileScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBar(context),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TenderDetailHeader(isBig: false),
SizedBox(height: 24.0.h()),
const TenderDetailCard(),
SizedBox(height: 24.0.h()),
TenderDetailActions(),
],
),
),
),
);
}
PreferredSizeWidget _buildAppBar(BuildContext context) {
return 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: Text(
AppStrings.tenderDetailTitle,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 20.0.sp(),
),
),
),
);
}
}
+14 -422
View File
@@ -1,432 +1,24 @@
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/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/login/widgets/login_button.dart';
import 'package:tm_app/core/utils/display_size_detector.dart';
import 'package:tm_app/views/detail/detail_desktop_screen.dart';
import 'package:tm_app/views/detail/detail_mobile_screen.dart';
import 'package:tm_app/views/detail/detail_tablet_screen.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),
),
final displaySize = MediaQuery.of(context).size.displaySize;
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(),
),
),
);
switch (displaySize) {
case DisplaySize.large:
case DisplaySize.medium:
return const TenderDetailDesktopScreen();
case DisplaySize.small:
return const TenderDetailTabletScreen();
case DisplaySize.extraSmall:
return const TenderDetailMobileScreen();
}
}
}
@@ -0,0 +1,67 @@
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/strings.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
class TenderDetailTabletScreen extends StatelessWidget {
const TenderDetailTabletScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: _buildAppBar(context),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: SizedBox(
width: 768,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TenderDetailHeader(isBig: true,),
SizedBox(height: 24.0.h()),
const TenderDetailCard(),
SizedBox(height: 24.0.h()),
TenderDetailActions(),
],
),
),
),
),
),
);
}
PreferredSizeWidget _buildAppBar(BuildContext context) {
return 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: Text(
AppStrings.tenderDetailTitle,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 20.0.sp(),
),
),
),
);
}
}
+163
View File
@@ -0,0 +1,163 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
class DeadlineItem extends StatelessWidget {
final String title;
final String approvalText;
final String approvalDate;
final String submissionText;
final String submissionDate;
final bool isBig;
const DeadlineItem({
required this.title, required this.approvalText, required this.approvalDate, required this.submissionText, required this.submissionDate, required this.isBig, super.key,
});
@override
Widget build(BuildContext context) {
return isBig ? 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(),
),
),
),
IntrinsicHeight(
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
approvalText,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
SizedBox(height: 4.0.h()),
Text(
approvalDate,
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
],
),
),
VerticalDivider(
color: AppColors.grey30,
thickness: 1,
width: 24,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
submissionText,
style: TextStyle(
color: AppColors.grey70,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
SizedBox(height: 4.0.h()),
Text(
submissionDate,
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w400,
fontSize: 14.0.sp(),
),
),
],
),
),
],
),
),
SizedBox(height: 8.0.h()),
const Divider(),
],
),
) : 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()),
const Divider(),
],
),
);
}
}
+43
View File
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
class InfoItem extends StatelessWidget {
const InfoItem({required this.title, required this.value, super.key});
final String title;
final String value;
@override
Widget build(BuildContext context) {
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()),
const Divider(),
],
),
);
}
}
+34
View File
@@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/utils/size_config.dart';
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(),
),
),
);
}
}
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/constants/strings.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/login_button.dart';
class TenderDetailActions extends StatelessWidget {
const TenderDetailActions({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
BaseButton(
isEnabled: true,
text: AppStrings.tenderSubmitButton,
backgroundColor: AppColors.lightBlue,
textColor: AppColors.mainBlue,
onPressed: () {},
),
SizedBox(height: 16.0.h()),
BaseButton(
isEnabled: true,
text: AppStrings.tenderRejectButton,
borderColor: AppColors.red10,
textColor: AppColors.red10,
backgroundColor: Colors.white,
borderWidth: 1,
onPressed: () {},
),
SizedBox(height: 16.0.h()),
],
);
}
}
@@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
class TenderDetailCard extends StatelessWidget {
const TenderDetailCard({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: [
const Text(
AppStrings.tenderMatchProfile,
style: TextStyle(
fontSize: 12.0,
color: Colors.black87,
fontWeight: FontWeight.w400,
),
),
Text(
AppStrings.tenderMatchPercentageExample,
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: [
const Icon(Icons.warning_rounded, color: Colors.red),
SizedBox(width: 8.0.w()),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
AppStrings.tenderIncompleteResume,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16.0,
color: Colors.black87,
),
),
SizedBox(height: 4.0),
Text(
AppStrings.tenderNoExperience,
style: TextStyle(
fontSize: 14.0,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
],
),
),
],
),
],
),
);
}
}
@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
import 'package:tm_app/views/detail/widgets/status_tag.dart';
import 'package:tm_app/views/detail/widgets/tender_detail_info_section.dart';
import 'package:tm_app/views/detail/widgets/tender_document_section.dart';
import 'package:tm_app/views/detail/widgets/tender_location_section.dart';
class TenderDetailHeader extends StatelessWidget {
final bool isBig;
const TenderDetailHeader({required this.isBig, super.key});
@override
Widget build(BuildContext context) {
return 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: [
_buildDateAndStatus(),
SizedBox(height: 12.0.h()),
_buildTitle(),
SizedBox(height: 10.0.h()),
const Divider(),
SizedBox(height: 5.0.h()),
TenderDetailInfoSection(isBig: isBig,),
TenderLocationSection(),
SizedBox(height: 16.0.h()),
TenderDocumentSection(),
],
),
);
}
Widget _buildDateAndStatus() => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppStrings.tenderDateExample,
style: TextStyle(
color: AppColors.grey60,
fontWeight: FontWeight.w400,
fontSize: 12.0.sp(),
),
),
const StatusTag(
text: AppStrings.tenderStatusOpen,
textColor: AppColors.cyanTeal,
backgroundColor: AppColors.cyanAqua,
),
],
);
Widget _buildTitle() => Text(
AppStrings.tenderTitleExample,
style: TextStyle(
color: AppColors.grey80,
fontWeight: FontWeight.w600,
fontSize: 18.0.sp(),
),
);
}
@@ -0,0 +1,42 @@
import 'package:flutter/material.dart';
import 'package:tm_app/core/constants/strings.dart';
import 'package:tm_app/views/detail/widgets/deadline_item.dart';
import 'package:tm_app/views/detail/widgets/info_item.dart';
class TenderDetailInfoSection extends StatelessWidget {
final bool isBig;
const TenderDetailInfoSection({required this.isBig ,super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InfoItem(
title: AppStrings.tenderIdLabel,
value: AppStrings.tenderIdExample,
),
DeadlineItem(
title: AppStrings.tenderDeadlineLabel,
approvalText: AppStrings.tenderApprovalText,
approvalDate: AppStrings.tenderApprovalDateExample,
submissionText: AppStrings.tenderSubmissionText,
submissionDate: AppStrings.tenderSubmissionDateExample, isBig: isBig,
),
InfoItem(
title: AppStrings.tenderClientLabel,
value: AppStrings.tenderClientExample,
),
InfoItem(
title: AppStrings.tenderDeliveryLocationsLabel,
value: AppStrings.tenderDeliveryLocationExample,
),
InfoItem(
title: AppStrings.tenderReferenceNumberLabel,
value: AppStrings.tenderReferenceNumberExample,
),
],
);
}
}
@@ -0,0 +1,29 @@
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/strings.dart';
import 'package:tm_app/core/utils/size_config.dart';
class TenderDocumentSection extends StatelessWidget {
const TenderDocumentSection({super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset(AssetsManager.export),
SizedBox(height: 6.0.h()),
Text(
AppStrings.tenderPdfDocument,
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 16.0.sp(),
color: Colors.blue,
decoration: TextDecoration.underline,
),
),
],
);
}
}
@@ -0,0 +1,68 @@
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/strings.dart';
import 'package:tm_app/core/theme/colors.dart';
import 'package:tm_app/core/utils/size_config.dart';
class TenderLocationSection extends StatelessWidget {
const TenderLocationSection({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 45.0.h(),
child: Text(
AppStrings.tenderReferenceNumberLabel,
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(
AppStrings.tenderLocationCountry,
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()),
Text(
AppStrings.tenderLocationLabel,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0.sp()),
),
SizedBox(height: 8.0.h()),
Text(
AppStrings.locationDescription,
style: TextStyle(fontWeight: FontWeight.w400, fontSize: 14.0.sp()),
),
SizedBox(height: 16.0.h()),
],
),
);
}
}