From e015c941d2635987eb44c271a31da64064e070fa Mon Sep 17 00:00:00 2001 From: amirrezaghabeli Date: Wed, 17 Sep 2025 14:33:04 +0330 Subject: [PATCH] fixed rtl supoort in some pages --- assets/icons/left-arrow.svg | 4 + lib/core/config/app_config.dart | 4 +- lib/core/constants/assets.dart | 1 + .../detail/pages/detail_mobile_page.dart | 85 +++++------ lib/views/home/pages/d_home_page.dart | 2 +- lib/views/home/tender_card.dart | 11 +- lib/views/home/tenders_list_item.dart | 3 +- .../pages/liked_tenders_desktop_page.dart | 98 ++++++------- lib/views/profile/pages/d_profile_page.dart | 2 +- lib/views/profile/pages/t_profile_page.dart | 2 +- lib/views/shared/tender_app_bar.dart | 3 +- lib/views/tenders/pages/t_tenders_page.dart | 51 ++++--- .../tenders/widgets/main_tenders_slider.dart | 109 +++++++------- .../pages/your_tenders_mobile_page.dart | 135 +++++++++--------- 14 files changed, 270 insertions(+), 240 deletions(-) create mode 100644 assets/icons/left-arrow.svg diff --git a/assets/icons/left-arrow.svg b/assets/icons/left-arrow.svg new file mode 100644 index 0000000..703721b --- /dev/null +++ b/assets/icons/left-arrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/core/config/app_config.dart b/lib/core/config/app_config.dart index b23e7de..d1e38d9 100644 --- a/lib/core/config/app_config.dart +++ b/lib/core/config/app_config.dart @@ -8,13 +8,13 @@ class AppConfig { // این متد بر اساس محیط فعال، URL مناسب را برمی‌گرداند. static String get apiBaseUrl { - return 'http://10.0.2.2:8081'; + // 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 'https://app.opplens.com'; + return 'https://app.opplens.com'; // return 'http://localhost:8081'; // } else { // For Android emulator, use 10.0.2.2 (special IP for host machine) diff --git a/lib/core/constants/assets.dart b/lib/core/constants/assets.dart index e0088c3..33252ae 100644 --- a/lib/core/constants/assets.dart +++ b/lib/core/constants/assets.dart @@ -47,6 +47,7 @@ class AssetsManager { static const shield = 'assets/icons/shield.svg'; static const edit = 'assets/icons/edit.svg'; static const arrowRight = 'assets/icons/arrow-right.svg'; + static const leftArrow = 'assets/icons/left-arrow.svg'; static const notification = 'assets/icons/notification.svg'; static const danger = 'assets/icons/danger.svg'; diff --git a/lib/views/detail/pages/detail_mobile_page.dart b/lib/views/detail/pages/detail_mobile_page.dart index 3f66d3d..ced899d 100644 --- a/lib/views/detail/pages/detail_mobile_page.dart +++ b/lib/views/detail/pages/detail_mobile_page.dart @@ -86,50 +86,55 @@ class _TenderDetailMobilePageState extends State { }); } }, - child: Scaffold( - backgroundColor: AppColors.backgroundColor, - appBar: appBar( - context: context, - title: TenderDetailsStrings.tenderDetailTitle, - ), - body: Consumer( - builder: (context, tenderViewModel, child) { - if (tenderViewModel.isLoading) { - return const Center( - child: CircularProgressIndicator(color: AppColors.secondary50), - ); - } + child: Directionality( + textDirection: TextDirection.rtl, + child: Scaffold( + backgroundColor: AppColors.backgroundColor, + appBar: appBar( + context: context, + title: TenderDetailsStrings.tenderDetailTitle, + ), + body: Consumer( + builder: (context, tenderViewModel, child) { + if (tenderViewModel.isLoading) { + return const Center( + child: CircularProgressIndicator( + color: AppColors.secondary50, + ), + ); + } - if (tenderViewModel.errorMessage != null) { - return Center(child: Text(tenderViewModel.errorMessage!)); - } + if (tenderViewModel.errorMessage != null) { + return Center(child: Text(tenderViewModel.errorMessage!)); + } - final detail = tenderViewModel.tenderDetail; - if (detail == null) { - return const Center( - child: Text(TenderDetailsStrings.tenderNoData), - ); - } + final detail = tenderViewModel.tenderDetail; + if (detail == null) { + return const Center( + child: Text(TenderDetailsStrings.tenderNoData), + ); + } - return SingleChildScrollView( - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: 16.0.w(), - vertical: 16.0.h(), + return SingleChildScrollView( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: 16.0.w(), + vertical: 16.0.h(), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TenderDetailHeader(isScreenBig: false, detail: detail), + SizedBox(height: 24.0.h()), + TenderDetailCard(detail: detail), + SizedBox(height: 24.0.h()), + TenderDetailActions(isScreenBig: false, detail: detail), + ], + ), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TenderDetailHeader(isScreenBig: false, detail: detail), - SizedBox(height: 24.0.h()), - TenderDetailCard(detail: detail), - SizedBox(height: 24.0.h()), - TenderDetailActions(isScreenBig: false, detail: detail), - ], - ), - ), - ); - }, + ); + }, + ), ), ), ); diff --git a/lib/views/home/pages/d_home_page.dart b/lib/views/home/pages/d_home_page.dart index 06861c0..f81370a 100644 --- a/lib/views/home/pages/d_home_page.dart +++ b/lib/views/home/pages/d_home_page.dart @@ -182,7 +182,7 @@ class DesktopHomePage extends StatelessWidget { return ConstrainedBox( constraints: const BoxConstraints(maxWidth: 740), child: Align( - alignment: Alignment.centerLeft, + alignment: AlignmentDirectional.centerStart, child: Text( isYourTenders ? HomeStrings.yourTenders diff --git a/lib/views/home/tender_card.dart b/lib/views/home/tender_card.dart index 2660767..ec20ef5 100644 --- a/lib/views/home/tender_card.dart +++ b/lib/views/home/tender_card.dart @@ -31,6 +31,7 @@ class TenderCard extends StatelessWidget { @override Widget build(BuildContext context) { + final directionality = Directionality.of(context); return InkWell( onTap: enableTap ? onTap : null, child: Container( @@ -67,7 +68,15 @@ class TenderCard extends StatelessWidget { ), ), enableTap - ? SvgPicture.asset(AssetsManager.arrowRight) + ? SvgPicture.asset( + directionality == TextDirection.rtl + ? AssetsManager.leftArrow + : AssetsManager.arrowRight, + colorFilter: ColorFilter.mode( + AppColors.grey50, + BlendMode.srcIn, + ), + ) : const SizedBox(), ], ), diff --git a/lib/views/home/tenders_list_item.dart b/lib/views/home/tenders_list_item.dart index a27cb60..510048c 100644 --- a/lib/views/home/tenders_list_item.dart +++ b/lib/views/home/tenders_list_item.dart @@ -87,9 +87,10 @@ class TendersListItem extends StatelessWidget { width: double.infinity, child: Text( tender.description!, - textAlign: TextAlign.left, + textAlign: TextAlign.start, maxLines: 4, overflow: TextOverflow.ellipsis, + style: TextStyle( fontSize: 14.0.sp(), fontWeight: FontWeight.w400, diff --git a/lib/views/liked_tenders/pages/liked_tenders_desktop_page.dart b/lib/views/liked_tenders/pages/liked_tenders_desktop_page.dart index b4f8387..172d724 100644 --- a/lib/views/liked_tenders/pages/liked_tenders_desktop_page.dart +++ b/lib/views/liked_tenders/pages/liked_tenders_desktop_page.dart @@ -56,9 +56,7 @@ class _LikedTendersDesktopPageState extends State { backgroundColor: AppColors.backgroundColor, endDrawer: Drawer( backgroundColor: AppColors.backgroundColor, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal(left: Radius.circular(20)), - ), + child: Padding( padding: const EdgeInsets.all(16.0), child: Column( @@ -131,59 +129,53 @@ class _LikedTendersDesktopPageState extends State { return Column( children: [ Expanded( - child: RefreshIndicator( - onRefresh: () async { - await viewModel.getLikedTenders(reset: true); - }, - child: ListView.builder( - padding: EdgeInsets.symmetric( - horizontal: 24.0.w(), - vertical: 15.0.h(), - ), - itemCount: feedback.length, - itemBuilder: (context, index) { - final item = feedback[index]; - TenderApprovalsData? approval; - bool hasApproval = viewModel - .hasTenderApprovalForTender(item.tenderId!); - if (hasApproval) { - approval = viewModel - .getApprovalStatusForTender( - item.tenderId!, - ); - } else { - approval = null; - } - return Padding( - padding: EdgeInsets.only(bottom: 20.0.h()), - child: Dismissible( - key: ValueKey(item.tenderId ?? index), - direction: DismissDirection.endToStart, - background: Container( - alignment: Alignment.centerRight, - padding: EdgeInsets.symmetric( - horizontal: 20.0.w(), - ), - child: SvgPicture.asset( - AssetsManager.trash, - ), + child: ListView.builder( + padding: EdgeInsets.symmetric( + horizontal: 24.0.w(), + vertical: 15.0.h(), + ), + itemCount: feedback.length, + itemBuilder: (context, index) { + final item = feedback[index]; + TenderApprovalsData? approval; + bool hasApproval = viewModel + .hasTenderApprovalForTender(item.tenderId!); + if (hasApproval) { + approval = viewModel.getApprovalStatusForTender( + item.tenderId!, + ); + } else { + approval = null; + } + return Padding( + padding: EdgeInsets.only(bottom: 20.0.h()), + child: Dismissible( + key: ValueKey(item.tenderId ?? index), + direction: DismissDirection.endToStart, + background: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.symmetric( + horizontal: 20.0.w(), ), - onDismissed: (_) { - if (item.tenderId != null) { - viewModel.removeTenderById( - item.tenderId!, - ); - } - }, - child: LikedListItem( - tender: item.tender!, - approval: approval, - isDesktop: true, + child: SvgPicture.asset( + AssetsManager.trash, ), ), - ); - }, - ), + onDismissed: (_) { + if (item.tenderId != null) { + viewModel.removeTenderById( + item.tenderId!, + ); + } + }, + child: LikedListItem( + tender: item.tender!, + approval: approval, + isDesktop: true, + ), + ), + ); + }, ), ), diff --git a/lib/views/profile/pages/d_profile_page.dart b/lib/views/profile/pages/d_profile_page.dart index 0ec481d..6a0f00d 100644 --- a/lib/views/profile/pages/d_profile_page.dart +++ b/lib/views/profile/pages/d_profile_page.dart @@ -140,7 +140,7 @@ class _DesktopProfilePageState extends State { SizedBox(height: 24.0.h()), // Spacer(), Align( - alignment: Alignment.centerRight, + alignment: AlignmentDirectional.centerEnd, child: InkWell( onTap: () => viewModel.logout(), borderRadius: BorderRadius.circular(100), diff --git a/lib/views/profile/pages/t_profile_page.dart b/lib/views/profile/pages/t_profile_page.dart index 19a5c49..9673336 100644 --- a/lib/views/profile/pages/t_profile_page.dart +++ b/lib/views/profile/pages/t_profile_page.dart @@ -145,7 +145,7 @@ class _TabletProfilePageState extends State { SizedBox(height: 24.0.h()), // Spacer(), Align( - alignment: Alignment.centerRight, + alignment: AlignmentDirectional.centerStart, child: InkWell( onTap: () => viewModel.logout(), borderRadius: BorderRadius.circular(100), diff --git a/lib/views/shared/tender_app_bar.dart b/lib/views/shared/tender_app_bar.dart index 58cf072..13893c7 100644 --- a/lib/views/shared/tender_app_bar.dart +++ b/lib/views/shared/tender_app_bar.dart @@ -35,6 +35,7 @@ PreferredSizeWidget appBar({ required BuildContext context, required String title, }) { + final isRtl = Directionality.of(context) == TextDirection.rtl; return PreferredSize( preferredSize: const Size.fromHeight(60), child: AppBar( @@ -43,7 +44,7 @@ PreferredSizeWidget appBar({ titleSpacing: 0, leading: IconButton( icon: SvgPicture.asset( - AssetsManager.arrowLeft, + isRtl ? AssetsManager.arrowRight : AssetsManager.arrowLeft, height: 24.0.w(), width: 24.0.w(), ), diff --git a/lib/views/tenders/pages/t_tenders_page.dart b/lib/views/tenders/pages/t_tenders_page.dart index f2f1846..53d03dd 100644 --- a/lib/views/tenders/pages/t_tenders_page.dart +++ b/lib/views/tenders/pages/t_tenders_page.dart @@ -34,30 +34,35 @@ class _TabletTendersPageState extends State { backgroundColor: AppColors.backgroundColor, appBar: tabletAppBar(title: TendersStrings.tendersTitle, key: key), drawer: const TabletNavigationWidget(currentIndex: 1), - body: SingleChildScrollView( - child: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading) { - return const Center( - child: CircularProgressIndicator(color: AppColors.jellyBean), - ); - } - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - if ((viewModel.tendersResponse?.data?.tenders == null || - viewModel.tendersResponse!.data!.tenders!.isEmpty) && - viewModel.isLoading == false) { - return const Center(child: Text(CommonStrings.noData)); - } - return Padding( - padding: EdgeInsets.only(right: 24.0.w(), top: 128.0.h()), - child: MainTendersSlider( - tenders: viewModel.tendersResponse?.data?.tenders ?? [], - ), + body: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading) { + return const Center( + child: CircularProgressIndicator(color: AppColors.jellyBean), ); - }, - ), + } + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + if ((viewModel.tendersResponse?.data?.tenders == null || + viewModel.tendersResponse!.data!.tenders!.isEmpty) && + viewModel.isLoading == false) { + return const Center(child: Text(CommonStrings.noData)); + } + return Expanded( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsetsDirectional.only( + end: 24.0.w(), + top: 128.0.h(), + ), + child: MainTendersSlider( + tenders: viewModel.tendersResponse?.data?.tenders ?? [], + ), + ), + ), + ); + }, ), ); } diff --git a/lib/views/tenders/widgets/main_tenders_slider.dart b/lib/views/tenders/widgets/main_tenders_slider.dart index 4c3526b..1ff7aae 100644 --- a/lib/views/tenders/widgets/main_tenders_slider.dart +++ b/lib/views/tenders/widgets/main_tenders_slider.dart @@ -83,8 +83,11 @@ class _MainTendersSliderState extends State { @override Widget build(BuildContext context) { + bool isLtr = Directionality.of(context) == TextDirection.ltr; return SingleChildScrollView( - child: Stack(children: [_tendersPageView(), _nextPreviousArrows()]), + child: Stack( + children: [_tendersPageView(), _nextPreviousArrows(isLtr: isLtr)], + ), ); } @@ -127,43 +130,48 @@ class _MainTendersSliderState extends State { ); } - Widget _nextPreviousArrows() { - return Positioned( + Widget _nextPreviousArrows({required bool isLtr}) { + return PositionedDirectional( top: 607.0.h(), bottom: 52.0.h(), - left: 9.0.w(), - right: 9.0.w(), + start: 9.0.w(), + end: 9.0.w(), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [_leftArrowButton(), _pageNumberText(), _rightArrowButton()], + children: [ + _leftArrowButton(isLtr: isLtr), + _pageNumberText(), + _rightArrowButton(isLtr: isLtr), + ], ), ); } - Widget _leftArrowButton() { - return Visibility( - visible: currentPage != 1, - child: InkWell( - borderRadius: BorderRadius.circular(100), - onTap: _goToPreviousPage, - child: Container( - width: 32.0.h(), - height: 32.0.h(), - 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, + Widget _leftArrowButton({required bool isLtr}) { + return currentPage != 1 + ? InkWell( + borderRadius: BorderRadius.circular(100), + onTap: _goToPreviousPage, + child: Container( + width: 32.0.h(), + height: 32.0.h(), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: AppColors.iconColor, width: 1.5), + ), + alignment: Alignment.center, + child: SvgPicture.asset( + isLtr + ? AssetsManager.arrowLeftSmall + : AssetsManager.arrowRightSmall, + colorFilter: ColorFilter.mode( + AppColors.iconColor, + BlendMode.srcATop, + ), ), ), - ), - ), - ); + ) + : SizedBox(width: 32.0.h(), height: 32.0.h()); } Widget _pageNumberText() { @@ -195,29 +203,30 @@ class _MainTendersSliderState extends State { ); } - Widget _rightArrowButton() { - return Visibility( - visible: currentPage != widget.tenders.length, - child: InkWell( - borderRadius: BorderRadius.circular(100), - onTap: _goToNextPage, - child: Container( - width: 32.0.h(), - height: 32.0.h(), - 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, + Widget _rightArrowButton({required bool isLtr}) { + return currentPage != widget.tenders.length + ? InkWell( + borderRadius: BorderRadius.circular(100), + onTap: _goToNextPage, + child: Container( + width: 32.0.h(), + height: 32.0.h(), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: AppColors.iconColor, width: 1.5), + ), + alignment: Alignment.center, + child: SvgPicture.asset( + isLtr + ? AssetsManager.arrowRightSmall + : AssetsManager.arrowLeftSmall, + colorFilter: ColorFilter.mode( + AppColors.iconColor, + BlendMode.srcATop, + ), ), ), - ), - ), - ); + ) + : SizedBox(width: 32.0.h(), height: 32.0.h()); } } 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 e4ca33c..12d6356 100644 --- a/lib/views/your_tenders/pages/your_tenders_mobile_page.dart +++ b/lib/views/your_tenders/pages/your_tenders_mobile_page.dart @@ -35,74 +35,77 @@ class _YourTendersMobilePageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.backgroundColor, - appBar: appBar(context: context, title: YourTendersStrings.yourTenders), - body: Column( - children: [ - const FilterButton(platformType: PlatformType.mobile), - Expanded( - child: Consumer( - builder: (context, viewModel, child) { - if (viewModel.isLoading && - (viewModel.data?.data?.tenders ?? []).isEmpty && - (viewModel.likedTendersData?.data?.feedback ?? []) - .isEmpty) { - return const Center( - child: CircularProgressIndicator( - color: AppColors.secondary50, - ), - ); - } - - if (viewModel.errorMessage != null) { - return Center(child: Text(viewModel.errorMessage!)); - } - - return Column( - children: [ - if (viewModel.selectedStatus == - YourTendersStrings.likeTenders && - viewModel.likedTendersData != null) - Expanded( - child: LikedDislikedTendersList( - data: viewModel.likedTendersData!, - status: TenderFeedback.liked.value, - isDesktop: false, - isMobile: true, - ), - ) - else if (viewModel.selectedStatus == - YourTendersStrings.dislikeTenders && - viewModel.likedTendersData != null) - Expanded( - child: LikedDislikedTendersList( - data: viewModel.likedTendersData!, - status: TenderFeedback.disliked.value, - isDesktop: false, - isMobile: true, - ), - ) - else if (viewModel.data != null) - Expanded( - child: TendersSubmitted( - approvedTenders: viewModel.data!, - isDesktop: false, - isMobile: true, - ), - ) - else - const Expanded( - child: Center( - child: Text(YourTendersStrings.noTenders), - ), + return Directionality( + textDirection: TextDirection.rtl, + child: Scaffold( + backgroundColor: AppColors.backgroundColor, + appBar: appBar(context: context, title: YourTendersStrings.yourTenders), + body: Column( + children: [ + const FilterButton(platformType: PlatformType.mobile), + Expanded( + child: Consumer( + builder: (context, viewModel, child) { + if (viewModel.isLoading && + (viewModel.data?.data?.tenders ?? []).isEmpty && + (viewModel.likedTendersData?.data?.feedback ?? []) + .isEmpty) { + return const Center( + child: CircularProgressIndicator( + color: AppColors.secondary50, ), - ], - ); - }, + ); + } + + if (viewModel.errorMessage != null) { + return Center(child: Text(viewModel.errorMessage!)); + } + + return Column( + children: [ + if (viewModel.selectedStatus == + YourTendersStrings.likeTenders && + viewModel.likedTendersData != null) + Expanded( + child: LikedDislikedTendersList( + data: viewModel.likedTendersData!, + status: TenderFeedback.liked.value, + isDesktop: false, + isMobile: true, + ), + ) + else if (viewModel.selectedStatus == + YourTendersStrings.dislikeTenders && + viewModel.likedTendersData != null) + Expanded( + child: LikedDislikedTendersList( + data: viewModel.likedTendersData!, + status: TenderFeedback.disliked.value, + isDesktop: false, + isMobile: true, + ), + ) + else if (viewModel.data != null) + Expanded( + child: TendersSubmitted( + approvedTenders: viewModel.data!, + isDesktop: false, + isMobile: true, + ), + ) + else + const Expanded( + child: Center( + child: Text(YourTendersStrings.noTenders), + ), + ), + ], + ); + }, + ), ), - ), - ], + ], + ), ), ); }