From 21d13ac072c54a9352587d42c8c62c6ddbd1b712 Mon Sep 17 00:00:00 2001 From: amirrezaghabeli Date: Tue, 5 Aug 2025 19:18:47 +0330 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20added=20your=20tenders=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- analysis_options.yaml | 1 - android/app/build.gradle.kts | 2 +- assets/icons/close-circle.svg | 8 +- assets/icons/homeActive.svg | 11 - assets/icons/home_active.svg | 11 + assets/icons/tick-circle.svg | 4 + lib/core/constants/assets.dart | 6 + lib/core/constants/colors.dart | 15 +- lib/core/constants/strings.dart | 6 + lib/core/routes/app_routes.dart | 13 +- lib/core/routes/app_routes.g.dart | 33 ++- lib/core/routes/app_shell_screen.dart | 5 +- lib/main.dart | 2 - lib/views/home/home_screen.dart | 10 +- lib/views/profile/profile_screen.dart | 125 +++++++++++- lib/views/shared/bottom_navigation.dart | 3 +- .../widgets => shared}/main_tab_bar.dart | 32 ++- .../{tenders/widgets => shared}/tab_item.dart | 6 +- lib/views/tenders/widgets/widgets.dart | 2 +- .../your_tenders/model/tender_model.dart | 101 ++++++++++ .../widgets/approved_tenders.dart | 31 +++ .../your_tenders/widgets/tender_card.dart | 190 ++++++++++++++++++ .../widgets/tenders_submitted.dart | 45 +++++ .../your_tenders/your_tenders_screen.dart | 83 ++++++++ 24 files changed, 682 insertions(+), 63 deletions(-) delete mode 100644 assets/icons/homeActive.svg create mode 100644 assets/icons/home_active.svg create mode 100644 assets/icons/tick-circle.svg rename lib/views/{tenders/widgets => shared}/main_tab_bar.dart (66%) rename lib/views/{tenders/widgets => shared}/tab_item.dart (89%) create mode 100644 lib/views/your_tenders/model/tender_model.dart create mode 100644 lib/views/your_tenders/widgets/approved_tenders.dart create mode 100644 lib/views/your_tenders/widgets/tender_card.dart create mode 100644 lib/views/your_tenders/widgets/tenders_submitted.dart create mode 100644 lib/views/your_tenders/your_tenders_screen.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 8bf901b..a4ccf49 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -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 diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 43d516a..e48e8c8 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -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 diff --git a/assets/icons/close-circle.svg b/assets/icons/close-circle.svg index 06ef87a..b4ec105 100644 --- a/assets/icons/close-circle.svg +++ b/assets/icons/close-circle.svg @@ -1,5 +1,5 @@ - - - - + + + + diff --git a/assets/icons/homeActive.svg b/assets/icons/homeActive.svg deleted file mode 100644 index faee82a..0000000 --- a/assets/icons/homeActive.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/assets/icons/home_active.svg b/assets/icons/home_active.svg new file mode 100644 index 0000000..6d27067 --- /dev/null +++ b/assets/icons/home_active.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icons/tick-circle.svg b/assets/icons/tick-circle.svg new file mode 100644 index 0000000..e1a3fba --- /dev/null +++ b/assets/icons/tick-circle.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/core/constants/assets.dart b/lib/core/constants/assets.dart index 100370b..2ee9106 100644 --- a/lib/core/constants/assets.dart +++ b/lib/core/constants/assets.dart @@ -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'; } diff --git a/lib/core/constants/colors.dart b/lib/core/constants/colors.dart index 78d7a52..c20a21a 100644 --- a/lib/core/constants/colors.dart +++ b/lib/core/constants/colors.dart @@ -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); } diff --git a/lib/core/constants/strings.dart b/lib/core/constants/strings.dart index 486ed98..7e4d405 100644 --- a/lib/core/constants/strings.dart +++ b/lib/core/constants/strings.dart @@ -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'; } diff --git a/lib/core/routes/app_routes.dart b/lib/core/routes/app_routes.dart index 0c82310..4dfd093 100644 --- a/lib/core/routes/app_routes.dart +++ b/lib/core/routes/app_routes.dart @@ -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 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(path: '/your-tenders') +class YourTendersRouteData extends GoRouteData with _$YourTendersRouteData { + const YourTendersRouteData(); + + @override + Widget build(BuildContext context, GoRouterState state) { + return const YourTendersScreen(); + } +} diff --git a/lib/core/routes/app_routes.g.dart b/lib/core/routes/app_routes.g.dart index c89110a..d46700d 100644 --- a/lib/core/routes/app_routes.g.dart +++ b/lib/core/routes/app_routes.g.dart @@ -6,7 +6,11 @@ part of 'app_routes.dart'; // GoRouterGenerator // ************************************************************************** -List get $appRoutes => [$loginScreenRoute, $appShellRouteData]; +List 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 push(BuildContext context) => context.push(location); + + @override + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + @override + void replace(BuildContext context) => context.replace(location); +} diff --git a/lib/core/routes/app_shell_screen.dart b/lib/core/routes/app_shell_screen.dart index 1072daa..4fb772f 100644 --- a/lib/core/routes/app_shell_screen.dart +++ b/lib/core/routes/app_shell_screen.dart @@ -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( diff --git a/lib/main.dart b/lib/main.dart index 3d2e886..7cb3e7c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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( diff --git a/lib/views/home/home_screen.dart b/lib/views/home/home_screen.dart index 80238b1..054911c 100644 --- a/lib/views/home/home_screen.dart +++ b/lib/views/home/home_screen.dart @@ -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); + }, ), ], ); diff --git a/lib/views/profile/profile_screen.dart b/lib/views/profile/profile_screen.dart index dddeccc..f623cbe 100644 --- a/lib/views/profile/profile_screen.dart +++ b/lib/views/profile/profile_screen.dart @@ -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( - backgroundColor: AppColors.backgroundColor, - appBar: AppBar( - title: const Text('Profile'), - backgroundColor: AppColors.grey10, - elevation: 0, - ), - body: const Center( - child: Text( - 'Profile Screen', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + 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.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'), + ], + ), + ), + ), + ); + } +} + +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, + ), + ], ), ), ); diff --git a/lib/views/shared/bottom_navigation.dart b/lib/views/shared/bottom_navigation.dart index d87568b..4a3f178 100644 --- a/lib/views/shared/bottom_navigation.dart +++ b/lib/views/shared/bottom_navigation.dart @@ -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 { }); }, iconPath: 'assets/icons/home.svg', - activeIconPath: 'assets/icons/homeActive.svg', + activeIconPath: AssetsManager.homeActive, ), _bottomNavigationItem( text: 'Tenders', diff --git a/lib/views/tenders/widgets/main_tab_bar.dart b/lib/views/shared/main_tab_bar.dart similarity index 66% rename from lib/views/tenders/widgets/main_tab_bar.dart rename to lib/views/shared/main_tab_bar.dart index 6b3d2cc..1ab5a87 100644 --- a/lib/views/tenders/widgets/main_tab_bar.dart +++ b/lib/views/shared/main_tab_bar.dart @@ -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 titles; @override State createState() => _MainTabBarState(); @@ -41,22 +41,14 @@ class _MainTabBarState extends State { ], ), 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); - }, - ), - ], + labelColor: AppColors.mainBlue, + unselectedLabelColor: AppColors.grey60, + labelStyle: TextStyle(fontSize: 16.0.sp(), fontWeight: FontWeight.w600), + unselectedLabelStyle: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + tabs: [Tab(text: widget.titles[0]), Tab(text: widget.titles[1])], ), ); } diff --git a/lib/views/tenders/widgets/tab_item.dart b/lib/views/shared/tab_item.dart similarity index 89% rename from lib/views/tenders/widgets/tab_item.dart rename to lib/views/shared/tab_item.dart index 0fe819c..2604be8 100644 --- a/lib/views/tenders/widgets/tab_item.dart +++ b/lib/views/shared/tab_item.dart @@ -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; diff --git a/lib/views/tenders/widgets/widgets.dart b/lib/views/tenders/widgets/widgets.dart index b0aa9ea..089d107 100644 --- a/lib/views/tenders/widgets/widgets.dart +++ b/lib/views/tenders/widgets/widgets.dart @@ -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'; diff --git a/lib/views/your_tenders/model/tender_model.dart b/lib/views/your_tenders/model/tender_model.dart new file mode 100644 index 0000000..45da451 --- /dev/null +++ b/lib/views/your_tenders/model/tender_model.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 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 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', + ), +]; diff --git a/lib/views/your_tenders/widgets/approved_tenders.dart b/lib/views/your_tenders/widgets/approved_tenders.dart new file mode 100644 index 0000000..2e8b3a1 --- /dev/null +++ b/lib/views/your_tenders/widgets/approved_tenders.dart @@ -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, + ); + }, + ); + } +} diff --git a/lib/views/your_tenders/widgets/tender_card.dart b/lib/views/your_tenders/widgets/tender_card.dart new file mode 100644 index 0000000..4a9cb63 --- /dev/null +++ b/lib/views/your_tenders/widgets/tender_card.dart @@ -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, + ), + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/your_tenders/widgets/tenders_submitted.dart b/lib/views/your_tenders/widgets/tenders_submitted.dart new file mode 100644 index 0000000..48ae07f --- /dev/null +++ b/lib/views/your_tenders/widgets/tenders_submitted.dart @@ -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, + ); + }, + ); + } +} diff --git a/lib/views/your_tenders/your_tenders_screen.dart b/lib/views/your_tenders/your_tenders_screen.dart new file mode 100644 index 0000000..61937d1 --- /dev/null +++ b/lib/views/your_tenders/your_tenders_screen.dart @@ -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 createState() => _YourTendersScreenState(); +} + +class _YourTendersScreenState extends State + 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()], + ), + ), + ], + ), + ), + ); + } +}