✨ added your tenders screen
This commit is contained in:
@@ -17,7 +17,6 @@ linter:
|
||||
avoid_bool_literals_in_conditional_expressions: true
|
||||
avoid_catches_without_on_clauses: true
|
||||
avoid_catching_errors: true
|
||||
avoid_classes_with_only_static_members: true
|
||||
avoid_final_parameters: true
|
||||
avoid_function_literals_in_foreach_calls: true
|
||||
avoid_relative_lib_imports: true
|
||||
|
||||
@@ -8,7 +8,7 @@ plugins {
|
||||
android {
|
||||
namespace = "com.example.tm_app"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
ndkVersion = "27.0.12077973"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
@@ -1,5 +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 width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.9987 14.6693C11.6654 14.6693 14.6654 11.6693 14.6654 8.0026C14.6654 4.33594 11.6654 1.33594 7.9987 1.33594C4.33203 1.33594 1.33203 4.33594 1.33203 8.0026C1.33203 11.6693 4.33203 14.6693 7.9987 14.6693Z" stroke="#C02525" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.11328 9.89052L9.88661 6.11719" stroke="#C02525" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.88661 9.89052L6.11328 6.11719" stroke="#C02525" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 535 B After Width: | Height: | Size: 602 B |
@@ -1,11 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_70_3561)">
|
||||
<path d="M9.02 2.83998L3.63 7.03998C2.73 7.73998 2 9.22998 2 10.36V17.77C2 20.09 3.89 21.99 6.21 21.99H17.79C20.11 21.99 22 20.09 22 17.78V10.5C22 9.28998 21.19 7.73998 20.2 7.04998L14.02 2.71998C12.62 1.73998 10.37 1.78998 9.02 2.83998Z" fill="#0164FF"/>
|
||||
<path d="M12 17.99V14.99" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_70_3561">
|
||||
<rect width="24" height="24" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 610 B |
@@ -0,0 +1,11 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_719_496)">
|
||||
<path d="M9.02 2.83821L3.63 7.03821C2.73 7.73821 2 9.22821 2 10.3582V17.7682C2 20.0882 3.89 21.9882 6.21 21.9882H17.79C20.11 21.9882 22 20.0882 22 17.7782V10.4982C22 9.28821 21.19 7.73821 20.2 7.04821L14.02 2.71821C12.62 1.73821 10.37 1.78821 9.02 2.83821Z" fill="#0164FF"/>
|
||||
<path d="M12 17.9922V14.9922" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_719_496">
|
||||
<rect width="24" height="24" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 633 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.9987 14.6693C11.6654 14.6693 14.6654 11.6693 14.6654 8.0026C14.6654 4.33594 11.6654 1.33594 7.9987 1.33594C4.33203 1.33594 1.33203 4.33594 1.33203 8.0026C1.33203 11.6693 4.33203 14.6693 7.9987 14.6693Z" stroke="#289744" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.16797 8.00385L7.05464 9.89052L10.8346 6.11719" stroke="#289744" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 509 B |
@@ -1,6 +1,9 @@
|
||||
class AssetsManager {
|
||||
AssetsManager._();
|
||||
|
||||
//bottom navigation
|
||||
static const homeActive = 'assets/icons/home_active.svg';
|
||||
|
||||
// login page
|
||||
static const logo = 'assets/pngs/logo.png';
|
||||
static const userIcon = 'assets/svgs/user_icon.svg';
|
||||
@@ -17,4 +20,7 @@ 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';
|
||||
|
||||
//your tenders page
|
||||
static const tickCircle = 'assets/icons/tick-circle.svg';
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ class AppColors {
|
||||
static const Color accentColor = Color(0xFFE83E8C);
|
||||
|
||||
// Backgrounds
|
||||
static const Color lightBackgroundColor = Color(0xFFF8F9FA);
|
||||
static const Color darkBackgroundColor = Color(0xFF343A40);
|
||||
static const Color lightBackgroundColor = Color(0xFFFFFFFF);
|
||||
static const Color darkBackgroundColor = Color(0xFF222222);
|
||||
|
||||
// Text Colors
|
||||
static const Color primaryTextColor = Color(0xFF212529);
|
||||
@@ -22,6 +22,8 @@ class AppColors {
|
||||
static const Color warningColor = Color(0xFFFFC107);
|
||||
|
||||
static const Color grey = Color(0xFF555555);
|
||||
static const Color grey20 = Color(0xFFE4E4E4);
|
||||
static const Color grey40 = Color(0xFFDADADA);
|
||||
static const Color grey50 = Color(0xFF9E9E9E);
|
||||
static const Color grey60 = Color(0xFF777777);
|
||||
static const Color grey70 = Color(0xFF444444);
|
||||
@@ -31,4 +33,13 @@ class AppColors {
|
||||
static const Color backgroundColor = Color(0xFFFFFFFF);
|
||||
static const Color borderColor = Color(0xFFE1E1E1);
|
||||
static const Color primary2 = Color(0xFFE5EFFF);
|
||||
static const Color dividerColor = Color(0xFFE1E1E1);
|
||||
|
||||
static const Color gren0 = Color(0xFFF9FCF8);
|
||||
static const Color green10 = Color(0xFFE0F0DC);
|
||||
static const Color gren20 = Color(0xFFDAF8D6);
|
||||
static const Color gren30 = Color(0xFF289744);
|
||||
|
||||
static const Color red0 = Color(0xFFF8D6D6);
|
||||
static const Color red10 = Color(0xFFC02525);
|
||||
}
|
||||
|
||||
@@ -35,4 +35,10 @@ class AppStrings {
|
||||
|
||||
//Tenders
|
||||
static const String tendersTitle = 'Tenders';
|
||||
|
||||
//profile
|
||||
static const String profile = 'Profile';
|
||||
|
||||
//your tenders
|
||||
static const String yourTendersTitle = 'Your tenders';
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ 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';
|
||||
import 'app_shell_screen.dart';
|
||||
|
||||
part 'app_routes.g.dart';
|
||||
@@ -20,7 +21,7 @@ final GlobalKey<NavigatorState> profileNavigatorKey =
|
||||
// Main app router
|
||||
final GoRouter appRouter = GoRouter(
|
||||
routes: $appRoutes,
|
||||
initialLocation: '/login',
|
||||
initialLocation: '/home',
|
||||
navigatorKey: rootNavigatorKey,
|
||||
);
|
||||
|
||||
@@ -134,3 +135,13 @@ class ProfileRouteData extends GoRouteData with _$ProfileRouteData {
|
||||
return const ProfileScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@TypedGoRoute<YourTendersRouteData>(path: '/your-tenders')
|
||||
class YourTendersRouteData extends GoRouteData with _$YourTendersRouteData {
|
||||
const YourTendersRouteData();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
return const YourTendersScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ part of 'app_routes.dart';
|
||||
// GoRouterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
List<RouteBase> get $appRoutes => [$loginScreenRoute, $appShellRouteData];
|
||||
List<RouteBase> get $appRoutes => [
|
||||
$loginScreenRoute,
|
||||
$appShellRouteData,
|
||||
$yourTendersRouteData,
|
||||
];
|
||||
|
||||
RouteBase get $loginScreenRoute =>
|
||||
GoRouteData.$route(path: '/login', factory: _$LoginScreenRoute._fromState);
|
||||
@@ -134,3 +138,30 @@ mixin _$ProfileRouteData on GoRouteData {
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
RouteBase get $yourTendersRouteData => GoRouteData.$route(
|
||||
path: '/your-tenders',
|
||||
|
||||
factory: _$YourTendersRouteData._fromState,
|
||||
);
|
||||
|
||||
mixin _$YourTendersRouteData on GoRouteData {
|
||||
static YourTendersRouteData _fromState(GoRouterState state) =>
|
||||
const YourTendersRouteData();
|
||||
|
||||
@override
|
||||
String get location => GoRouteData.$location('/your-tenders');
|
||||
|
||||
@override
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@override
|
||||
Future<T?> push<T>(BuildContext context) => context.push<T>(location);
|
||||
|
||||
@override
|
||||
void pushReplacement(BuildContext context) =>
|
||||
context.pushReplacement(location);
|
||||
|
||||
@override
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../constants/assets.dart';
|
||||
import '../utils/size_config.dart';
|
||||
|
||||
class AppShellScreen extends StatelessWidget {
|
||||
@@ -19,6 +20,7 @@ class AppShellScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SizeConfig.init(context);
|
||||
return Scaffold(
|
||||
body: navigationShell,
|
||||
bottomNavigationBar: Container(
|
||||
@@ -38,7 +40,7 @@ class AppShellScreen extends StatelessWidget {
|
||||
isActive: navigationShell.currentIndex == 0,
|
||||
onTap: () => _gotoBranch(0),
|
||||
iconPath: 'assets/icons/home.svg',
|
||||
activeIconPath: 'assets/icons/homeActive.svg',
|
||||
activeIconPath: AssetsManager.homeActive,
|
||||
),
|
||||
_bottomNavigationItem(
|
||||
context: context,
|
||||
@@ -81,6 +83,7 @@ class AppShellScreen extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SvgPicture.asset(isActive ? activeIconPath : iconPath),
|
||||
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:tm_app/core/config/dependencies.dart';
|
||||
|
||||
import 'core/routes/app_routes.dart';
|
||||
import 'core/utils/logger.dart';
|
||||
import 'core/utils/size_config.dart';
|
||||
|
||||
void main() {
|
||||
// Initialize the logger
|
||||
@@ -23,7 +22,6 @@ class MyApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SizeConfig.init(context);
|
||||
return MaterialApp.router(
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tm_app/core/routes/app_routes.dart';
|
||||
|
||||
import '../../../core/constants/strings.dart';
|
||||
import '../../core/constants/colors.dart';
|
||||
@@ -10,6 +11,7 @@ class HomeScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SizeConfig.init(context);
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
@@ -36,7 +38,7 @@ class HomeScreen extends StatelessWidget {
|
||||
// SizedBox(height: 32.0.h()),
|
||||
_progressBarsRow(),
|
||||
SizedBox(height: 32.0.h()),
|
||||
_firstStatisticsRow(),
|
||||
_firstStatisticsRow(context),
|
||||
SizedBox(height: 8.0.h()),
|
||||
_secondStatisticsRow(),
|
||||
SizedBox(height: 32.0.h()),
|
||||
@@ -104,7 +106,7 @@ class HomeScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _firstStatisticsRow() {
|
||||
Widget _firstStatisticsRow(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@@ -124,7 +126,9 @@ class HomeScreen extends StatelessWidget {
|
||||
amount: '03',
|
||||
textColor: Color(0xFF24848E),
|
||||
enableTap: true,
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
YourTendersRouteData().push(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tm_app/core/constants/strings.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
|
||||
import '../../core/constants/colors.dart';
|
||||
|
||||
@@ -7,17 +9,118 @@ class ProfileScreen extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.backgroundColor,
|
||||
appBar: AppBar(
|
||||
title: const Text('Profile'),
|
||||
backgroundColor: AppColors.grey10,
|
||||
elevation: 0,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: Size.fromHeight(56.0.h()),
|
||||
child: Container(
|
||||
color: AppColors.backgroundColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
||||
height: 56.0.h(),
|
||||
width: double.infinity,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppStrings.profile,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF222222),
|
||||
),
|
||||
),
|
||||
Image.asset(
|
||||
'assets/icons/tenderLogo.png',
|
||||
width: 59.0.w(),
|
||||
height: 28.0.h(),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 24.0.w(),
|
||||
vertical: 16.0.h(),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 36.0.h()),
|
||||
TitleDescription(
|
||||
title: 'Company Name',
|
||||
description: 'Telecom Solutions GmbH',
|
||||
),
|
||||
TitleDescription(
|
||||
title: 'National ID',
|
||||
description: '12345678901',
|
||||
),
|
||||
TitleDescription(
|
||||
title: 'Registration No.',
|
||||
description: 'DE-55667788',
|
||||
),
|
||||
TitleDescription(
|
||||
title: 'Business Type',
|
||||
description: 'Telecommunications',
|
||||
),
|
||||
TitleDescription(title: 'Founded', description: '2010'),
|
||||
],
|
||||
),
|
||||
body: const Center(
|
||||
child: Text(
|
||||
'Profile Screen',
|
||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TitleDescription extends StatelessWidget {
|
||||
const TitleDescription({
|
||||
required this.title,
|
||||
required this.description,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String description;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 24.0.h()),
|
||||
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
height: 43.0.h(),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.grey60,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.grey80,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 1.0.h(),
|
||||
color: AppColors.dividerColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:tm_app/core/constants/assets.dart';
|
||||
|
||||
import '../../core/utils/size_config.dart';
|
||||
|
||||
@@ -33,7 +34,7 @@ class _TenderBottomNavigationState extends State<TenderBottomNavigation> {
|
||||
});
|
||||
},
|
||||
iconPath: 'assets/icons/home.svg',
|
||||
activeIconPath: 'assets/icons/homeActive.svg',
|
||||
activeIconPath: AssetsManager.homeActive,
|
||||
),
|
||||
_bottomNavigationItem(
|
||||
text: 'Tenders',
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/constants/colors.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
import 'tab_item.dart';
|
||||
import '../../core/constants/colors.dart';
|
||||
import '../../core/utils/size_config.dart';
|
||||
|
||||
class MainTabBar extends StatefulWidget {
|
||||
const MainTabBar({super.key, required this.controller});
|
||||
const MainTabBar({required this.controller, required this.titles, super.key});
|
||||
|
||||
final TabController controller;
|
||||
final List<String> titles;
|
||||
|
||||
@override
|
||||
State<MainTabBar> createState() => _MainTabBarState();
|
||||
@@ -41,22 +41,14 @@ class _MainTabBarState extends State<MainTabBar> {
|
||||
],
|
||||
),
|
||||
controller: widget.controller,
|
||||
tabs: [
|
||||
TabItem(
|
||||
title: 'New',
|
||||
isActive: widget.controller.index == 0,
|
||||
onTap: () {
|
||||
widget.controller.animateTo(0);
|
||||
},
|
||||
labelColor: AppColors.mainBlue,
|
||||
unselectedLabelColor: AppColors.grey60,
|
||||
labelStyle: TextStyle(fontSize: 16.0.sp(), fontWeight: FontWeight.w600),
|
||||
unselectedLabelStyle: TextStyle(
|
||||
fontSize: 16.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
TabItem(
|
||||
title: 'Last',
|
||||
isActive: widget.controller.index == 1,
|
||||
onTap: () {
|
||||
widget.controller.animateTo(1);
|
||||
},
|
||||
),
|
||||
],
|
||||
tabs: [Tab(text: widget.titles[0]), Tab(text: widget.titles[1])],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/constants/colors.dart';
|
||||
import '../../../core/utils/size_config.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,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String title;
|
||||
@@ -1,4 +1,4 @@
|
||||
export 'last_tenders_tab.dart';
|
||||
export 'main_tab_bar.dart';
|
||||
export '../../shared/main_tab_bar.dart';
|
||||
export 'tender_app_bar.dart';
|
||||
export 'tender_card.dart';
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TenderModel {
|
||||
final String date;
|
||||
final String title;
|
||||
final String description;
|
||||
final String location;
|
||||
final String countryFlag;
|
||||
final String status;
|
||||
final String projectStatus;
|
||||
final Color? backgroundColor;
|
||||
final Color? borderColor;
|
||||
final String? statusIcon;
|
||||
final Color? statusCardColor;
|
||||
|
||||
TenderModel({
|
||||
required this.date,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.location,
|
||||
required this.countryFlag,
|
||||
required this.status,
|
||||
required this.projectStatus,
|
||||
this.backgroundColor,
|
||||
this.borderColor,
|
||||
this.statusIcon,
|
||||
this.statusCardColor,
|
||||
});
|
||||
}
|
||||
|
||||
List<TenderModel> approvedTenders = [
|
||||
TenderModel(
|
||||
date: '2025-01-01',
|
||||
title:
|
||||
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. ',
|
||||
location: 'Stockholm, Sweden',
|
||||
countryFlag: 'assets/icons/SE.png',
|
||||
status: 'Completed',
|
||||
projectStatus: 'Self Control',
|
||||
),
|
||||
TenderModel(
|
||||
date: '2025-01-01',
|
||||
title:
|
||||
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. ',
|
||||
location: 'Stockholm, Sweden',
|
||||
countryFlag: 'assets/icons/SE.png',
|
||||
status: 'Completed',
|
||||
projectStatus: 'Patner Ship',
|
||||
),
|
||||
TenderModel(
|
||||
date: '2025-01-01',
|
||||
title:
|
||||
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. ',
|
||||
location: 'Stockholm, Sweden',
|
||||
countryFlag: 'assets/icons/SE.png',
|
||||
status: 'Completed',
|
||||
projectStatus: 'Self Control',
|
||||
),
|
||||
];
|
||||
|
||||
List<TenderModel> tendersSubmitted = [
|
||||
TenderModel(
|
||||
date: '2025-01-01',
|
||||
title:
|
||||
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. ',
|
||||
location: 'Stockholm, Sweden',
|
||||
countryFlag: 'assets/icons/SE.png',
|
||||
status: 'Won',
|
||||
projectStatus: 'Self Control',
|
||||
),
|
||||
TenderModel(
|
||||
date: '2025-01-01',
|
||||
title:
|
||||
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. ',
|
||||
location: 'Stockholm, Sweden',
|
||||
countryFlag: 'assets/icons/SE.png',
|
||||
status: 'Reject',
|
||||
projectStatus: 'Patner Ship',
|
||||
),
|
||||
TenderModel(
|
||||
date: '2025-01-01',
|
||||
title:
|
||||
'Lorem ipsum dolor sit amet consectetur. Sed mi tortor eu purus senectus.',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet consectetur. Volutpat velit tincidunt amet diam. Placerat congue ut Sed facilisis faucibus porttitor. Proin suspendisse eu euismod sit lorem quis. ',
|
||||
location: 'Stockholm, Sweden',
|
||||
countryFlag: 'assets/icons/SE.png',
|
||||
status: 'Won',
|
||||
projectStatus: 'Self Control',
|
||||
),
|
||||
];
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/views/your_tenders/model/tender_model.dart';
|
||||
import 'package:tm_app/views/your_tenders/widgets/tender_card.dart';
|
||||
|
||||
class ApprovedTenders extends StatelessWidget {
|
||||
const ApprovedTenders({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.only(top: 20.0.h()),
|
||||
itemCount: approvedTenders.length,
|
||||
itemBuilder: (context, index) {
|
||||
final tender = approvedTenders[index];
|
||||
return TenderCard(
|
||||
date: tender.date,
|
||||
title: tender.title,
|
||||
description: tender.description,
|
||||
location: tender.location,
|
||||
countryFlag: tender.countryFlag,
|
||||
status: tender.status,
|
||||
projectStatus: tender.projectStatus,
|
||||
backgroundColor: tender.backgroundColor,
|
||||
borderColor: tender.borderColor,
|
||||
statusIcon: tender.statusIcon,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
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 title;
|
||||
final String description;
|
||||
final String location;
|
||||
final String countryFlag;
|
||||
final String status;
|
||||
final String projectStatus;
|
||||
final Color? backgroundColor;
|
||||
final Color? borderColor;
|
||||
final String? statusIcon;
|
||||
final Color? statusCardColor;
|
||||
final Color? statusTextColor;
|
||||
|
||||
const TenderCard({
|
||||
required this.date,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.location,
|
||||
this.countryFlag = 'assets/icons/SE.png',
|
||||
this.status = 'Completed',
|
||||
this.projectStatus = 'Self Control',
|
||||
this.backgroundColor,
|
||||
this.borderColor,
|
||||
this.statusIcon,
|
||||
this.statusCardColor,
|
||||
this.statusTextColor,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
margin: EdgeInsets.only(
|
||||
left: 24.0.w(),
|
||||
right: 24.0.w(),
|
||||
bottom: 24.0.h(),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor ?? AppColors.grey0,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: borderColor ?? AppColors.borderColor),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16.0.w()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Top section with date and status
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Date
|
||||
Text(
|
||||
date,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey60,
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
// Completed status badge
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 16.0.w(),
|
||||
vertical: 4.0.h(),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: statusCardColor ?? AppColors.gren20,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
if (statusIcon != null)
|
||||
SvgPicture.asset(
|
||||
statusIcon!,
|
||||
width: 16.0.w(),
|
||||
height: 16.0.h(),
|
||||
),
|
||||
SizedBox(width: 4.0.w()),
|
||||
Text(
|
||||
status,
|
||||
style: TextStyle(
|
||||
color: statusTextColor ?? AppColors.gren30,
|
||||
fontSize: 12.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,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8.0.h()),
|
||||
|
||||
// Description
|
||||
Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey70,
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.4,
|
||||
),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
SizedBox(height: 24.0.h()),
|
||||
|
||||
// Bottom section with location and action button
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Location with flag
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
AssetsManager.location,
|
||||
width: 16.0.w(),
|
||||
height: 16.0.h(),
|
||||
),
|
||||
SizedBox(width: 4.0.w()),
|
||||
Text(
|
||||
location,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey80,
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8.0.w()),
|
||||
// Country flag
|
||||
Image.asset(
|
||||
countryFlag,
|
||||
width: 32.0.w(),
|
||||
height: 21.0.h(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Self Control button
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 16.0.w(),
|
||||
vertical: 4.0.h(),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.grey20,
|
||||
borderRadius: BorderRadius.circular(88),
|
||||
border: Border.all(color: AppColors.grey40),
|
||||
),
|
||||
child: Text(
|
||||
projectStatus,
|
||||
style: TextStyle(
|
||||
color: AppColors.grey60,
|
||||
fontSize: 12.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.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/your_tenders/model/tender_model.dart';
|
||||
import 'package:tm_app/views/your_tenders/widgets/tender_card.dart';
|
||||
|
||||
class TendersSubmitted extends StatelessWidget {
|
||||
const TendersSubmitted({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.only(top: 20.0.h()),
|
||||
itemCount: tendersSubmitted.length,
|
||||
itemBuilder: (context, index) {
|
||||
final tender = tendersSubmitted[index];
|
||||
return TenderCard(
|
||||
date: tender.date,
|
||||
title: tender.title,
|
||||
description: tender.description,
|
||||
location: tender.location,
|
||||
countryFlag: tender.countryFlag,
|
||||
status: tender.status,
|
||||
projectStatus: tender.projectStatus,
|
||||
|
||||
backgroundColor:
|
||||
tender.status == 'Won'
|
||||
? AppColors.gren0
|
||||
: AppColors.red0.withValues(alpha: 0.2),
|
||||
borderColor:
|
||||
tender.status == 'Won' ? AppColors.green10 : AppColors.red0,
|
||||
statusIcon:
|
||||
tender.status == 'Won'
|
||||
? AssetsManager.tickCircle
|
||||
: AssetsManager.closeCircle,
|
||||
statusCardColor:
|
||||
tender.status == 'Won' ? AppColors.gren20 : AppColors.red0,
|
||||
statusTextColor:
|
||||
tender.status == 'Won' ? AppColors.gren30 : AppColors.red10,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tm_app/core/constants/colors.dart';
|
||||
import 'package:tm_app/core/constants/strings.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/views/your_tenders/widgets/approved_tenders.dart';
|
||||
import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart';
|
||||
|
||||
import '../shared/main_tab_bar.dart';
|
||||
|
||||
class YourTendersScreen extends StatefulWidget {
|
||||
const YourTendersScreen({super.key});
|
||||
|
||||
@override
|
||||
State<YourTendersScreen> createState() => _YourTendersScreenState();
|
||||
}
|
||||
|
||||
class _YourTendersScreenState extends State<YourTendersScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller = TabController(length: 2, vsync: this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.backgroundColor,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: Size.fromHeight(56.0.h()),
|
||||
child: Container(
|
||||
color: AppColors.backgroundColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
||||
height: 56.0.h(),
|
||||
width: double.infinity,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppStrings.yourTenders,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0.sp(),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF222222),
|
||||
),
|
||||
),
|
||||
Image.asset(
|
||||
'assets/icons/tenderLogo.png',
|
||||
width: 59.0.w(),
|
||||
height: 28.0.h(),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
MainTabBar(
|
||||
controller: controller,
|
||||
titles: ['Approved tenders', 'Tenders submitted'],
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: controller,
|
||||
children: [ApprovedTenders(), TendersSubmitted()],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user