Refactor: rename BottomNavigation and update TendersScreen structure
- Renamed BottomNavigation to TenderBottomNavigation for clarity. - Updated TendersScreen to use TenderBottomNavigation. - Converted TendersScreen from StatelessWidget to StatefulWidget to manage tab state. - Added TabController for handling tab changes and improved layout with SafeArea and PageView.
This commit is contained in:
@@ -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="M12 2C17.5 2 22 6.5 22 12C22 17.5 17.5 22 12 22C6.5 22 2 17.5 2 12C2 6.5 6.5 2 12 2Z" stroke="#9E9E9E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.17188 9.16813L14.8319 14.8281" stroke="#9E9E9E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14.8319 9.16813L9.17188 14.8281" stroke="#9E9E9E" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 535 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.48047 5.64954L10.5805 3.24954C10.9805 2.84954 11.8805 2.64954 12.4805 2.64954H16.2805C17.4805 2.64954 18.7805 3.54954 19.0805 4.74954L21.4805 12.0495C21.9805 13.4495 21.0805 14.6495 19.5805 14.6495H15.5805C14.9805 14.6495 14.4805 15.1495 14.5805 15.8495L15.0805 19.0495C15.2805 19.9495 14.6805 20.9495 13.7805 21.2495C12.9805 21.5495 11.9805 21.1495 11.5805 20.5495L7.48047 14.4495" stroke="#9E9E9E" stroke-width="2" stroke-miterlimit="10"/>
|
||||
<path d="M2.37891 5.65156V15.4516C2.37891 16.8516 2.97891 17.3516 4.37891 17.3516H5.37891C6.77891 17.3516 7.37891 16.8516 7.37891 15.4516V5.65156C7.37891 4.25156 6.77891 3.75156 5.37891 3.75156H4.37891C2.97891 3.75156 2.37891 4.25156 2.37891 5.65156Z" stroke="#9E9E9E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 892 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.48047 18.3505L10.5805 20.7505C10.9805 21.1505 11.8805 21.3505 12.4805 21.3505H16.2805C17.4805 21.3505 18.7805 20.4505 19.0805 19.2505L21.4805 11.9505C21.9805 10.5505 21.0805 9.35046 19.5805 9.35046H15.5805C14.9805 9.35046 14.4805 8.85046 14.5805 8.15046L15.0805 4.95046C15.2805 4.05046 14.6805 3.05046 13.7805 2.75046C12.9805 2.45046 11.9805 2.85046 11.5805 3.45046L7.48047 9.55046" stroke="#34C759" stroke-width="2" stroke-miterlimit="10"/>
|
||||
<path d="M2.37891 18.3484V8.54844C2.37891 7.14844 2.97891 6.64844 4.37891 6.64844H5.37891C6.77891 6.64844 7.37891 7.14844 7.37891 8.54844V18.3484C7.37891 19.7484 6.77891 20.2484 5.37891 20.2484H4.37891C2.97891 20.2484 2.37891 19.7484 2.37891 18.3484Z" stroke="#34C759" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 892 B |
@@ -3,14 +3,14 @@ import 'package:flutter_svg/svg.dart';
|
||||
|
||||
import '../../core/utils/size_config.dart';
|
||||
|
||||
class BottomNavigation extends StatefulWidget {
|
||||
const BottomNavigation({super.key});
|
||||
class TenderBottomNavigation extends StatefulWidget {
|
||||
const TenderBottomNavigation({super.key});
|
||||
|
||||
@override
|
||||
State<BottomNavigation> createState() => _BottomNavigationState();
|
||||
State<TenderBottomNavigation> createState() => _TenderBottomNavigationState();
|
||||
}
|
||||
|
||||
class _BottomNavigationState extends State<BottomNavigation> {
|
||||
class _TenderBottomNavigationState extends State<TenderBottomNavigation> {
|
||||
int activeTab = 0;
|
||||
|
||||
@override
|
||||
|
||||
@@ -10,4 +10,9 @@ class AssetsManager {
|
||||
|
||||
// tenders page
|
||||
static const tenderLogo = 'assets/icons/tenderLogo.png';
|
||||
static const like = 'assets/icons/like.svg';
|
||||
static const dislike = 'assets/icons/dislike.svg';
|
||||
static const closeCircle = 'assets/icons/close-circle.svg';
|
||||
static const seFlag = 'assets/icons/SE.png';
|
||||
static const location = 'assets/icons/location.svg';
|
||||
}
|
||||
|
||||
@@ -21,5 +21,13 @@ class AppColors {
|
||||
static const Color errorColor = Color(0xFFDC3545);
|
||||
static const Color warningColor = Color(0xFFFFC107);
|
||||
|
||||
static const Color grey = Color(0xFF555555);
|
||||
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 grey0 = Color(0xFFFCFCFC);
|
||||
static const Color backgroundColor = Color(0xFFFFFFFF);
|
||||
static const Color borderColor = Color(0xFFE1E1E1);
|
||||
static const Color primary2 = Color(0xFFE5EFFF);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class Homescreen extends StatelessWidget {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: _body(),
|
||||
bottomNavigationBar: BottomNavigation(),
|
||||
bottomNavigationBar: TenderBottomNavigation(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
class Tender {
|
||||
final String date;
|
||||
final String deadline;
|
||||
final String title;
|
||||
final String description;
|
||||
final String tenderId;
|
||||
final String location;
|
||||
final String country;
|
||||
final double matchPercentage;
|
||||
|
||||
Tender({
|
||||
required this.date,
|
||||
required this.deadline,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.tenderId,
|
||||
required this.location,
|
||||
required this.country,
|
||||
required this.matchPercentage,
|
||||
});
|
||||
|
||||
factory Tender.fromJson(Map<String, dynamic> json) {
|
||||
return Tender(
|
||||
date: json['date'] as String,
|
||||
deadline: json['deadline'] as String,
|
||||
title: json['title'] as String,
|
||||
description: json['description'] as String,
|
||||
tenderId: json['tenderId'] as String,
|
||||
location: json['location'] as String,
|
||||
country: json['country'] as String,
|
||||
matchPercentage: (json['matchPercentage'] as num).toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'date': date,
|
||||
'deadline': deadline,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'tenderId': tenderId,
|
||||
'location': location,
|
||||
'country': country,
|
||||
'matchPercentage': matchPercentage,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
final List<Tender> sampleTenders = [
|
||||
Tender(
|
||||
date: '2025-05-20',
|
||||
deadline: '2025-06-10',
|
||||
title: 'Digital Services Tender',
|
||||
description:
|
||||
'A tender for digital services and IT infrastructure development. The project involves modernizing existing systems and implementing new digital solutions for improved efficiency.',
|
||||
tenderId: 'KLF 2025/119',
|
||||
location: 'Stockholm',
|
||||
country: 'SE',
|
||||
matchPercentage: 85.0,
|
||||
),
|
||||
Tender(
|
||||
date: '2025-04-15',
|
||||
deadline: '2025-05-01',
|
||||
title: 'Construction Project',
|
||||
description:
|
||||
'Seeking contractors for a large-scale construction project in the city center. Includes both residential and commercial buildings.',
|
||||
tenderId: 'CST 2025/042',
|
||||
location: 'Gothenburg',
|
||||
country: 'SE',
|
||||
matchPercentage: 72.0,
|
||||
),
|
||||
Tender(
|
||||
date: '2025-03-10',
|
||||
deadline: '2025-04-05',
|
||||
title: 'Healthcare Equipment Supply',
|
||||
description:
|
||||
'Supplying medical and healthcare equipment to regional hospitals. Includes installation and maintenance services.',
|
||||
tenderId: 'HLT 2025/301',
|
||||
location: 'Malmö',
|
||||
country: 'SE',
|
||||
matchPercentage: 90.0,
|
||||
),
|
||||
Tender(
|
||||
date: '2025-02-28',
|
||||
deadline: '2025-03-20',
|
||||
title: 'IT Consulting Services',
|
||||
description:
|
||||
'Looking for experienced IT consultants to support digital transformation initiatives for public sector organizations.',
|
||||
tenderId: 'ITC 2025/210',
|
||||
location: 'Uppsala',
|
||||
country: 'SE',
|
||||
matchPercentage: 78.0,
|
||||
),
|
||||
];
|
||||
@@ -1,40 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../core/constants/assets.dart';
|
||||
import '../../common/widgets/bottom_navigation.dart';
|
||||
import '../../core/constants/colors.dart';
|
||||
import '../../core/constants/strings.dart';
|
||||
import '../../core/utils/size_config.dart';
|
||||
import 'models/tender_model.dart';
|
||||
import 'widgets/widgets.dart';
|
||||
|
||||
class TendersScreen extends StatelessWidget {
|
||||
class TendersScreen extends StatefulWidget {
|
||||
const TendersScreen({super.key});
|
||||
|
||||
@override
|
||||
State<TendersScreen> createState() => _TendersScreenState();
|
||||
}
|
||||
|
||||
class _TendersScreenState extends State<TendersScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final TabController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = TabController(length: 2, vsync: this);
|
||||
// Add listener to rebuild when tab changes
|
||||
controller.addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w(), vertical: 24.0.h()),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
backgroundColor: AppColors.backgroundColor,
|
||||
bottomNavigationBar: TenderBottomNavigation(),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 24.0.w(),
|
||||
vertical: 24.0.h(),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
AppStrings.tendersTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey70,
|
||||
TenderAppBar(),
|
||||
SizedBox(height: 24.0.h()),
|
||||
|
||||
MainTabBar(controller: controller),
|
||||
SizedBox(height: 24.0.h()),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 762.0.h(),
|
||||
child: PageView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: sampleTenders.length,
|
||||
itemBuilder: (context, index) {
|
||||
final tender = sampleTenders[index];
|
||||
|
||||
return TenderCard(
|
||||
date: tender.date,
|
||||
deadline: tender.deadline,
|
||||
title: tender.title,
|
||||
description: tender.description,
|
||||
tenderId: tender.tenderId,
|
||||
location: tender.location,
|
||||
country: tender.country,
|
||||
matchPercentage: tender.matchPercentage,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Image.asset(
|
||||
AssetsManager.tenderLogo,
|
||||
width: 59.0.w(),
|
||||
height: 28.0.h(),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LastTendersTab extends StatelessWidget {
|
||||
const LastTendersTab({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(color: Colors.blue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/constants/colors.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
import 'tab_item.dart';
|
||||
|
||||
class MainTabBar extends StatefulWidget {
|
||||
const MainTabBar({super.key, required this.controller});
|
||||
|
||||
final TabController controller;
|
||||
|
||||
@override
|
||||
State<MainTabBar> createState() => _MainTabBarState();
|
||||
}
|
||||
|
||||
class _MainTabBarState extends State<MainTabBar> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: 51.0.h(),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.0.w(), vertical: 8.0.h()),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey10,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: TabBar(
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
dividerColor: Colors.transparent,
|
||||
indicator: BoxDecoration(
|
||||
color: AppColors.backgroundColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.12),
|
||||
blurRadius: 4,
|
||||
offset: Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
controller: widget.controller,
|
||||
tabs: [
|
||||
TabItem(
|
||||
title: 'New',
|
||||
isActive: widget.controller.index == 0,
|
||||
onTap: () {
|
||||
widget.controller.animateTo(0);
|
||||
},
|
||||
),
|
||||
TabItem(
|
||||
title: 'Last',
|
||||
isActive: widget.controller.index == 1,
|
||||
onTap: () {
|
||||
widget.controller.animateTo(1);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/constants/colors.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
|
||||
class TabItem extends StatelessWidget {
|
||||
const TabItem({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.isActive,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final bool isActive;
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Tab(
|
||||
child: SizedBox(
|
||||
width: 170.0.w(),
|
||||
child: Center(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isActive ? AppColors.mainBlue : AppColors.grey60,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/constants/assets.dart';
|
||||
import '../../../core/constants/colors.dart';
|
||||
import '../../../core/constants/strings.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
|
||||
class TenderAppBar extends StatelessWidget {
|
||||
const TenderAppBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppStrings.tendersTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey70,
|
||||
),
|
||||
),
|
||||
Image.asset(
|
||||
AssetsManager.tenderLogo,
|
||||
width: 59.0.w(),
|
||||
height: 28.0.h(),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
import '../../../core/constants/assets.dart';
|
||||
import '../../../core/constants/colors.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
|
||||
class TenderCard extends StatelessWidget {
|
||||
final String date;
|
||||
final String deadline;
|
||||
final String title;
|
||||
final String description;
|
||||
final String tenderId;
|
||||
final String location;
|
||||
final String country;
|
||||
final double matchPercentage;
|
||||
final VoidCallback? onApply;
|
||||
final VoidCallback? onLike;
|
||||
final VoidCallback? onDislike;
|
||||
final VoidCallback? onClose;
|
||||
final bool isLiked;
|
||||
final bool isDisliked;
|
||||
|
||||
const TenderCard({
|
||||
super.key,
|
||||
required this.date,
|
||||
required this.deadline,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.tenderId,
|
||||
required this.location,
|
||||
required this.country,
|
||||
required this.matchPercentage,
|
||||
this.onApply,
|
||||
this.onLike,
|
||||
this.onDislike,
|
||||
this.onClose,
|
||||
this.isLiked = false,
|
||||
this.isDisliked = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 364.0.w(),
|
||||
height: 587.0.h(),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey0,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.borderColor),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Main content
|
||||
Padding(
|
||||
padding: EdgeInsets.all(16.0.w()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Date
|
||||
Text(
|
||||
date,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey60,
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12.0.h()),
|
||||
|
||||
// Deadline badge
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 24.0.h(),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8.0.w(),
|
||||
vertical: 4.0.h(),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primary2,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Deadline:',
|
||||
style: TextStyle(
|
||||
color: AppColors.mainBlue,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
deadline,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey80,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12.0.h()),
|
||||
|
||||
// Title
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey80,
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.0.h()),
|
||||
|
||||
// Description
|
||||
Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey70,
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12.0.h()),
|
||||
|
||||
// Tender ID
|
||||
Text(
|
||||
tenderId,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey60,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
// Bottom section with progress and actions
|
||||
Padding(
|
||||
padding: EdgeInsets.all(16.0.w()),
|
||||
child: Column(
|
||||
children: [
|
||||
// Match percentage
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Match with your profile',
|
||||
style: TextStyle(
|
||||
color: AppColors.primaryTextColor,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${matchPercentage.toInt()}%',
|
||||
style: TextStyle(
|
||||
color: const Color(0xFF2484A8),
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8.0.h()),
|
||||
|
||||
// Progress bar
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 4.0.h(),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey10,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
child: FractionallySizedBox(
|
||||
alignment: Alignment.centerLeft,
|
||||
widthFactor: matchPercentage / 100,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF34BC9B),
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.0.h()),
|
||||
|
||||
// Location and apply button
|
||||
Row(
|
||||
children: [
|
||||
// Location info
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(AssetsManager.location),
|
||||
SizedBox(width: 4.0.w()),
|
||||
Text(
|
||||
location,
|
||||
style: TextStyle(
|
||||
color: AppColors.primaryTextColor,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8.0.w()),
|
||||
// Country flag placeholder
|
||||
Image.asset(
|
||||
AssetsManager.seFlag,
|
||||
width: 32.0.w(),
|
||||
height: 21.0.h(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Apply button
|
||||
GestureDetector(
|
||||
onTap: onApply,
|
||||
child: Container(
|
||||
width: 108.0.w(),
|
||||
height: 40.0.h(),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primary2,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
),
|
||||
child: Text(
|
||||
'See More',
|
||||
style: TextStyle(
|
||||
color: AppColors.mainBlue,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 24.0.h()),
|
||||
TenderActionButtons(
|
||||
isDisliked: isDisliked,
|
||||
isLiked: isLiked,
|
||||
onDislike: onDislike,
|
||||
onLike: onLike,
|
||||
onClose: onClose,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Action buttons row widget
|
||||
class TenderActionButtons extends StatelessWidget {
|
||||
final VoidCallback? onLike;
|
||||
final VoidCallback? onDislike;
|
||||
final VoidCallback? onClose;
|
||||
final bool isLiked;
|
||||
final bool isDisliked;
|
||||
|
||||
const TenderActionButtons({
|
||||
super.key,
|
||||
this.onLike,
|
||||
this.onDislike,
|
||||
this.onClose,
|
||||
this.isLiked = false,
|
||||
this.isDisliked = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(width: 16.0.w()),
|
||||
|
||||
// Dislike button
|
||||
GestureDetector(
|
||||
onTap: onDislike,
|
||||
child: SvgPicture.asset(AssetsManager.dislike),
|
||||
),
|
||||
|
||||
SizedBox(width: 16.0.w()),
|
||||
|
||||
// Close button
|
||||
GestureDetector(
|
||||
onTap: onClose,
|
||||
child: SvgPicture.asset(AssetsManager.closeCircle),
|
||||
),
|
||||
SizedBox(width: 16.0.w()),
|
||||
// Like button
|
||||
GestureDetector(
|
||||
onTap: onLike,
|
||||
child: SvgPicture.asset(AssetsManager.like),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export 'last_tenders_tab.dart';
|
||||
export 'main_tab_bar.dart';
|
||||
export 'tender_app_bar.dart';
|
||||
export 'tender_card.dart';
|
||||
Reference in New Issue
Block a user