diff --git a/lib/core/constants/strings.dart b/lib/core/constants/strings.dart index 7de2758..be50e66 100644 --- a/lib/core/constants/strings.dart +++ b/lib/core/constants/strings.dart @@ -37,6 +37,10 @@ class AppStrings { //Tenders static const String tendersTitle = 'Tenders'; static const String tenderSeeMore = 'See More'; + static const String reject = 'Reject'; + static const String submit = 'Submit'; + static const String dislike = 'Dislike'; + static const String like = 'Like'; //profile static const String profile = 'Profile'; diff --git a/lib/core/routes/app_shell/mobile_shell_page.dart b/lib/core/routes/app_shell/mobile_shell_page.dart index 1ee5181..40f6539 100644 --- a/lib/core/routes/app_shell/mobile_shell_page.dart +++ b/lib/core/routes/app_shell/mobile_shell_page.dart @@ -24,7 +24,7 @@ class MobileShellPage extends StatelessWidget { height: 72.0.h(), decoration: BoxDecoration( color: AppColors.grey10, - border: Border.fromBorderSide(BorderSide(color: AppColors.grey30)), + border: Border(top: BorderSide(color: AppColors.grey30)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, diff --git a/lib/data/services/mock_data/mock_your_tenders_data.dart b/lib/data/services/mock_data/mock_your_tenders_data.dart index 4071345..64d6acd 100644 --- a/lib/data/services/mock_data/mock_your_tenders_data.dart +++ b/lib/data/services/mock_data/mock_your_tenders_data.dart @@ -8,7 +8,7 @@ const String mockYourTendersData = ''' "location": "Sweden", "countryFlag": "assets/icons/SE.png", "status": "Completed", - "projectStatus": "Self Control" + "projectStatus": "Self Apply" }, { "date": "2025-05-21", @@ -26,7 +26,7 @@ const String mockYourTendersData = ''' "location": "Italy", "countryFlag": "assets/icons/SE.png", "status": "Completed", - "projectStatus": "Self Control" + "projectStatus": "Self Apply" } ], "tendersSubmitted": [ @@ -37,7 +37,7 @@ const String mockYourTendersData = ''' "location": "Sweden", "countryFlag": "assets/icons/SE.png", "status": "Won", - "projectStatus": "Self Control" + "projectStatus": "Self Apply" }, { "date": "2025-05-21", @@ -55,7 +55,7 @@ const String mockYourTendersData = ''' "location": "Italy", "countryFlag": "assets/icons/SE.png", "status": "Won", - "projectStatus": "Self Control" + "projectStatus": "Self Apply" } ] } diff --git a/lib/data/services/mock_data/tenders_mock_data.dart b/lib/data/services/mock_data/tenders_mock_data.dart index ad93a34..47f0a08 100644 --- a/lib/data/services/mock_data/tenders_mock_data.dart +++ b/lib/data/services/mock_data/tenders_mock_data.dart @@ -9,7 +9,7 @@ final String tendersMockData = ''' "deadline": "2025-06-15", "location": "Sweden", "type": "Self Apply", - "profile_match": 0.75, + "profile_match": 75, "liked": false, "disliked": false, "rejected": false, @@ -23,7 +23,7 @@ final String tendersMockData = ''' "deadline": "2025-07-20", "location": "Norway", "type": "Invitation", - "profile_match": 0.85, + "profile_match": 85, "liked": false, "disliked": false, "rejected": false, @@ -37,7 +37,7 @@ final String tendersMockData = ''' "deadline": "2025-08-10", "location": "Finland", "type": "Self Apply", - "profile_match": 0.65, + "profile_match": 65, "liked": false, "disliked": false, "rejected": false, @@ -51,7 +51,7 @@ final String tendersMockData = ''' "deadline": "2025-09-05", "location": "Denmark", "type": "Invitation", - "profile_match": 0.90, + "profile_match": 90, "liked": false, "disliked": false, "rejected": false, @@ -65,7 +65,7 @@ final String tendersMockData = ''' "deadline": "2025-10-12", "location": "Iceland", "type": "Self Apply", - "profile_match": 0.70, + "profile_match": 70, "liked": false, "disliked": false, "rejected": false, diff --git a/lib/views/home/pages/m_home_page.dart b/lib/views/home/pages/m_home_page.dart index 37f3878..b740d42 100644 --- a/lib/views/home/pages/m_home_page.dart +++ b/lib/views/home/pages/m_home_page.dart @@ -28,35 +28,7 @@ class MobileHomePage extends StatelessWidget { } if (homeViewModel.errorMessage != null) { - return Center( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.error_outline, - size: 64, - color: Colors.red, - ), - const SizedBox(height: 16), - Text( - homeViewModel.errorMessage!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - color: Colors.grey.shade700, - ), - ), - const SizedBox(height: 24), - ElevatedButton( - onPressed: () => homeViewModel.getHome(), - child: const Text('Try Again'), - ), - ], - ), - ), - ); + return Center(child: Text(homeViewModel.errorMessage!)); } return SingleChildScrollView( diff --git a/lib/views/login/pages/login_desktop_page.dart b/lib/views/login/pages/login_desktop_page.dart index 3b48eb0..7ab4d0a 100644 --- a/lib/views/login/pages/login_desktop_page.dart +++ b/lib/views/login/pages/login_desktop_page.dart @@ -30,8 +30,9 @@ class _LoginDesktopPageState extends State { if (viewModel.loggedInUser != null) { HomeRouteData().go(context); } else if (viewModel.errorMessage != null) { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(viewModel.errorMessage!))); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(viewModel.errorMessage!))); } } diff --git a/lib/views/profile/pages/m_profile_page.dart b/lib/views/profile/pages/m_profile_page.dart index eaf59d1..516ee41 100644 --- a/lib/views/profile/pages/m_profile_page.dart +++ b/lib/views/profile/pages/m_profile_page.dart @@ -12,51 +12,43 @@ class MobileProfilePage extends StatelessWidget { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - appBar: tenderMobileAppBar(title: AppStrings.profile), - 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', + return Scaffold( + backgroundColor: AppColors.backgroundColor, + appBar: tenderMobileAppBar(title: AppStrings.profile), + 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'), + SizedBox(height: 24.0.h()), + // Theme Toggle + Container( + padding: EdgeInsets.symmetric( + horizontal: 16.0.w(), + vertical: 12.0.h(), ), - TitleDescription( - title: 'National ID', - description: '12345678901', + decoration: BoxDecoration( + color: AppColors.surfaceColor, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColors.borderColor), ), - TitleDescription( - title: 'Registration No.', - description: 'DE-55667788', - ), - TitleDescription( - title: 'Business Type', - description: 'Telecommunications', - ), - TitleDescription(title: 'Founded', description: '2010'), - SizedBox(height: 24.0.h()), - // Theme Toggle - Container( - padding: EdgeInsets.symmetric( - horizontal: 16.0.w(), - vertical: 12.0.h(), - ), - decoration: BoxDecoration( - color: AppColors.surfaceColor, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.borderColor), - ), - child: const ThemeToggle(), - ), - ], - ), + child: const ThemeToggle(), + ), + ], ), ), ); diff --git a/lib/views/shared/tender_app_bar.dart b/lib/views/shared/tender_app_bar.dart index 9b03bce..b6adeee 100644 --- a/lib/views/shared/tender_app_bar.dart +++ b/lib/views/shared/tender_app_bar.dart @@ -3,37 +3,6 @@ import 'package:tm_app/core/constants/assets.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; -// PreferredSize tenderMobileAppBar({required String title}) { -// return PreferredSize( -// preferredSize: Size.fromHeight(kToolbarHeight.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( -// title, -// style: TextStyle( -// fontSize: 20, -// fontWeight: FontWeight.bold, -// color: AppColors.grey70, -// ), -// ), -// Image.asset( -// 'assets/icons/tenderLogo.png', -// width: 59.0.w(), -// height: 28.0.h(), -// fit: BoxFit.cover, -// ), -// ], -// ), -// ), -// ); -// } - PreferredSizeWidget tenderMobileAppBar({required String title}) { return PreferredSize( preferredSize: const Size.fromHeight(56), @@ -65,39 +34,3 @@ PreferredSizeWidget tenderMobileAppBar({required String title}) { ), ); } - -// PreferredSize appBar({required String title, required BuildContext context}) { -// return PreferredSize( -// preferredSize: Size.fromHeight(kToolbarHeight.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: [ -// GestureDetector( -// onTap: () { -// Navigator.pop(context); -// }, -// child: SvgPicture.asset( -// AssetsManager.arrowLeft, -// width: 24.0.w(), -// height: 24.0.h(), -// ), -// ), -// SizedBox(width: 2.0.w()), -// Text( -// title, -// style: TextStyle( -// fontSize: 20, -// fontWeight: FontWeight.bold, -// color: AppColors.grey70, -// ), -// ), -// ], -// ), -// ), -// ); -// } diff --git a/lib/views/tenders/pages/m_tenders_page.dart b/lib/views/tenders/pages/m_tenders_page.dart index 5e0d4ed..4f07b79 100644 --- a/lib/views/tenders/pages/m_tenders_page.dart +++ b/lib/views/tenders/pages/m_tenders_page.dart @@ -13,29 +13,27 @@ class MobileTendersPage extends StatelessWidget { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - appBar: tenderMobileAppBar(title: AppStrings.tendersTitle), - body: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return Center( - child: CircularProgressIndicator(color: AppColors.jellyBean), - ); - } - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - - return Padding( - padding: EdgeInsets.symmetric(vertical: 24.0.h()), - child: MainTendersSlider( - tenders: viewModel.tendersResponse?.tenders ?? [], - ), + return Scaffold( + backgroundColor: AppColors.backgroundColor, + appBar: tenderMobileAppBar(title: AppStrings.tendersTitle), + body: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return Center( + child: CircularProgressIndicator(color: AppColors.jellyBean), ); - }, - ), + } + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + + return Padding( + padding: EdgeInsets.symmetric(vertical: 24.0.h()), + child: MainTendersSlider( + tenders: viewModel.tendersResponse?.tenders ?? [], + ), + ); + }, ), ); } diff --git a/lib/views/tenders/widgets/main_tenders_slider.dart b/lib/views/tenders/widgets/main_tenders_slider.dart index 24228b1..76c540e 100644 --- a/lib/views/tenders/widgets/main_tenders_slider.dart +++ b/lib/views/tenders/widgets/main_tenders_slider.dart @@ -59,84 +59,93 @@ class _MainTendersSliderState extends State { @override Widget build(BuildContext context) { - return Stack( - children: [ - SizedBox( - width: double.infinity, - height: 717.0.h(), - child: PageView.builder( - controller: pageController, - scrollDirection: Axis.horizontal, - itemCount: widget.tenders.length, - onPageChanged: (index) { - setState(() { - currentPage = index + 1; - }); - }, - itemBuilder: (context, index) { - final tender = widget.tenders[index]; - return TenderCard(tender: tender, isDesktop: widget.isDesktop); - }, - ), + return SingleChildScrollView( + child: Stack(children: [_tendersPageView(), _nextPreviousArrows()]), + ); + } + + Widget _tendersPageView() { + return SizedBox( + width: double.infinity, + height: 719.0.h(), + child: PageView.builder( + controller: pageController, + scrollDirection: Axis.horizontal, + itemCount: widget.tenders.length, + onPageChanged: (index) { + setState(() { + currentPage = index + 1; + }); + }, + itemBuilder: (context, index) { + final tender = widget.tenders[index]; + return TenderCard(tender: tender, isDesktop: widget.isDesktop); + }, + ), + ); + } + + Widget _nextPreviousArrows() { + return Positioned( + top: 607.0.h(), + bottom: 52.0.h(), + left: 9.0.w(), + right: 9.0.w(), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [_leftArrowButton(), _pageNumberText(), _rightArrowButton()], + ), + ); + } + + Widget _leftArrowButton() { + return InkWell( + borderRadius: BorderRadius.circular(100), + onTap: _goToPreviousPage, + child: Container( + width: 32.0.w(), + height: 32.0.w(), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: AppColors.iconColor, width: 1.5), ), - Positioned( - top: 607.0.h(), - bottom: 52.0.h(), - left: 9.0.w(), - right: 9.0.w(), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: _goToPreviousPage, - child: Container( - width: 32.0.w(), - height: 32.0.w(), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: AppColors.iconColor, width: 1.5), - ), - alignment: Alignment.center, - child: SvgPicture.asset( - AssetsManager.arrowLeftSmall, - colorFilter: ColorFilter.mode( - AppColors.iconColor, - BlendMode.srcATop, - ), - ), - ), - ), - Text( - '$currentPage/${widget.tenders.length}', - style: TextStyle( - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - color: AppColors.grey, - ), - ), - GestureDetector( - onTap: _goToNextPage, - child: Container( - width: 32.0.w(), - height: 32.0.w(), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: AppColors.iconColor, width: 1.5), - ), - alignment: Alignment.center, - child: SvgPicture.asset( - AssetsManager.arrowRightSmall, - colorFilter: ColorFilter.mode( - AppColors.iconColor, - BlendMode.srcATop, - ), - ), - ), - ), - ], - ), + alignment: Alignment.center, + child: SvgPicture.asset( + AssetsManager.arrowLeftSmall, + colorFilter: ColorFilter.mode(AppColors.iconColor, BlendMode.srcATop), ), - ], + ), + ); + } + + Widget _pageNumberText() { + return Text( + '$currentPage/${widget.tenders.length}', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.grey, + ), + ); + } + + Widget _rightArrowButton() { + return InkWell( + borderRadius: BorderRadius.circular(100), + onTap: _goToNextPage, + child: Container( + width: 32.0.w(), + height: 32.0.w(), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: AppColors.iconColor, width: 1.5), + ), + alignment: Alignment.center, + child: SvgPicture.asset( + AssetsManager.arrowRightSmall, + colorFilter: ColorFilter.mode(AppColors.iconColor, BlendMode.srcATop), + ), + ), ); } } diff --git a/lib/views/tenders/widgets/tender_action_buttons.dart b/lib/views/tenders/widgets/tender_action_buttons.dart deleted file mode 100644 index 7e48fe1..0000000 --- a/lib/views/tenders/widgets/tender_action_buttons.dart +++ /dev/null @@ -1,214 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:provider/provider.dart'; -import 'package:tm_app/data/services/model/home/tender/tender_model.dart'; -import 'package:tm_app/view_models/tenders_view_model.dart'; - -import '../../../core/constants/assets.dart'; -import '../../../core/theme/colors.dart'; -import '../../../core/utils/size_config.dart'; - -class TenderActionButtons extends StatelessWidget { - final TenderModel tender; - final bool isDesktop; - - const TenderActionButtons({ - required this.tender, - this.isDesktop = false, - super.key, - }); - - @override - Widget build(BuildContext context) { - final viewModel = context.watch(); - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(width: 16.0.w()), - - // Dislike button - Tooltip( - message: 'Dislike', - child: InkWell( - splashColor: Colors.transparent, - onTap: () { - viewModel.toggleDislike(tender); - }, - child: Column( - children: [ - SvgPicture.asset( - width: 32.0.w(), - height: 32.0.w(), - fit: BoxFit.cover, - AssetsManager.dislike, - colorFilter: ColorFilter.mode( - tender.disliked ?? false - ? AppColors.errorColor - : AppColors.grey50, - BlendMode.srcATop, - ), - ), - SizedBox(height: 8.0.h()), - if (!isDesktop) - Text( - 'Dislike', - style: TextStyle( - fontSize: 12.0.sp(), - fontWeight: FontWeight.w400, - color: - tender.disliked ?? false - ? AppColors.errorColor - : AppColors.grey50, - ), - ), - ], - ), - ), - ), - SizedBox(width: 32.0.w()), - //reject button - Tooltip( - message: 'Reject', - child: InkWell( - splashColor: Colors.transparent, - onTap: () { - viewModel.toggleReject(tender); - }, - child: Column( - children: [ - Container( - width: 32.0.w(), - height: 32.0.w(), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: - tender.rejected ?? false - ? AppColors.errorColor - : AppColors.grey60, - width: 1.5.w(), - ), - ), - alignment: Alignment.center, - child: Icon( - Icons.close, - color: - tender.rejected ?? false - ? AppColors.errorColor - : AppColors.grey60, - size: 16, - ), - ), - SizedBox(height: 8.0.h()), - if (!isDesktop) - Text( - 'Reject', - style: TextStyle( - fontSize: 12.0.sp(), - fontWeight: FontWeight.w400, - color: - tender.rejected ?? false - ? AppColors.errorColor - : AppColors.grey60, - ), - ), - ], - ), - ), - ), - SizedBox(width: 32.0.w()), - //submit button - Tooltip( - message: 'Submit', - child: InkWell( - splashColor: Colors.transparent, - onTap: () { - viewModel.toggleSubmit(tender); - }, - child: Column( - children: [ - Container( - width: 32.0.w(), - height: 32.0.w(), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: - tender.submitted ?? false - ? AppColors.successColor - : AppColors.grey60, - width: 1.5.w(), - ), - ), - alignment: Alignment.center, - child: SvgPicture.asset( - AssetsManager.tick, - colorFilter: ColorFilter.mode( - tender.submitted ?? false - ? AppColors.successColor - : AppColors.grey60, - BlendMode.srcATop, - ), - ), - ), - SizedBox(height: 8.0.h()), - if (!isDesktop) - Text( - 'Submit', - style: TextStyle( - fontSize: 12.0.sp(), - fontWeight: FontWeight.w400, - color: - tender.submitted ?? false - ? AppColors.successColor - : AppColors.grey60, - ), - ), - ], - ), - ), - ), - SizedBox(width: 32.0.w()), - // Like button - Tooltip( - message: 'Like', - child: InkWell( - splashColor: Colors.transparent, - onTap: () { - viewModel.toggleLike(tender); - }, - child: Column( - children: [ - SvgPicture.asset( - width: 32.0.w(), - height: 32.0.w(), - fit: BoxFit.cover, - AssetsManager.like, - colorFilter: ColorFilter.mode( - tender.liked ?? false - ? AppColors.successColor - : AppColors.grey50, - BlendMode.srcATop, - ), - ), - SizedBox(height: 8.0.h()), - if (!isDesktop) - Text( - 'Like', - style: TextStyle( - fontSize: 12.0.sp(), - fontWeight: FontWeight.w400, - color: - tender.liked ?? false - ? AppColors.successColor - : AppColors.grey50, - ), - ), - ], - ), - ), - ), - ], - ); - } -} diff --git a/lib/views/tenders/widgets/tender_action_buttons_row.dart b/lib/views/tenders/widgets/tender_action_buttons_row.dart new file mode 100644 index 0000000..5f569ae --- /dev/null +++ b/lib/views/tenders/widgets/tender_action_buttons_row.dart @@ -0,0 +1,231 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:provider/provider.dart'; +import 'package:tm_app/core/constants/strings.dart'; +import 'package:tm_app/data/services/model/home/tender/tender_model.dart'; +import 'package:tm_app/view_models/tenders_view_model.dart'; + +import '../../../core/constants/assets.dart'; +import '../../../core/theme/colors.dart'; +import '../../../core/utils/size_config.dart'; + +class TenderActionButtonsRow extends StatelessWidget { + final TenderModel tender; + final bool isDesktop; + + const TenderActionButtonsRow({ + required this.tender, + this.isDesktop = false, + super.key, + }); + + @override + Widget build(BuildContext context) { + final viewModel = context.watch(); + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(width: 16.0.w()), + + // Dislike button + _dislikeButton(viewModel), + SizedBox(width: 32.0.w()), + //reject button + _rejectButton(viewModel), + SizedBox(width: 32.0.w()), + //submit button + _submitButton(viewModel), + SizedBox(width: 32.0.w()), + // Like button + _likeButton(viewModel), + ], + ); + } + + Widget _rejectButton(TendersViewModel viewModel) { + return Tooltip( + message: AppStrings.reject, + child: InkWell( + splashColor: Colors.transparent, + onTap: () { + viewModel.toggleReject(tender); + }, + child: Column( + children: [ + Container( + width: 32.0.w(), + height: 32.0.w(), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: + tender.rejected ?? false + ? AppColors.errorColor + : AppColors.grey60, + width: 1.5.w(), + ), + ), + alignment: Alignment.center, + child: Icon( + Icons.close, + color: + tender.rejected ?? false + ? AppColors.errorColor + : AppColors.grey60, + size: 16, + ), + ), + SizedBox(height: 8.0.h()), + if (!isDesktop) + Text( + AppStrings.reject, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: + tender.rejected ?? false + ? AppColors.errorColor + : AppColors.grey60, + ), + ), + ], + ), + ), + ); + } + + Widget _submitButton(TendersViewModel viewModel) { + return Tooltip( + message: AppStrings.submit, + child: InkWell( + splashColor: Colors.transparent, + onTap: () { + viewModel.toggleSubmit(tender); + }, + child: Column( + children: [ + Container( + width: 32.0.w(), + height: 32.0.w(), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: + tender.submitted ?? false + ? AppColors.successColor + : AppColors.grey60, + width: 1.5.w(), + ), + ), + alignment: Alignment.center, + child: SvgPicture.asset( + AssetsManager.tick, + colorFilter: ColorFilter.mode( + tender.submitted ?? false + ? AppColors.successColor + : AppColors.grey60, + BlendMode.srcATop, + ), + ), + ), + SizedBox(height: 8.0.h()), + if (!isDesktop) + Text( + AppStrings.submit, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: + tender.submitted ?? false + ? AppColors.successColor + : AppColors.grey60, + ), + ), + ], + ), + ), + ); + } + + Widget _dislikeButton(TendersViewModel viewModel) { + return Tooltip( + message: AppStrings.dislike, + child: InkWell( + splashColor: Colors.transparent, + onTap: () { + viewModel.toggleDislike(tender); + }, + child: Column( + children: [ + SvgPicture.asset( + width: 32.0.w(), + height: 32.0.w(), + fit: BoxFit.cover, + AssetsManager.dislike, + colorFilter: ColorFilter.mode( + tender.disliked ?? false + ? AppColors.errorColor + : AppColors.grey50, + BlendMode.srcATop, + ), + ), + SizedBox(height: 8.0.h()), + if (!isDesktop) + Text( + AppStrings.dislike, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: + tender.disliked ?? false + ? AppColors.errorColor + : AppColors.grey50, + ), + ), + ], + ), + ), + ); + } + + Widget _likeButton(TendersViewModel viewModel) { + return Tooltip( + message: AppStrings.like, + child: InkWell( + splashColor: Colors.transparent, + onTap: () { + viewModel.toggleLike(tender); + }, + child: Column( + children: [ + SvgPicture.asset( + width: 32.0.w(), + height: 32.0.w(), + fit: BoxFit.cover, + AssetsManager.like, + colorFilter: ColorFilter.mode( + tender.liked ?? false + ? AppColors.successColor + : AppColors.grey50, + BlendMode.srcATop, + ), + ), + SizedBox(height: 8.0.h()), + if (!isDesktop) + Text( + AppStrings.like, + style: TextStyle( + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + color: + tender.liked ?? false + ? AppColors.successColor + : AppColors.grey50, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/tenders/widgets/tender_app_bar.dart b/lib/views/tenders/widgets/tender_app_bar.dart deleted file mode 100644 index 2d6cfdc..0000000 --- a/lib/views/tenders/widgets/tender_app_bar.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../../core/constants/assets.dart'; -import '../../../core/constants/strings.dart'; -import '../../../core/theme/colors.dart'; -import '../../../core/utils/size_config.dart'; - -class TenderAppBar extends StatelessWidget { - const TenderAppBar({super.key}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 24.0.w()), - child: 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, - ), - ], - ), - ); - } -} diff --git a/lib/views/tenders/widgets/tender_card.dart b/lib/views/tenders/widgets/tender_card.dart index 3c8fe23..f779ad6 100644 --- a/lib/views/tenders/widgets/tender_card.dart +++ b/lib/views/tenders/widgets/tender_card.dart @@ -7,7 +7,7 @@ import 'package:tm_app/data/services/model/home/tender/tender_model.dart'; import '../../../core/constants/assets.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/size_config.dart'; -import 'tender_action_buttons.dart'; +import 'tender_action_buttons_row.dart'; class TenderCard extends StatelessWidget { final TenderModel tender; @@ -19,7 +19,6 @@ class TenderCard extends StatelessWidget { return Column( children: [ Container( - // width: 364.0.w(), width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 16.0.w()), height: 587.0.h(), @@ -40,16 +39,9 @@ class TenderCard extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - tender.createdTime ?? '', - style: TextStyle( - color: AppColors.grey60, - fontSize: 12.0.sp(), - fontWeight: FontWeight.w400, - ), - ), + _dateText(), if (isDesktop) - TenderActionButtons( + TenderActionButtonsRow( tender: tender, isDesktop: isDesktop, ), @@ -58,70 +50,19 @@ class TenderCard extends StatelessWidget { SizedBox(height: 12.0.h()), // Deadline badge - Container( - width: double.infinity, - height: 24.0.h(), - padding: EdgeInsets.symmetric(horizontal: 8.0.w()), - decoration: BoxDecoration( - color: AppColors.primary20, - borderRadius: BorderRadius.circular(4), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - AppStrings.tenderDeadlineLabel, - style: TextStyle( - color: AppColors.textBlue, - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - ), - ), - Text( - tender.deadline ?? '', - style: TextStyle( - color: AppColors.grey80, - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), + _deadlineBadge(), SizedBox(height: 12.0.h()), // Title - Text( - tender.title ?? '', - style: TextStyle( - color: AppColors.grey80, - fontSize: 16.0.sp(), - fontWeight: FontWeight.w600, - ), - ), + _tenderTitle(), SizedBox(height: 8.0.h()), // Description - Text( - tender.description ?? '', - style: TextStyle( - color: AppColors.grey70, - fontSize: 16.0.sp(), - fontWeight: FontWeight.w400, - height: 1.5, - ), - ), + _tenderDescription(), SizedBox(height: 12.0.h()), // Tender ID - Text( - tender.tenderId ?? '', - style: TextStyle( - color: AppColors.grey, - fontSize: 14.0.sp(), - fontWeight: FontWeight.w400, - ), - ), + _idText(), ], ), ), @@ -132,101 +73,21 @@ class TenderCard extends StatelessWidget { child: Column( children: [ // Match percentage - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - AppStrings.tenderMatchProfile, - style: TextStyle( - color: AppColors.grey80, - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - ), - ), - Text( - '${tender.profileMatch?.toInt() ?? 0}%', - style: TextStyle( - color: AppColors.secondaryTextColor, - fontSize: 16.0.sp(), - fontWeight: FontWeight.w600, - ), - ), - ], - ), + _matchPercentage(), SizedBox(height: 8.0.h()), // Progress bar - Container( - width: double.infinity, - height: 4.0.h(), - decoration: BoxDecoration( - color: AppColors.grey20, - borderRadius: BorderRadius.circular(2), - ), - child: FractionallySizedBox( - alignment: Alignment.centerLeft, - widthFactor: tender.profileMatch ?? 0 / 100, - child: Container( - decoration: BoxDecoration( - color: AppColors.secondary50, - borderRadius: BorderRadius.circular(2), - ), - ), - ), - ), + _progressBar(), 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( - tender.location ?? '', - style: TextStyle( - color: AppColors.grey80, - 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(), - ), - ], - ), - ), + _locationInfo(), // See More button - GestureDetector( - onTap: () { - TenderDetailRouteData().push(context); - }, - child: Container( - width: 108.0.w(), - height: 40.0.h(), - alignment: Alignment.center, - decoration: BoxDecoration( - color: AppColors.primary20, - borderRadius: BorderRadius.circular(100), - ), - child: Text( - AppStrings.tenderSeeMore, - style: TextStyle( - color: AppColors.mainBlue, - fontSize: 14.0.sp(), - fontWeight: FontWeight.w500, - ), - ), - ), - ), + _seeMoreButton(context), ], ), ], @@ -236,8 +97,178 @@ class TenderCard extends StatelessWidget { ), ), SizedBox(height: 72.0.h()), - if (!isDesktop) TenderActionButtons(tender: tender), + if (!isDesktop) TenderActionButtonsRow(tender: tender), ], ); } + + Widget _dateText() { + return Text( + tender.createdTime ?? '', + style: TextStyle( + color: AppColors.grey60, + fontSize: 12.0.sp(), + fontWeight: FontWeight.w400, + ), + ); + } + + Widget _deadlineBadge() { + return Container( + width: double.infinity, + height: 24.0.h(), + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + AppStrings.tenderDeadlineLabel, + style: TextStyle( + color: AppColors.textBlue, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + Text( + tender.deadline ?? '', + style: TextStyle( + color: AppColors.grey80, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } + + Widget _tenderTitle() { + return Text( + tender.title ?? '', + style: TextStyle( + color: AppColors.grey80, + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + ); + } + + Widget _tenderDescription() { + return Text( + tender.description ?? '', + style: TextStyle( + color: AppColors.grey70, + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + height: 1.5, + ), + ); + } + + Widget _idText() { + return Text( + tender.tenderId ?? '', + style: TextStyle( + color: AppColors.grey, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w400, + ), + ); + } + + Widget _matchPercentage() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + AppStrings.tenderMatchProfile, + style: TextStyle( + color: AppColors.grey80, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + Text( + '${tender.profileMatch ?? 0}%', + style: TextStyle( + color: AppColors.secondaryTextColor, + fontSize: 16.0.sp(), + fontWeight: FontWeight.w600, + ), + ), + ], + ); + } + + Widget _progressBar() { + return Container( + width: double.infinity, + height: 4.0.h(), + decoration: BoxDecoration( + color: AppColors.grey20, + borderRadius: BorderRadius.circular(2), + ), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: (tender.profileMatch ?? 0) / 100, + child: Container( + decoration: BoxDecoration( + color: AppColors.secondary50, + borderRadius: BorderRadius.circular(2), + ), + ), + ), + ); + } + + Widget _locationInfo() { + return Expanded( + child: Row( + children: [ + SvgPicture.asset(AssetsManager.location), + SizedBox(width: 4.0.w()), + Text( + tender.location ?? '', + style: TextStyle( + color: AppColors.grey80, + 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()), + ], + ), + ); + } + + Widget _seeMoreButton(BuildContext context) { + return InkWell( + onTap: () { + TenderDetailRouteData().push(context); + }, + child: Container( + width: 108.0.w(), + height: 40.0.h(), + alignment: Alignment.center, + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + child: Text( + AppStrings.tenderSeeMore, + style: TextStyle( + color: AppColors.mainBlue, + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + ), + ), + ), + ); + } } diff --git a/lib/views/tenders/widgets/widgets.dart b/lib/views/tenders/widgets/widgets.dart index ec13bdb..9ce94bd 100644 --- a/lib/views/tenders/widgets/widgets.dart +++ b/lib/views/tenders/widgets/widgets.dart @@ -1,3 +1,2 @@ export '../../shared/main_tab_bar.dart'; -export 'tender_app_bar.dart'; export 'tender_card.dart'; diff --git a/lib/views/your_tenders/pages/your_tenders_mobile_page.dart b/lib/views/your_tenders/pages/your_tenders_mobile_page.dart index acb218d..82be965 100644 --- a/lib/views/your_tenders/pages/your_tenders_mobile_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_mobile_page.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/constants/strings.dart'; import 'package:tm_app/core/theme/colors.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/view_models/your_tenders_view_model.dart'; import 'package:tm_app/views/shared/main_tab_bar.dart'; -import 'package:tm_app/views/shared/tender_app_bar.dart'; import 'package:tm_app/views/your_tenders/widgets/approved_tenders.dart'; import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart'; -import 'package:tm_app/view_models/your_tenders_view_model.dart'; + +import '../../../core/constants/assets.dart'; class YourTendersMobilePage extends StatefulWidget { const YourTendersMobilePage({super.key}); @@ -37,25 +40,50 @@ class _YourTendersMobilePageState extends State @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - appBar: tenderMobileAppBar(title: AppStrings.yourTenders), - body: Column( - children: [ - MainTabBar( + return Scaffold( + backgroundColor: AppColors.backgroundColor, + appBar: _buildAppBar(context), + body: Column( + children: [ + MainTabBar( + controller: controller, + titles: [AppStrings.approvedTenders, AppStrings.tenderSubmitted], + ), + Expanded( + child: TabBarView( controller: controller, - titles: [AppStrings.approvedTenders, AppStrings.tenderSubmitted], + children: const [ApprovedTenders(), TendersSubmitted()], ), - Expanded( - child: TabBarView( - controller: controller, - children: const [ApprovedTenders(), TendersSubmitted()], - ), - ), - ], - ), + ), + ], ), ); } } + +PreferredSizeWidget _buildAppBar(BuildContext context) { + return PreferredSize( + preferredSize: const Size.fromHeight(60), + child: AppBar( + backgroundColor: AppColors.backgroundColor, + elevation: 0, + titleSpacing: 0, + leading: IconButton( + icon: SvgPicture.asset( + AssetsManager.arrowLeft, + height: 24.0.w(), + width: 24.0.w(), + ), + onPressed: () => Navigator.pop(context), + ), + title: Text( + AppStrings.yourTenders, + style: TextStyle( + color: AppColors.grey70, + fontWeight: FontWeight.w600, + fontSize: 20.0.sp(), + ), + ), + ), + ); +} diff --git a/lib/views/your_tenders/widgets/approved_tenders.dart b/lib/views/your_tenders/widgets/approved_tenders.dart index ab0d7f7..720f49b 100644 --- a/lib/views/your_tenders/widgets/approved_tenders.dart +++ b/lib/views/your_tenders/widgets/approved_tenders.dart @@ -39,13 +39,13 @@ class ApprovedTenders extends StatelessWidget { t.status == 'Won' ? AppColors.gren0 : t.status == 'Completed' - ? AppColors.white + ? AppColors.grey0 : AppColors.red0.withValues(alpha: 0.2), borderColor: t.status == 'Won' ? AppColors.green10 : t.status == 'Completed' - ? AppColors.cyanAqua + ? AppColors.grey30 : AppColors.red0, statusIcon: t.status == 'Won'