From 777d9c3e70814b7d5e34a7e8e480ad58946351a2 Mon Sep 17 00:00:00 2001 From: amirrezaghabeli Date: Wed, 3 Sep 2025 15:15:37 +0330 Subject: [PATCH] delete likes in liked screen --- lib/core/config/dependencies.dart | 6 +- .../liked_tenders_repository.dart | 7 +- lib/view_models/liked_tenders_view_model.dart | 176 ++++++++++-------- lib/views/home/pages/m_home_page.dart | 4 +- .../pages/liked_tenders_desktop_page.dart | 11 +- .../pages/liked_tenders_mobile_page.dart | 19 +- .../pages/liked_tenders_screen.dart | 24 ++- .../pages/liked_tenders_tablet_page.dart | 4 +- 8 files changed, 158 insertions(+), 93 deletions(-) diff --git a/lib/core/config/dependencies.dart b/lib/core/config/dependencies.dart index d128ccb..6164a53 100644 --- a/lib/core/config/dependencies.dart +++ b/lib/core/config/dependencies.dart @@ -119,8 +119,10 @@ List get viewModels { ), ChangeNotifierProvider( create: - (context) => - LikedTendersViewModel(likedTendersRepository: context.read()), + (context) => LikedTendersViewModel( + likedTendersRepository: context.read(), + tendersRepository: context.read(), + ), ), ChangeNotifierProvider( create: diff --git a/lib/data/repositories/liked_tenders_repository.dart b/lib/data/repositories/liked_tenders_repository.dart index 7bad344..e944797 100644 --- a/lib/data/repositories/liked_tenders_repository.dart +++ b/lib/data/repositories/liked_tenders_repository.dart @@ -3,13 +3,14 @@ import 'package:tm_app/data/services/liked_tenders_service.dart'; import 'package:tm_app/data/services/model/liked_tenders_response/liked_tenders_response.dart'; class LikedTendersRepository { - final LikedTendersService likedTendersService; - LikedTendersRepository({required this.likedTendersService}); + final LikedTendersService _likedTendersService; + LikedTendersRepository({required LikedTendersService likedTendersService}) + : _likedTendersService = likedTendersService; Future> getLikedTenders({ int offset = 0, int limit = 20, }) { - return likedTendersService.getLikedTenders(offset: offset, limit: limit); + return _likedTendersService.getLikedTenders(offset: offset, limit: limit); } } diff --git a/lib/view_models/liked_tenders_view_model.dart b/lib/view_models/liked_tenders_view_model.dart index 28dcf9a..6370122 100644 --- a/lib/view_models/liked_tenders_view_model.dart +++ b/lib/view_models/liked_tenders_view_model.dart @@ -1,14 +1,20 @@ import 'package:flutter/material.dart'; import 'package:tm_app/core/utils/result.dart'; import 'package:tm_app/data/repositories/liked_tenders_repository.dart'; +import 'package:tm_app/data/repositories/tenders_repository.dart'; import 'package:tm_app/data/services/model/liked_tender_feedback/liked_tender_feedback.dart'; import 'package:tm_app/data/services/model/liked_tenders_response/liked_tenders_response.dart'; +import '../data/services/model/feedback_response/feedback_response.dart'; + class LikedTendersViewModel with ChangeNotifier { - final LikedTendersRepository likedTendersRepository; - LikedTendersViewModel({required this.likedTendersRepository}) { - getLikedTenders(reset: true); - } + final LikedTendersRepository _likedTendersRepository; + final TendersRepository _tendersRepository; + LikedTendersViewModel({ + required LikedTendersRepository likedTendersRepository, + required TendersRepository tendersRepository, + }) : _likedTendersRepository = likedTendersRepository, + _tendersRepository = tendersRepository; bool isLoading = false; bool isLoadingMore = false; @@ -21,71 +27,70 @@ class LikedTendersViewModel with ChangeNotifier { int currentPage = 1; -Future getLikedTenders({bool reset = false}) async { - if (!reset && (isLoadingMore || !hasMore)) { - return; - } - - if (reset) { - _offset = (currentPage - 1) * _limit; - hasMore = true; - - data = null; - isLoading = true; - notifyListeners(); - } else { - if (_offset == 0) { - isLoading = true; - } else { - isLoadingMore = true; + Future getLikedTenders({bool reset = false}) async { + if (!reset && (isLoadingMore || !hasMore)) { + return; } + + if (reset) { + _offset = (currentPage - 1) * _limit; + hasMore = true; + + data = null; + isLoading = true; + notifyListeners(); + } else { + if (_offset == 0) { + isLoading = true; + } else { + isLoadingMore = true; + } + notifyListeners(); + } + + errorMessage = null; + + final result = await _likedTendersRepository.getLikedTenders( + offset: _offset, + limit: _limit, + ); + + switch (result) { + case Ok(): + final incoming = result.value; + final incomingList = incoming.data?.feedback ?? []; + + if (reset) { + data = incoming; + } else { + final existingList = data?.data?.feedback ?? []; + final combined = List.of(existingList) + ..addAll(incomingList); + + data = data?.copyWith( + data: data?.data?.copyWith( + feedback: combined, + meta: incoming.data?.meta ?? data!.data!.meta, + ), + ); + } + + hasMore = incomingList.length == _limit; + _offset += _limit; + + errorMessage = null; + break; + + case Error(): + errorMessage = result.error.toString(); + break; + } + + isLoading = false; + isLoadingMore = false; notifyListeners(); } - errorMessage = null; - - final result = await likedTendersRepository.getLikedTenders( - offset: _offset, - limit: _limit, - ); - - switch (result) { - case Ok(): - final incoming = result.value; - final incomingList = incoming.data?.feedback ?? []; - - if (reset) { - data = incoming; - } else { - final existingList = data?.data?.feedback ?? []; - final combined = List.of(existingList) - ..addAll(incomingList); - - data = data?.copyWith( - data: data?.data?.copyWith( - feedback: combined, - meta: incoming.data?.meta ?? data!.data!.meta, - ), - ); - } - - hasMore = incomingList.length == _limit; - _offset += _limit; - - errorMessage = null; - break; - - case Error(): - errorMessage = result.error.toString(); - break; - } - - isLoading = false; - isLoadingMore = false; - notifyListeners(); -} - - Future loadMoreIfNeeded() async { if (isLoadingMore || !hasMore) { return; @@ -100,24 +105,49 @@ Future getLikedTenders({bool reset = false}) async { await getLikedTenders(reset: true); } - void removeTenderById(String id) { + void removeTenderById(String id) async { final current = data; final list = current?.data?.feedback; if (current == null || list == null) { return; } + // Store original list to restore if error occurs + final originalList = List.of(list); final updatedList = List.of(list) - ..removeWhere((e) => e.id == id); - - final updatedMeta = current.data?.meta?.copyWith(total: updatedList.length); + ..removeWhere((e) => e.tenderId == id); + // Temporarily update UI data = current.copyWith( - data: current.data?.copyWith( - feedback: updatedList, - meta: updatedMeta, - ), + data: current.data?.copyWith(feedback: updatedList), ); + notifyListeners(); + + final result = await _tendersRepository.toggleFeedback( + tenderId: id, + feedbackType: 'like', + ); + + switch (result) { + case Ok(): + final updatedMeta = current.data?.meta?.copyWith( + total: updatedList.length, + ); + data = current.copyWith( + data: current.data?.copyWith( + feedback: updatedList, + meta: updatedMeta, + ), + ); + break; + case Error(): + // Restore original list if error occurs + data = current.copyWith( + data: current.data?.copyWith(feedback: originalList), + ); + errorMessage = result.error.toString(); + break; + } notifyListeners(); } diff --git a/lib/views/home/pages/m_home_page.dart b/lib/views/home/pages/m_home_page.dart index 0e8bcc2..db6e7e7 100644 --- a/lib/views/home/pages/m_home_page.dart +++ b/lib/views/home/pages/m_home_page.dart @@ -152,7 +152,9 @@ class MobileHomePage extends StatelessWidget { textColor: AppColors.grey80, enableTap: true, onTap: () { - LikedTendersRouteData().push(context); + LikedTendersRouteData().push(context).then((value) { + homeViewModel.init(); + }); }, ), ], 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 42a1584..b08c7c2 100644 --- a/lib/views/liked_tenders/pages/liked_tenders_desktop_page.dart +++ b/lib/views/liked_tenders/pages/liked_tenders_desktop_page.dart @@ -61,7 +61,9 @@ class _LikedTendersDesktopPageState extends State { final feedback = viewModel.data?.data?.feedback ?? []; if (feedback.isEmpty) { - return const Center(child: Text('Nothing to show')); + return const Center( + child: Text('You haven’t liked any tenders yet.'), + ); } final currentPage = viewModel.currentPage; @@ -140,8 +142,11 @@ class _LikedTendersDesktopPageState extends State { final pageNumber = index + 1; return ListTile( title: Text('Page $pageNumber'), - onTap: () => - Navigator.pop(context, pageNumber), + onTap: + () => Navigator.pop( + context, + pageNumber, + ), ); }, ), diff --git a/lib/views/liked_tenders/pages/liked_tenders_mobile_page.dart b/lib/views/liked_tenders/pages/liked_tenders_mobile_page.dart index 0d1b8e1..559292e 100644 --- a/lib/views/liked_tenders/pages/liked_tenders_mobile_page.dart +++ b/lib/views/liked_tenders/pages/liked_tenders_mobile_page.dart @@ -31,7 +31,7 @@ class _LikedTendersMobilePageState extends State { } final max = _scrollController.position.maxScrollExtent; final pos = _scrollController.position.pixels; - const threshold = 200.0; + const threshold = 200.0; if (max - pos <= threshold) { final vm = Provider.of(context, listen: false); vm.loadMoreIfNeeded(); @@ -71,10 +71,13 @@ class _LikedTendersMobilePageState extends State { final feedback = viewModel.data?.data?.feedback ?? []; if (feedback.isEmpty) { - return const Center(child: Text('Nothing to show')); + return const Center( + child: Text('You haven’t liked any tenders yet.'), + ); } - final itemCount = feedback.length + (viewModel.isLoadingMore ? 1 : 0); + final itemCount = + feedback.length + (viewModel.isLoadingMore ? 1 : 0); return RefreshIndicator( onRefresh: () async { @@ -93,16 +96,18 @@ class _LikedTendersMobilePageState extends State { return Padding( padding: EdgeInsets.only(bottom: 20.0.h()), child: Dismissible( - key: ValueKey(item.id ?? index), + key: ValueKey(item.tenderId ?? index), direction: DismissDirection.endToStart, background: Container( alignment: Alignment.centerRight, - padding: EdgeInsets.symmetric(horizontal: 20.0.w()), + padding: EdgeInsets.symmetric( + horizontal: 20.0.w(), + ), child: SvgPicture.asset(AssetsManager.trash), ), onDismissed: (_) { - if (item.id != null) { - viewModel.removeTenderById(item.id!); + if (item.tenderId != null) { + viewModel.removeTenderById(item.tenderId!); } }, child: LikedListItem(tender: item.tender!), diff --git a/lib/views/liked_tenders/pages/liked_tenders_screen.dart b/lib/views/liked_tenders/pages/liked_tenders_screen.dart index 8f7a1c3..642c998 100644 --- a/lib/views/liked_tenders/pages/liked_tenders_screen.dart +++ b/lib/views/liked_tenders/pages/liked_tenders_screen.dart @@ -1,13 +1,31 @@ import 'package:flutter/material.dart'; -import 'package:tm_app/core/utils/size_config.dart'; -import 'package:tm_app/views/shared/responsive_builder.dart'; +import 'package:provider/provider.dart'; +import 'package:tm_app/core/utils/size_config.dart'; +import 'package:tm_app/view_models/liked_tenders_view_model.dart'; import 'package:tm_app/views/liked_tenders/pages/liked_tenders_desktop_page.dart'; import 'package:tm_app/views/liked_tenders/pages/liked_tenders_mobile_page.dart'; import 'package:tm_app/views/liked_tenders/pages/liked_tenders_tablet_page.dart'; +import 'package:tm_app/views/shared/responsive_builder.dart'; -class LikedTendersScreen extends StatelessWidget { +class LikedTendersScreen extends StatefulWidget { const LikedTendersScreen({super.key}); + @override + State createState() => _LikedTendersScreenState(); +} + +class _LikedTendersScreenState extends State { + late final LikedTendersViewModel viewModel; + + @override + void initState() { + viewModel = context.read(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + viewModel.getLikedTenders(reset: true); + }); + super.initState(); + } + @override Widget build(BuildContext context) { SizeConfig.init(context); diff --git a/lib/views/liked_tenders/pages/liked_tenders_tablet_page.dart b/lib/views/liked_tenders/pages/liked_tenders_tablet_page.dart index 8e59ffe..4260732 100644 --- a/lib/views/liked_tenders/pages/liked_tenders_tablet_page.dart +++ b/lib/views/liked_tenders/pages/liked_tenders_tablet_page.dart @@ -68,7 +68,9 @@ class _LikedTendersTabletPageState extends State { final feedback = viewModel.data?.data?.feedback ?? []; if (feedback.isEmpty) { - return const Center(child: Text('Nothing to show')); + return const Center( + child: Text('You haven’t liked any tenders yet.'), + ); } final currentPage = viewModel.currentPage;