This commit is contained in:
amirrezaghabeli
2025-08-06 08:31:47 +03:30
11 changed files with 534 additions and 16 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.9998 19.9181L8.47984 13.3981C7.70984 12.6281 7.70984 11.3681 8.47984 10.5981L14.9998 4.07812" stroke="#444444" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 318 B

+5
View File
@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.4405 8.89844C20.0405 9.20844 21.5105 11.0584 21.5105 15.1084V15.2384C21.5105 19.7084 19.7205 21.4984 15.2505 21.4984H8.74047C4.27047 21.4984 2.48047 19.7084 2.48047 15.2384V15.1084C2.48047 11.0884 3.93047 9.23844 7.47047 8.90844" stroke="#888888" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 14.9972V3.61719" stroke="#888888" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15.3484 5.85L11.9984 2.5L8.64844 5.85" stroke="#888888" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 680 B

+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
+43
View File
@@ -0,0 +1,43 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
+5
View File
@@ -20,7 +20,12 @@ 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';
<<<<<<< HEAD
//your tenders page
static const tickCircle = 'assets/icons/tick-circle.svg';
=======
static const arrowLeft = 'assets/svgs/arrow_left.svg';
static const export = 'assets/svgs/export.svg';
>>>>>>> 92b89fdea46b90000b1e2c986d973dd8161fb7cb
}
+7 -1
View File
@@ -20,7 +20,7 @@ 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 grey20 = Color(0xFFE4E4E4);
static const Color grey40 = Color(0xFFDADADA);
@@ -29,6 +29,7 @@ class AppColors {
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);
@@ -42,4 +43,9 @@ class AppColors {
static const Color red0 = Color(0xFFF8D6D6);
static const Color red10 = Color(0xFFC02525);
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 '../../views/your_tenders/your_tenders_screen.dart';
@@ -32,7 +31,7 @@ class LoginScreenRoute extends GoRouteData with _$LoginScreenRoute {
@override
Widget build(BuildContext context, GoRouterState state) {
return const LoginScreen();
return const TenderDetailScreen();
}
}
+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,
),
),
),
);
}
}
}