diff --git a/assets/icons/logo_big.svg b/assets/icons/logo_big.svg new file mode 100644 index 0000000..eb23ac8 --- /dev/null +++ b/assets/icons/logo_big.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/icons/logo_small.svg b/assets/icons/logo_small.svg new file mode 100644 index 0000000..22b4215 --- /dev/null +++ b/assets/icons/logo_small.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/core/config/app_config.dart b/lib/core/config/app_config.dart index a28bd6e..e740c3d 100644 --- a/lib/core/config/app_config.dart +++ b/lib/core/config/app_config.dart @@ -1,3 +1,5 @@ +import 'package:flutter/foundation.dart'; + class AppConfig { // این فلگ نشان می‌دهد که آیا برنامه در حالت Development است یا خیر. // می‌توانید این مقدار را با استفاده از environment variables در زمان بیلد تغییر دهید. @@ -8,23 +10,24 @@ class AppConfig { // این متد بر اساس محیط فعال، URL مناسب را برمی‌گرداند. static String get apiBaseUrl { - return 'http://10.0.2.2:8081'; - // return 'http:127.0.0.1'; + // return 'http://10.0.2.2:8081'; + // return '192.168.1.103:8081'; // if (isDevelopment) { // // Handle different platforms for local development - // if (kIsWeb) { - // // For web, use localhost - // return 'http://localhost:8081'; - // } else if (Platform.isAndroid) { - // // For Android emulator, use 10.0.2.2 (special IP for host machine) - // return 'http://10.0.2.2:8081'; - // } else if (Platform.isIOS) { - // // For iOS simulator, use localhost - // return 'http://localhost:8081'; - // } else { - // // For other platforms (desktop), use localhost - // return 'http://localhost:8081'; - // } + if (kIsWeb) { + // For web, use localhost + return 'http://localhost:8081'; + } else { + // For Android emulator, use 10.0.2.2 (special IP for host machine) + return 'http://10.0.2.2:8081'; + } + // else if (Platform.isIOS) { + // // For iOS simulator, use localhost + // return 'http://localhost:8081'; + // } else { + // // For other platforms (desktop), use localhost + // return 'http://localhost:8081'; + // } // } else { // // Production URL - replace with your actual production server // return 'https://your-production-server.com'; diff --git a/lib/core/constants/assets.dart b/lib/core/constants/assets.dart index 02e8bcf..1cc24c0 100644 --- a/lib/core/constants/assets.dart +++ b/lib/core/constants/assets.dart @@ -1,6 +1,10 @@ class AssetsManager { AssetsManager._(); + //logo + static const logoSmall = 'assets/icons/logo_small.svg'; + static const logoBig = 'assets/icons/logo_big.svg'; + //bottom navigation static const homeActive = 'assets/icons/home_active.svg'; static const home = 'assets/icons/home.svg'; diff --git a/lib/core/network/network_connectivity.dart b/lib/core/network/network_connectivity.dart index 6dcc9b5..37c39f5 100644 --- a/lib/core/network/network_connectivity.dart +++ b/lib/core/network/network_connectivity.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:flutter/foundation.dart'; + class NetworkConnectivity { static final NetworkConnectivity _instance = NetworkConnectivity._internal(); factory NetworkConnectivity() => _instance; @@ -7,15 +9,19 @@ class NetworkConnectivity { /// Check if device has internet connectivity Future hasInternetConnection() async { - try { - // Try to reach a reliable host to check internet connectivity - final result = await InternetAddress.lookup('google.com'); - return result.isNotEmpty && result[0].rawAddress.isNotEmpty; - } on SocketException catch (_) { - return false; - } on Exception catch (_) { - // If connectivity check fails, assume no connection - return false; + if (kIsWeb) { + return true; + } else { + try { + // Try to reach a reliable host to check internet connectivity + final result = await InternetAddress.lookup('google.com'); + return result.isNotEmpty && result[0].rawAddress.isNotEmpty; + } on SocketException catch (_) { + return false; + } on Exception catch (_) { + // If connectivity check fails, assume no connection + return false; + } } } } diff --git a/lib/core/network/network_manager.dart b/lib/core/network/network_manager.dart index c380497..b557e6b 100644 --- a/lib/core/network/network_manager.dart +++ b/lib/core/network/network_manager.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../config/app_config.dart'; import '../utils/logger.dart'; import '../utils/result.dart'; import 'app_exceptions.dart'; @@ -16,7 +17,7 @@ class NetworkManager { NetworkManager() : mainDio = Dio( BaseOptions( - baseUrl: 'http://10.0.2.2:8081', + baseUrl: AppConfig.apiBaseUrl, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', diff --git a/lib/core/routes/app_shell/desktop_shell_page.dart b/lib/core/routes/app_shell/desktop_shell_page.dart index de0de32..a549edb 100644 --- a/lib/core/routes/app_shell/desktop_shell_page.dart +++ b/lib/core/routes/app_shell/desktop_shell_page.dart @@ -38,7 +38,7 @@ class DesktopShellPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(width: 40), - Image.asset(AssetsManager.logo, width: 59, height: 28), + SvgPicture.asset(AssetsManager.logoSmall), Spacer(), _bottomNavigationItem( context: context, @@ -67,7 +67,7 @@ class DesktopShellPage extends StatelessWidget { activeIconPath: AssetsManager.profileActive, ), Spacer(), - SizedBox(width: 59), + SizedBox(width: 68), ], ), ); @@ -84,7 +84,7 @@ class DesktopShellPage extends StatelessWidget { return InkWell( onTap: onTap, child: SizedBox( - width: 200.0, + width: 100.0, height: 64, child: Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/core/routes/app_shell/tablet_shell_page.dart b/lib/core/routes/app_shell/tablet_shell_page.dart index 7958e7a..e2c9841 100644 --- a/lib/core/routes/app_shell/tablet_shell_page.dart +++ b/lib/core/routes/app_shell/tablet_shell_page.dart @@ -38,11 +38,7 @@ class TabletShellPage extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Image.asset( - AssetsManager.logo, - width: 59.0.w(), - height: 28.0.h(), - ), + SvgPicture.asset(AssetsManager.logoSmall), InkWell( onTap: () => _key.currentState!.openDrawer(), child: SvgPicture.asset(AssetsManager.menu), diff --git a/lib/views/detail/pages/detail_desktop_page.dart b/lib/views/detail/pages/detail_desktop_page.dart index 7a2c7c0..afaeed0 100644 --- a/lib/views/detail/pages/detail_desktop_page.dart +++ b/lib/views/detail/pages/detail_desktop_page.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; -import 'package:tm_app/core/constants/assets.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/tender_detail_view_model.dart'; @@ -10,15 +7,73 @@ import 'package:tm_app/views/detail/widgets/tender_detail_action.dart'; import 'package:tm_app/views/detail/widgets/tender_detail_card.dart'; import 'package:tm_app/views/detail/widgets/tender_detail_header.dart'; -class TenderDetailDesktopPage extends StatelessWidget { +class TenderDetailDesktopPage extends StatefulWidget { final String tenderId; const TenderDetailDesktopPage({required this.tenderId, super.key}); + @override + State createState() => + _TenderDetailDesktopPageState(); +} + +class _TenderDetailDesktopPageState extends State { + late final TenderDetailViewModel viewModel; + @override + void initState() { + viewModel = context.read(); + viewModel.addListener(_viewModelListener); + super.initState(); + } + + void _viewModelListener() { + if (viewModel.status.isNotEmpty && + viewModel.status == 'approved' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('tender approved successfully!'))); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'unapproved' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('tender approve removed sucessfully!')), + ); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'rejected' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('tender rejected sucessfully!'))); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'unrejected' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('tender reject removed sucessfully!')), + ); + } + // if (viewModel.errorMessage != null) { + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // backgroundColor: AppColors.errorColor, + // content: Text(viewModel.errorMessage!), + // ), + // ); + // } + } + + @override + void dispose() { + viewModel.removeListener(_viewModelListener); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: _buildAppBar(context), body: Consumer( builder: (context, tenderViewModel, child) { if (tenderViewModel.isLoading) { @@ -60,31 +115,4 @@ class TenderDetailDesktopPage extends StatelessWidget { ), ); } - - 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.tenderDetailTitle, - style: TextStyle( - color: AppColors.grey70, - fontWeight: FontWeight.w600, - fontSize: 20.0.sp(), - ), - ), - ), - ); - } } diff --git a/lib/views/detail/pages/detail_tablet_page.dart b/lib/views/detail/pages/detail_tablet_page.dart index 0a5f08f..f395be4 100644 --- a/lib/views/detail/pages/detail_tablet_page.dart +++ b/lib/views/detail/pages/detail_tablet_page.dart @@ -10,10 +10,68 @@ import 'package:tm_app/views/detail/widgets/tender_detail_action.dart'; import 'package:tm_app/views/detail/widgets/tender_detail_card.dart'; import 'package:tm_app/views/detail/widgets/tender_detail_header.dart'; -class TenderDetailTabletPage extends StatelessWidget { +class TenderDetailTabletPage extends StatefulWidget { final String tenderId; const TenderDetailTabletPage({required this.tenderId, super.key}); + @override + State createState() => _TenderDetailTabletPageState(); +} + +class _TenderDetailTabletPageState extends State { + late final TenderDetailViewModel viewModel; + @override + void initState() { + viewModel = context.read(); + viewModel.addListener(_viewModelListener); + super.initState(); + } + + void _viewModelListener() { + if (viewModel.status.isNotEmpty && + viewModel.status == 'approved' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('tender approved successfully!'))); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'unapproved' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('tender approve removed sucessfully!')), + ); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'rejected' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('tender rejected sucessfully!'))); + } + if (viewModel.status.isNotEmpty && + viewModel.status == 'unrejected' && + viewModel.approvalStatus == true) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('tender reject removed sucessfully!')), + ); + } + // if (viewModel.errorMessage != null) { + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar( + // backgroundColor: AppColors.errorColor, + // content: Text(viewModel.errorMessage!), + // ), + // ); + // } + } + + @override + void dispose() { + viewModel.removeListener(_viewModelListener); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/views/detail/widgets/tender_detail_action.dart b/lib/views/detail/widgets/tender_detail_action.dart index 67826d5..b10db98 100644 --- a/lib/views/detail/widgets/tender_detail_action.dart +++ b/lib/views/detail/widgets/tender_detail_action.dart @@ -24,23 +24,77 @@ class TenderDetailActions extends StatelessWidget { ? Row( children: [ Spacer(), - BaseButton( - isEnabled: true, - text: AppStrings.tenderRejectButton, - textColor: AppColors.red10, - backgroundColor: AppColors.backgroundColor, - borderWidth: 1, - onPressed: () {}, - width: 120.0.w(), + Consumer( + builder: (context, viewModel, child) { + return viewModel.isRejectApprovalLoading + ? BaseButton( + isEnabled: true, + text: AppStrings.tenderRejectButton, + textColor: AppColors.red10, + backgroundColor: AppColors.backgroundColor, + borderWidth: 1, + onPressed: () {}, + width: 120.0.w(), + ) + : BaseButton( + isEnabled: true, + text: AppStrings.tenderRejectButton, + textColor: AppColors.red10, + backgroundColor: AppColors.backgroundColor, + borderWidth: 1, + onPressed: () { + viewModel.rejectTenderApproval( + tenderId: detail.id!, + submissionMode: 'self-apply', + ); + }, + width: 120.0.w(), + ); + }, ), SizedBox(width: 5.0.w()), - BaseButton( - isEnabled: true, - text: AppStrings.tenderSubmitButton, - backgroundColor: AppColors.lightBlue, - textColor: AppColors.mainBlue, - onPressed: () {}, - width: 120.0.w(), + Consumer( + builder: (context, viewModel, child) { + return viewModel.isSubmitApprovalLoading + ? BaseButton( + isEnabled: true, + text: AppStrings.tenderSubmitButton, + backgroundColor: AppColors.lightBlue, + textColor: AppColors.mainBlue, + onPressed: () {}, + width: 120.0.w(), + ) + : BaseButton( + isEnabled: true, + text: AppStrings.tenderSubmitButton, + backgroundColor: AppColors.lightBlue, + textColor: AppColors.mainBlue, + onPressed: () { + if (viewModel.status == 'approved') { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: 'self-apply', + ); + } else { + showModalBottomSheet( + isDismissible: true, + context: context, + builder: (context) { + return SelectSubmissionBottomSheet( + onConfirm: (value) { + viewModel.submitTenderApproval( + tenderId: detail.id!, + submissionMode: value, + ); + }, + ); + }, + ); + } + }, + width: 120.0.w(), + ); + }, ), ], ) diff --git a/lib/views/home/pages/d_home_page.dart b/lib/views/home/pages/d_home_page.dart index fee7e3c..2f9326d 100644 --- a/lib/views/home/pages/d_home_page.dart +++ b/lib/views/home/pages/d_home_page.dart @@ -6,7 +6,6 @@ import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart'; import 'package:tm_app/view_models/home_view_model.dart'; -import 'package:tm_app/views/home/widgets/notification_card.dart'; import '../widgets.dart'; @@ -33,7 +32,7 @@ class DesktopHomePage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 55), - SizedBox(width: 780, child: NotificationCard()), + // SizedBox(width: 780, child: NotificationCard()), SizedBox(height: 40.0), _progressBarsRow(homeViewModel.tenderApprovalsStateResponse!), SizedBox(height: 32.0.h()), @@ -70,7 +69,7 @@ class DesktopHomePage extends StatelessWidget { ProgressBarColumn( text: AppStrings.partnership, value: double.parse('$partnershipPercent'), - amount: double.parse('$partnershipPercent').toString(), + amount: double.parse('$partnershipPercent').toString(), circularProgressIndicatorWidth: 176, circularProgressIndicatorHeight: 176, ), @@ -78,7 +77,8 @@ class DesktopHomePage extends StatelessWidget { ProgressBarColumn( text: AppStrings.selfApply, value: double.parse(selfApplyPercent.toString()), - amount: double.parse(selfApplyPercent.toString()).toString(), circularProgressIndicatorWidth: 176, + amount: double.parse(selfApplyPercent.toString()).toString(), + circularProgressIndicatorWidth: 176, circularProgressIndicatorHeight: 176, ), SizedBox(width: 106), @@ -104,18 +104,18 @@ class DesktopHomePage extends StatelessWidget { backgroundColor: AppColors.primary20, iconPath: 'assets/icons/arrows.svg', title: AppStrings.tenderSubmitted, - amount: '0', - // tenderApprovalsStateResponse - // .data! - // .approvalsBySubmission! - // .selfApply - // .toString(), + amount: tenderApprovalsStateResponse.data!.approvedTenders.toString(), + // tenderApprovalsStateResponse + // .data! + // .approvalsBySubmission! + // .selfApply + // .toString(), textColor: Color(0xFF0164FF), enableTap: true, width: 178, height: 148, onTap: () { - // YourTendersRouteData().push(context); + YourTendersRouteData().push(context); }, ), SizedBox(width: 10), @@ -123,7 +123,7 @@ class DesktopHomePage extends StatelessWidget { backgroundColor: AppColors.primary10, iconPath: 'assets/icons/thumb.svg', title: AppStrings.approvedTenders, - amount: tenderApprovalsStateResponse.data!.approvedTenders.toString(), + amount: '0', textColor: Color(0xFF24848E), enableTap: true, width: 178, diff --git a/lib/views/home/pages/m_home_page.dart b/lib/views/home/pages/m_home_page.dart index 350b82c..edd12d1 100644 --- a/lib/views/home/pages/m_home_page.dart +++ b/lib/views/home/pages/m_home_page.dart @@ -8,25 +8,13 @@ import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart'; import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart'; import 'package:tm_app/view_models/home_view_model.dart'; -import 'package:tm_app/views/home/widgets/notification_card.dart'; import 'package:tm_app/views/shared/tender_app_bar.dart'; import '../widgets.dart'; -class MobileHomePage extends StatefulWidget { +class MobileHomePage extends StatelessWidget { const MobileHomePage({super.key}); - @override - State createState() => _MobileHomePageState(); -} - -class _MobileHomePageState extends State { - @override - void initState() { - // context.read().init(); - super.initState(); - } - @override Widget build(BuildContext context) { return Scaffold( @@ -49,8 +37,8 @@ class _MobileHomePageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 18.0.h()), - NotificationCard(), + // SizedBox(height: 18.0.h()), + // NotificationCard(), SizedBox(height: 32.0.h()), _progressBarsRow(homeViewModel.tenderApprovalsStateResponse!), SizedBox(height: 32.0.h()), @@ -128,7 +116,8 @@ class _MobileHomePageState extends State { backgroundColor: AppColors.primary20, iconPath: AssetsManager.arrows, title: AppStrings.tenderSubmitted, - amount: '0', + amount: + tenderApprovalsStateResponse.data!.approvedTenders.toString(), // tenderApprovalsStateResponse // .data! // .approvalsBySubmission! @@ -144,8 +133,8 @@ class _MobileHomePageState extends State { backgroundColor: AppColors.primary10, iconPath: AssetsManager.thumb, title: AppStrings.approvedTenders, - amount: - tenderApprovalsStateResponse.data!.approvedTenders.toString(), + amount: '0', + textColor: Color(0xFF24848E), enableTap: true, onTap: () { diff --git a/lib/views/home/pages/t_home_page.dart b/lib/views/home/pages/t_home_page.dart index fd9f3ff..233ebf7 100644 --- a/lib/views/home/pages/t_home_page.dart +++ b/lib/views/home/pages/t_home_page.dart @@ -7,7 +7,6 @@ import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart'; import 'package:tm_app/data/services/model/tender_approvals_state_response/tender_approvals_state_response.dart'; import 'package:tm_app/view_models/home_view_model.dart'; -import 'package:tm_app/views/home/widgets/notification_card.dart'; import '../widgets.dart'; @@ -40,7 +39,7 @@ class TabletHomePage extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - NotificationCard(), + // NotificationCard(), SizedBox(height: 40.0.h()), _progressBarsRow(homeViewModel.tenderApprovalsStateResponse!), SizedBox(height: 32.0.h()), @@ -80,15 +79,16 @@ class TabletHomePage extends StatelessWidget { ProgressBarColumn( text: AppStrings.partnership, value: double.parse('$partnershipPercent'), - amount: double.parse('$partnershipPercent').toString(), + amount: double.parse('$partnershipPercent').toString(), circularProgressIndicatorWidth: 176.0, circularProgressIndicatorHeight: 176.0, strokeWidth: 8.0, ), + Spacer(), ProgressBarColumn( text: AppStrings.selfApply, value: double.parse(selfApplyPercent.toString()), - amount: double.parse(selfApplyPercent.toString()).toString(), + amount: double.parse(selfApplyPercent.toString()).toString(), circularProgressIndicatorWidth: 176.0, circularProgressIndicatorHeight: 176.0, strokeWidth: 8.0, @@ -119,12 +119,13 @@ class TabletHomePage extends StatelessWidget { backgroundColor: AppColors.primary20, iconPath: 'assets/icons/arrows.svg', title: AppStrings.tenderSubmitted, - amount: '0', - // tenderApprovalsStateResponse - // .data! - // .approvalsBySubmission! - // .selfApply - // .toString(), + amount: + tenderApprovalsStateResponse.data!.approvedTenders.toString(), + // tenderApprovalsStateResponse + // .data! + // .approvalsBySubmission! + // .selfApply + // .toString(), textColor: Color(0xFF0164FF), enableTap: true, width: double.infinity, @@ -140,8 +141,7 @@ class TabletHomePage extends StatelessWidget { backgroundColor: AppColors.primary10, iconPath: 'assets/icons/thumb.svg', title: AppStrings.approvedTenders, - amount: - tenderApprovalsStateResponse.data!.approvedTenders.toString(), + amount: '0', textColor: Color(0xFF24848E), enableTap: true, diff --git a/lib/views/login/pages/login_desktop_page.dart b/lib/views/login/pages/login_desktop_page.dart index 7ab4d0a..2a93362 100644 --- a/lib/views/login/pages/login_desktop_page.dart +++ b/lib/views/login/pages/login_desktop_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; @@ -58,8 +59,13 @@ class _LoginDesktopPageState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ - LoginLogo(width: 190.0.w(), height: 88.0.h()), - SizedBox(height: 32.0.h()), + SvgPicture.asset( + AssetsManager.logoBig, + width: 320, + height: 50, + fit: BoxFit.cover, + ), + SizedBox(height: 72.0.h()), const LoginTitle(), SizedBox(height: 32.0.h()), LoginTextField( diff --git a/lib/views/login/pages/login_mobile_page.dart b/lib/views/login/pages/login_mobile_page.dart index 5044cc2..5234bc5 100644 --- a/lib/views/login/pages/login_mobile_page.dart +++ b/lib/views/login/pages/login_mobile_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/core/theme/colors.dart'; @@ -54,7 +55,15 @@ class _LoginMobilePageState extends State { return Column( mainAxisSize: MainAxisSize.min, children: [ - LoginLogo(width: 190.0.w(), height: 88.0.h()), + // LoginLogo(width: 190.0.w(), height: 88.0.h()), + Padding( + padding: EdgeInsets.symmetric(horizontal: 22.0.w()), + child: SvgPicture.asset( + AssetsManager.logoBig, + width: double.infinity, + height: 50.0.h(), + ), + ), SizedBox(height: 32.0.h()), const LoginTitle(), SizedBox(height: 32.0.h()), diff --git a/lib/views/login/widgets/login_title.dart b/lib/views/login/widgets/login_title.dart index 5ee7eca..233c9e2 100644 --- a/lib/views/login/widgets/login_title.dart +++ b/lib/views/login/widgets/login_title.dart @@ -21,7 +21,7 @@ class LoginTitle extends StatelessWidget { style: TextStyle( fontSize: 14.0.sp(), fontWeight: FontWeight.w400, - color: AppColors.grey60, + color: AppColors.grey60, ), textAlign: TextAlign.center, ), diff --git a/lib/views/profile/pages/d_profile_page.dart b/lib/views/profile/pages/d_profile_page.dart index 99f3bcf..956c44f 100644 --- a/lib/views/profile/pages/d_profile_page.dart +++ b/lib/views/profile/pages/d_profile_page.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:tm_app/core/routes/app_routes.dart'; import 'package:tm_app/view_models/profile_view_model.dart'; +import '../../../core/constants/assets.dart'; +import '../../../core/constants/strings.dart'; import '../../../core/theme/colors.dart'; import '../../../core/utils/size_config.dart'; import '../widgets/theme_toggle.dart'; @@ -63,40 +66,94 @@ class _DesktopProfilePageState extends State { return Center( child: SizedBox( width: 740, - height: 507, + height: 662, child: Column( children: [ SizedBox(height: 36.0.h()), TitleDescription( title: 'Company Name', - description: 'Telecom Solutions GmbH', + description: viewModel.companyProfileData!.name!, ), TitleDescription( title: 'National ID', - description: '12345678901', + description: viewModel.companyProfileData!.id!, ), TitleDescription( title: 'Registration No.', - description: 'DE-55667788', + description: + viewModel.companyProfileData!.registrationNumber!, ), + TitleDescription(title: 'Business Type', description: '-'), TitleDescription( - title: 'Business Type', - description: 'Telecommunications', + title: 'Founded', + description: + viewModel.companyProfileData!.foundedYear!.toString(), ), - TitleDescription(title: 'Founded', description: '2010'), SizedBox(height: 24.0.h()), // Theme Toggle - Container( - padding: EdgeInsets.symmetric( - horizontal: 16.0.w(), - vertical: 12.0.h(), + Align( + alignment: AlignmentDirectional.centerStart, + child: Text( + AppStrings.settings, + style: TextStyle( + fontSize: 20.0.sp(), + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), ), - decoration: BoxDecoration( - color: AppColors.surfaceColor, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.borderColor), + ), + SizedBox(height: 36.0.h()), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + child: Row( + children: [ + Text( + AppStrings.appTheme, + style: TextStyle( + fontSize: 16.0.sp(), + fontWeight: FontWeight.w400, + color: AppColors.grey70, + ), + ), + Spacer(), + SvgPicture.asset(AssetsManager.sun), + SizedBox(width: 12.0.w()), + SizedBox( + width: 52.0.w(), + height: 32.0.h(), + child: ThemeToggle(), + ), + SizedBox(width: 12.0.w()), + SvgPicture.asset(AssetsManager.moon), + ], + ), + ), + SizedBox(height: 24.0.h()), + Divider(color: AppColors.dividerColor, thickness: 1), + SizedBox(height: 24.0.h()), + // Spacer(), + Align( + alignment: Alignment.centerRight, + child: InkWell( + onTap: () => viewModel.logout(), + child: Container( + width: 156, + height: 56.0.h(), + decoration: BoxDecoration( + color: AppColors.primary20, + borderRadius: BorderRadius.circular(100), + ), + alignment: Alignment.center, + child: Text( + 'Logout', + style: TextStyle( + fontSize: 14.0.sp(), + fontWeight: FontWeight.w500, + color: AppColors.primaryColor, + ), + ), + ), ), - child: const ThemeToggle(), ), ], ), diff --git a/lib/views/shared/tender_app_bar.dart b/lib/views/shared/tender_app_bar.dart index 8be706b..b332468 100644 --- a/lib/views/shared/tender_app_bar.dart +++ b/lib/views/shared/tender_app_bar.dart @@ -13,12 +13,7 @@ PreferredSizeWidget tenderMobileAppBar({required String title}) { titleSpacing: 0, automaticallyImplyLeading: false, actions: [ - Image.asset( - AssetsManager.tenderLogo, - width: 59.0.w(), - height: 28.0.h(), - fit: BoxFit.cover, - ), + SvgPicture.asset(AssetsManager.logoSmall), SizedBox(width: 24.0.w()), ], title: Padding( diff --git a/lib/views/tenders/pages/d_tenders_page.dart b/lib/views/tenders/pages/d_tenders_page.dart index 1a11c7f..47f0049 100644 --- a/lib/views/tenders/pages/d_tenders_page.dart +++ b/lib/views/tenders/pages/d_tenders_page.dart @@ -5,9 +5,47 @@ import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/view_models/tenders_view_model.dart'; import 'package:tm_app/views/tenders/widgets/main_tenders_slider.dart'; -class DesktopTendersPage extends StatelessWidget { +class DesktopTendersPage extends StatefulWidget { const DesktopTendersPage({super.key}); + @override + State createState() => _DesktopTendersPageState(); +} + +class _DesktopTendersPageState extends State { + late final TendersViewModel viewModel; + @override + void initState() { + super.initState(); + viewModel = context.read(); + viewModel.addListener(_viewModelListener); + } + + void _viewModelListener() { + if (viewModel.feedbackErrorMessage != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppColors.error, + content: Text(viewModel.feedbackErrorMessage!), + ), + ); + } + if (viewModel.tenderApprovalErrorMessage != null) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: AppColors.error, + content: Text(viewModel.tenderApprovalErrorMessage!), + ), + ); + } + } + + @override + void dispose() { + viewModel.removeListener(_viewModelListener); + super.dispose(); + } + @override Widget build(BuildContext context) { return SafeArea( diff --git a/lib/views/tenders/pages/m_tenders_page.dart b/lib/views/tenders/pages/m_tenders_page.dart index d35c8e0..ec761c9 100644 --- a/lib/views/tenders/pages/m_tenders_page.dart +++ b/lib/views/tenders/pages/m_tenders_page.dart @@ -33,13 +33,6 @@ class _MobileTendersPageState extends State { ), ); } - // if (viewModel.errorMessage != null) { - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Text(viewModel.errorMessage!), - // ), - // ); - // } if (viewModel.tenderApprovalErrorMessage != null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( diff --git a/lib/views/your_tenders/pages/your_tenders_desktop_page.dart b/lib/views/your_tenders/pages/your_tenders_desktop_page.dart index a0f8b68..2df8396 100644 --- a/lib/views/your_tenders/pages/your_tenders_desktop_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_desktop_page.dart @@ -4,8 +4,8 @@ import 'package:tm_app/core/constants/strings.dart'; import 'package:tm_app/core/theme/colors.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/tablet_desktop_appbar.dart'; import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart'; class YourTendersDesktopPage extends StatefulWidget { @@ -40,12 +40,15 @@ class _YourTendersDesktopPageState extends State return SafeArea( child: Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: tenderMobileAppBar(title: AppStrings.yourTenders), + body: Center( child: SizedBox( width: 740, child: Column( children: [ + SizedBox(height: 128.0), + TabletDesktopAppbar(), + SizedBox(height: 20.0), MainTabBar( controller: controller, titles: [ @@ -71,13 +74,8 @@ class _YourTendersDesktopPageState extends State return TabBarView( controller: controller, children: [ - ApprovedTenders( - approvedTenders: viewModel.data!, - ), - TendersSubmitted( - tendersSubmitted: - [], - ), + ApprovedTenders(tendersSubmitted: []), + TendersSubmitted(approvedTenders: viewModel.data!), ], ); }, 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 ac3630a..2e91d6a 100644 --- a/lib/views/your_tenders/pages/your_tenders_mobile_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_mobile_page.dart @@ -64,12 +64,8 @@ class _YourTendersMobilePageState extends State return TabBarView( controller: controller, children: [ - ApprovedTenders( - approvedTenders: viewModel.data!, - ), - TendersSubmitted( - tendersSubmitted: [], - ), + ApprovedTenders(tendersSubmitted: []), + TendersSubmitted(approvedTenders: viewModel.data!), ], ); }, diff --git a/lib/views/your_tenders/pages/your_tenders_tablet_page.dart b/lib/views/your_tenders/pages/your_tenders_tablet_page.dart index 6134175..8cb0c52 100644 --- a/lib/views/your_tenders/pages/your_tenders_tablet_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_tablet_page.dart @@ -2,10 +2,11 @@ import 'package:flutter/material.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/tablet_desktop_appbar.dart'; import 'package:tm_app/views/your_tenders/widgets/tenders_submitted.dart'; class YourTendersTabletPage extends StatefulWidget { @@ -40,12 +41,18 @@ class _YourTendersTabletPageState extends State return SafeArea( child: Scaffold( backgroundColor: AppColors.backgroundColor, - appBar: tenderMobileAppBar(title: AppStrings.yourTenders), + body: Center( child: SizedBox( width: 720, child: Column( children: [ + SizedBox(height: 64.0.h()), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0.w()), + child: TabletDesktopAppbar(), + ), + SizedBox(height: 24.0.h()), MainTabBar( controller: controller, titles: [ @@ -71,12 +78,8 @@ class _YourTendersTabletPageState extends State return TabBarView( controller: controller, children: [ - ApprovedTenders( - approvedTenders: viewModel.data!, - ), - TendersSubmitted( - tendersSubmitted: [], - ), + ApprovedTenders(tendersSubmitted: []), + TendersSubmitted(approvedTenders: viewModel.data!), ], ); }, diff --git a/lib/views/your_tenders/widgets/approved_tenders.dart b/lib/views/your_tenders/widgets/approved_tenders.dart index a2e6a2a..f98e1fb 100644 --- a/lib/views/your_tenders/widgets/approved_tenders.dart +++ b/lib/views/your_tenders/widgets/approved_tenders.dart @@ -1,64 +1,63 @@ import 'package:flutter/material.dart'; import 'package:tm_app/core/constants/assets.dart'; import 'package:tm_app/core/theme/colors.dart'; -import 'package:tm_app/data/services/model/tender_approvals_response/tender_approvals_response.dart'; import 'package:tm_app/views/your_tenders/widgets/tender_card.dart'; -class ApprovedTenders extends StatelessWidget { - const ApprovedTenders({required this.approvedTenders, super.key}); +import '../../../data/services/model/your_tender_model/your_tender_model.dart'; - final TenderApprovalsResponse approvedTenders; +class ApprovedTenders extends StatelessWidget { + const ApprovedTenders({required this.tendersSubmitted, super.key}); + + final List tendersSubmitted; @override Widget build(BuildContext context) { - return approvedTenders.data == null - ? const Center(child: Text('No approved projects yet.')) - : ListView.builder( - padding: const EdgeInsets.only(top: 20), - itemCount: approvedTenders.data!.length, - itemBuilder: (context, index) { - final tender = approvedTenders.data![index]; - return TenderCard( - date: tender.createdAt!.toString(), - title: tender.tender!.title!, - description: tender.tender!.description!, - location: tender.tender!.countryCode!, - countryFlag: AssetsManager.seFlag, - status: tender.status, - countryCode: tender.tender!.countryCode!, - projectStatus: tender.tender!.status!, - backgroundColor: - tender.status == 'Won' - ? AppColors.green0 - : tender.status == 'approved' - ? AppColors.grey0 - : AppColors.red0.withValues(alpha: 0.2), - borderColor: - tender.status == 'Won' - ? AppColors.green10 - : tender.status == 'approved' - ? AppColors.grey30 - : AppColors.red0, - statusIcon: - tender.status == 'Won' - ? AssetsManager.tickCircle - : tender.status == 'approved' - ? null - : AssetsManager.closeCircle, - statusCardColor: - tender.status == 'Won' - ? AppColors.green20 - : tender.status == 'approved' - ? AppColors.green20 - : AppColors.red0, - statusTextColor: - tender.status == 'Won' - ? AppColors.green30 - : tender.status == 'approved' - ? AppColors.green30 - : AppColors.red10, - ); - }, + return ListView.builder( + padding: const EdgeInsets.only(top: 20), + 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, + countryCode: '', + projectStatus: tender.projectStatus, + backgroundColor: + tender.status == 'Won' + ? AppColors.green0 + : tender.status == 'Completed' + ? AppColors.grey0 + : AppColors.red0, + borderColor: + tender.status == 'Won' + ? AppColors.green10 + : tender.status == 'Completed' + ? AppColors.grey30 + : AppColors.red10, + statusIcon: + tender.status == 'Won' + ? AssetsManager.tickCircle + : tender.status == 'Completed' + ? null + : AssetsManager.closeCircle, + statusCardColor: + tender.status == 'Won' + ? AppColors.green20 + : tender.status == 'Completed' + ? AppColors.blue0 + : AppColors.red10, + statusTextColor: + tender.status == 'Won' + ? AppColors.green30 + : tender.status == 'Completed' + ? AppColors.cyanTeal + : AppColors.red20, ); + }, + ); } } diff --git a/lib/views/your_tenders/widgets/tablet_desktop_appbar.dart b/lib/views/your_tenders/widgets/tablet_desktop_appbar.dart new file mode 100644 index 0000000..5933efd --- /dev/null +++ b/lib/views/your_tenders/widgets/tablet_desktop_appbar.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; +import 'package:tm_app/core/utils/size_config.dart'; + +import '../../../core/constants/assets.dart'; +import '../../../core/constants/strings.dart'; +import '../../../core/theme/colors.dart'; + +class TabletDesktopAppbar extends StatelessWidget { + const TabletDesktopAppbar({super.key}); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + InkWell( + onTap: () => context.pop(), + child: SvgPicture.asset(AssetsManager.arrowLeft), + ), + SizedBox(width: 8.0.w()), + Text( + AppStrings.yourTendersTitle, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: AppColors.grey70, + ), + ), + ], + ); + } +} diff --git a/lib/views/your_tenders/widgets/tenders_submitted.dart b/lib/views/your_tenders/widgets/tenders_submitted.dart index 725d21c..058935f 100644 --- a/lib/views/your_tenders/widgets/tenders_submitted.dart +++ b/lib/views/your_tenders/widgets/tenders_submitted.dart @@ -1,62 +1,65 @@ import 'package:flutter/material.dart'; import 'package:tm_app/core/constants/assets.dart'; import 'package:tm_app/core/theme/colors.dart'; -import 'package:tm_app/data/services/model/your_tender_model/your_tender_model.dart'; import 'package:tm_app/views/your_tenders/widgets/tender_card.dart'; -class TendersSubmitted extends StatelessWidget { - const TendersSubmitted({required this.tendersSubmitted, super.key}); +import '../../../data/services/model/tender_approvals_response/tender_approvals_response.dart'; - final List tendersSubmitted; +class TendersSubmitted extends StatelessWidget { + const TendersSubmitted({required this.approvedTenders, super.key}); + + final TenderApprovalsResponse approvedTenders; @override Widget build(BuildContext context) { - return ListView.builder( - padding: const EdgeInsets.only(top: 20), - 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, - countryCode: '', - projectStatus: tender.projectStatus, - backgroundColor: - tender.status == 'Won' - ? AppColors.green0 - : tender.status == 'Completed' - ? AppColors.grey0 - : AppColors.red0, - borderColor: - tender.status == 'Won' - ? AppColors.green10 - : tender.status == 'Completed' - ? AppColors.grey30 - : AppColors.red10, - statusIcon: - tender.status == 'Won' - ? AssetsManager.tickCircle - : tender.status == 'Completed' - ? null - : AssetsManager.closeCircle, - statusCardColor: - tender.status == 'Won' - ? AppColors.green20 - : tender.status == 'Completed' - ? AppColors.blue0 - : AppColors.red10, - statusTextColor: - tender.status == 'Won' - ? AppColors.green30 - : tender.status == 'Completed' - ? AppColors.cyanTeal - : AppColors.red20, + return approvedTenders.data == null + ? const Center(child: Text('No approved projects yet.')) + : ListView.builder( + padding: const EdgeInsets.only(top: 20), + itemCount: approvedTenders.data!.length, + itemBuilder: (context, index) { + final tender = approvedTenders.data![index]; + return TenderCard( + date: tender.createdAt!.toString(), + title: tender.tender!.title!, + description: tender.tender!.description!, + location: tender.tender!.countryCode!, + countryFlag: AssetsManager.seFlag, + status: tender.status, + countryCode: tender.tender!.countryCode!, + projectStatus: tender.tender!.status!, + backgroundColor: + tender.status == 'Won' + ? AppColors.green0 + : tender.status == 'approved' + ? AppColors.grey0 + : AppColors.red0.withValues(alpha: 0.2), + borderColor: + tender.status == 'Won' + ? AppColors.green10 + : tender.status == 'approved' + ? AppColors.grey30 + : AppColors.red0, + statusIcon: + tender.status == 'Won' + ? AssetsManager.tickCircle + : tender.status == 'approved' + ? null + : AssetsManager.closeCircle, + statusCardColor: + tender.status == 'Won' + ? AppColors.green20 + : tender.status == 'approved' + ? AppColors.green20 + : AppColors.red0, + statusTextColor: + tender.status == 'Won' + ? AppColors.green30 + : tender.status == 'approved' + ? AppColors.green30 + : AppColors.red10, + ); + }, ); - }, - ); } }