diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index f61880a50d..ac980dd968 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -92,6 +92,7 @@ import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/state/delete_all_permanently_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/empty_spam_folder_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_unread_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/move_all_selection_all_emails_state.dart'; @@ -317,6 +318,10 @@ class MailboxController extends BaseMailboxController _refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } else if (success is DeleteAllPermanentlyEmailsSuccess) { _refreshMailboxChanges(currentMailboxState: success.currentMailboxState); + } else if (success is MarkAllAsStarredSelectionAllEmailsAllSuccess) { + _refreshMailboxChanges(currentMailboxState: success.currentMailboxState); + } else if (success is MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure) { + _refreshMailboxChanges(currentMailboxState: success.currentMailboxState); } }); }); diff --git a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart index 31a5a8c05a..55b7314a7a 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -119,6 +119,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/delete_all_permane import 'package:tmail_ui_user/features/thread/domain/usecases/empty_spam_folder_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/get_email_by_id_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_unread_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; @@ -190,6 +191,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); Get.put(AdvancedFilterController()); } @@ -380,6 +382,11 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), )); + Get.lazyPut(() => MarkAllAsStarredSelectionAllEmailsInteractor( + Get.find(), + Get.find(), + Get.find(), + )); } @override diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 3a12221061..7a0fa0c948 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -147,6 +147,7 @@ import 'package:tmail_ui_user/features/thread/domain/state/delete_all_permanentl import 'package:tmail_ui_user/features/thread/domain/state/empty_spam_folder_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_email_by_id_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_unread_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_as_star_multiple_email_state.dart'; @@ -157,6 +158,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/delete_all_permane import 'package:tmail_ui_user/features/thread/domain/usecases/empty_spam_folder_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/get_email_by_id_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_unread_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; @@ -218,6 +220,7 @@ class MailboxDashBoardController extends ReloadableController final MarkAllAsUnreadSelectionAllEmailsInteractor _markAllAsUnreadSelectionAllEmailsInteractor; final MoveAllSelectionAllEmailsInteractor _moveAllSelectionAllEmailsInteractor; final DeleteAllPermanentlyEmailsInteractor _deleteAllPermanentlyEmailsInteractor; + final MarkAllAsStarredSelectionAllEmailsInteractor _markAllAsStarredSelectionAllEmailsInteractor; GetAllVacationInteractor? _getAllVacationInteractor; UpdateVacationInteractor? _updateVacationInteractor; @@ -255,6 +258,7 @@ class MailboxDashBoardController extends ReloadableController final markAllAsUnreadSelectionAllEmailsViewState = Rx>(Right(UIState.idle)); final moveAllSelectionAllEmailsViewState = Rx>(Right(UIState.idle)); final deleteAllPermanentlyEmailsViewState = Rx>(Right(UIState.idle)); + final markAllAsStarredSelectionAllEmailsViewState = Rx>(Right(UIState.idle)); Session? sessionCurrent; Map mapDefaultMailboxIdByRole = {}; @@ -276,6 +280,7 @@ class MailboxDashBoardController extends ReloadableController late StreamSubscription _markAllAsUnreadSelectionAllEmailsStreamSubscription; late StreamSubscription _moveAllSelectionAllEmailsStreamSubscription; late StreamSubscription _deleteAllPermanentlyEmailsStreamSubscription; + late StreamSubscription _markAllAsStarredSelectionAllEmailsStreamSubscription; final StreamController> _markAsReadMailboxStreamController = StreamController>.broadcast(); @@ -287,6 +292,8 @@ class MailboxDashBoardController extends ReloadableController StreamController>.broadcast(); final StreamController> _deleteAllPermanentlyEmailsStreamController = StreamController>.broadcast(); + final StreamController> _markAllAsStarredSelectionAllEmailsStreamController = + StreamController>.broadcast(); final _notificationManager = LocalNotificationManager.instance; final _fcmService = FcmService.instance; @@ -320,6 +327,7 @@ class MailboxDashBoardController extends ReloadableController this._markAllAsUnreadSelectionAllEmailsInteractor, this._moveAllSelectionAllEmailsInteractor, this._deleteAllPermanentlyEmailsInteractor, + this._markAllAsStarredSelectionAllEmailsInteractor, ); @override @@ -451,6 +459,9 @@ class MailboxDashBoardController extends ReloadableController _handleMoveAllSelectionAllEmailsSuccess(success); } else if (success is DeleteAllPermanentlyEmailsSuccess) { _handleDeleteAllPermanentlyEmailsSuccess(success); + } else if (success is MarkAllAsStarredSelectionAllEmailsAllSuccess + || success is MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure) { + _handleMarkAllAsStarredSelectionAllEmailsSuccess(success); } } @@ -487,6 +498,9 @@ class MailboxDashBoardController extends ReloadableController _handleMoveAllSelectionAllEmailsFailure(failure); } else if (failure is DeleteAllPermanentlyEmailsFailure) { _handleDeleteAllPermanentlyEmailsFailure(failure); + } else if (failure is MarkAllAsStarredSelectionAllEmailsFailure + || failure is MarkAllAsStarredSelectionAllEmailsAllFailure) { + _handleMarkAllAsStarredSelectionAllEmailsFailure(failure); } } @@ -688,6 +702,10 @@ class MailboxDashBoardController extends ReloadableController deleteAllPermanentlyEmailsViewState.value = state; }); + _markAllAsStarredSelectionAllEmailsStreamSubscription = _markAllAsStarredSelectionAllEmailsStreamController.stream.listen((state) { + markAllAsStarredSelectionAllEmailsViewState.value = state; + }); + _registerLocalNotificationStreamListener(); } @@ -3203,6 +3221,47 @@ class MailboxDashBoardController extends ReloadableController ); } + void markAllAsStarredSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + String mailboxDisplayName, + int totalEmails + ) { + consumeState(_markAllAsStarredSelectionAllEmailsInteractor.execute( + session, + accountId, + mailboxId, + mailboxDisplayName, + totalEmails, + _markAllAsUnreadSelectionAllEmailsStreamController + )); + } + + void _handleMarkAllAsStarredSelectionAllEmailsSuccess(Success success) { + markAllAsStarredSelectionAllEmailsViewState.value = Right(UIState.idle); + + if (currentContext == null || currentOverlayContext == null) return; + + toastManager.showSuccessMessage( + context: currentContext!, + overlayContext: currentOverlayContext!, + success: success, + ); + } + + void _handleMarkAllAsStarredSelectionAllEmailsFailure(Failure failure) { + markAllAsStarredSelectionAllEmailsViewState.value = Right(UIState.idle); + + if (currentContext == null || currentOverlayContext == null) return; + + toastManager.showFailureMessage( + context: currentContext!, + overlayContext: currentOverlayContext!, + failure: failure, + ); + } + @override void onClose() { if (PlatformInfo.isWeb) { @@ -3228,6 +3287,8 @@ class MailboxDashBoardController extends ReloadableController _moveAllSelectionAllEmailsStreamController.close(); _deleteAllPermanentlyEmailsStreamSubscription.cancel(); _deleteAllPermanentlyEmailsStreamController.close(); + _markAllAsStarredSelectionAllEmailsStreamSubscription.cancel(); + _markAllAsStarredSelectionAllEmailsStreamController.close(); _notificationManager.closeStream(); _fcmService.closeStream(); applicationManager.releaseUserAgent(); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index b0337a01e4..8a9a310653 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -26,6 +26,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/do import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/mark_mailbox_as_read_loading_banner.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/navigation_bar/navigation_bar_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/loading/delete_all_permanently_emails_loading_widget.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/loading/mark_all_as_starred_selection_all_emails_loading_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/loading/mark_all_as_unread_selection_all_emails_loading_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/loading/mark_mailbox_as_read_loading_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/loading/move_all_selection_all_emails_loading_widget.dart'; @@ -141,6 +142,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { Obx(() => MarkAllAsUnreadSelectionAllEmailsLoadingWidget(viewState: controller.markAllAsUnreadSelectionAllEmailsViewState.value)), Obx(() => MoveAllSelectionAllEmailsLoadingWidget(viewState: controller.moveAllSelectionAllEmailsViewState.value)), Obx(() => DeleteAllPermanentlyEmailsLoadingWidget(viewState: controller.deleteAllPermanentlyEmailsViewState.value)), + Obx(() => MarkAllAsStarredSelectionAllEmailsLoadingWidget(viewState: controller.markAllAsStarredSelectionAllEmailsViewState.value)), Expanded(child: Obx(() { switch(controller.dashboardRoute.value) { case DashboardRoutes.thread: diff --git a/lib/features/mailbox_dashboard/presentation/widgets/loading/mark_all_as_starred_selection_all_emails_loading_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/loading/mark_all_as_starred_selection_all_emails_loading_widget.dart new file mode 100644 index 0000000000..c859468221 --- /dev/null +++ b/lib/features/mailbox_dashboard/presentation/widgets/loading/mark_all_as_starred_selection_all_emails_loading_widget.dart @@ -0,0 +1,38 @@ + +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter/material.dart'; +import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; + +class MarkAllAsStarredSelectionAllEmailsLoadingWidget extends StatelessWidget with AppLoaderMixin { + + final Either viewState; + + const MarkAllAsStarredSelectionAllEmailsLoadingWidget({super.key, required this.viewState}); + + @override + Widget build(BuildContext context) { + return viewState.fold( + (failure) => const SizedBox.shrink(), + (success) { + if (success is MarkAllAsStarredSelectionAllEmailsLoading) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: horizontalLoadingWidget + ); + } else if (success is MarkAllAsStarredSelectionAllEmailsUpdating) { + final percent = success.total > 0 + ? success.countStarred / success.total + : 0.0; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: horizontalPercentLoadingWidget(percent) + ); + } + return const SizedBox.shrink(); + } + ); + } +} diff --git a/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart b/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart index 48db476256..ee9f844613 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart @@ -73,17 +73,13 @@ class TopBarThreadSelection extends StatelessWidget{ ) ), TMailButtonWidget.fromIcon( - icon: listEmail.isAllEmailStarred - ? imagePaths.icUnStar - : imagePaths.icStar, - tooltipMessage: listEmail.isAllEmailStarred - ? AppLocalizations.of(context).un_star - : AppLocalizations.of(context).star, + icon: _getIconForMarkAsStar(), + tooltipMessage: _getTooltipMessageForMarkAsStar(context), backgroundColor: Colors.transparent, iconSize: 24, onTapActionCallback: () => onEmailActionTypeAction?.call( List.from(listEmail), - listEmail.isAllEmailStarred ? EmailActionType.unMarkAsStarred : EmailActionType.markAsStarred + _getActionTypeForMarkAsStar() ) ), if (canSpamAndMove) @@ -241,4 +237,35 @@ class TopBarThreadSelection extends StatelessWidget{ return EmailActionType.moveToTrash; } } + + String _getIconForMarkAsStar() { + if (isSelectAllEmailsEnabled) { + return imagePaths.icStar; + } else { + return listEmail.isAllEmailStarred + ? imagePaths.icUnStar + : imagePaths.icStar; + } + } + + String _getTooltipMessageForMarkAsStar(BuildContext context) { + if (isSelectAllEmailsEnabled) { + return AppLocalizations.of(context).allStarred; + } else { + return listEmail.isAllEmailStarred + ? AppLocalizations.of(context).un_star + : AppLocalizations.of(context).star; + } + } + + + EmailActionType _getActionTypeForMarkAsStar() { + if (isSelectAllEmailsEnabled) { + return EmailActionType.markAllAsStarred; + } else { + return listEmail.isAllEmailStarred + ? EmailActionType.unMarkAsStarred + : EmailActionType.markAsStarred; + } + } } \ No newline at end of file diff --git a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart index e24b3e34c2..b6a6a30137 100644 --- a/lib/features/search/mailbox/presentation/search_mailbox_controller.dart +++ b/lib/features/search/mailbox/presentation/search_mailbox_controller.dart @@ -63,6 +63,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dash import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_bindings.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/features/thread/domain/state/delete_all_permanently_emails_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_unread_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/move_all_selection_all_emails_state.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -180,6 +181,10 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa _refreshMailboxChanges(mailboxState: success.currentMailboxState); } else if (success is DeleteAllPermanentlyEmailsSuccess) { _refreshMailboxChanges(mailboxState: success.currentMailboxState); + } else if (success is MarkAllAsStarredSelectionAllEmailsAllSuccess) { + _refreshMailboxChanges(mailboxState: success.currentMailboxState); + } else if (success is MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure) { + _refreshMailboxChanges(mailboxState: success.currentMailboxState); } } diff --git a/lib/features/thread/data/datasource/thread_datasource.dart b/lib/features/thread/data/datasource/thread_datasource.dart index 761aec08c4..c1c2788797 100644 --- a/lib/features/thread/data/datasource/thread_datasource.dart +++ b/lib/features/thread/data/datasource/thread_datasource.dart @@ -102,4 +102,12 @@ abstract class ThreadDataSource { int totalEmails, StreamController> onProgressController, ); + + Future> markAllAsStarredForSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + int totalEmails, + StreamController> onProgressController + ); } \ No newline at end of file diff --git a/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart b/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart index 645236307d..d680f09361 100644 --- a/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart +++ b/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart @@ -160,4 +160,15 @@ class LocalThreadDataSourceImpl extends ThreadDataSource { ) { throw UnimplementedError(); } + + @override + Future> markAllAsStarredForSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + int totalEmails, + StreamController> onProgressController + ) { + throw UnimplementedError(); + } } \ No newline at end of file diff --git a/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart b/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart index 71aa4ef6cb..fc98e1d530 100644 --- a/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart +++ b/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart @@ -199,4 +199,23 @@ class ThreadDataSourceImpl extends ThreadDataSource { ); }).catchError(_exceptionThrower.throwException); } + + @override + Future> markAllAsStarredForSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + int totalEmails, + StreamController> onProgressController + ) { + return Future.sync(() async { + return await _threadIsolateWorker.markAllAsStarredForSelectionAllEmails( + session, + accountId, + mailboxId, + totalEmails, + onProgressController, + ); + }).catchError(_exceptionThrower.throwException); + } } \ No newline at end of file diff --git a/lib/features/thread/data/network/thread_isolate_worker.dart b/lib/features/thread/data/network/thread_isolate_worker.dart index ffa096a296..467afcaff2 100644 --- a/lib/features/thread/data/network/thread_isolate_worker.dart +++ b/lib/features/thread/data/network/thread_isolate_worker.dart @@ -18,6 +18,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_property.dart'; +import 'package:model/email/mark_star_action.dart'; import 'package:model/email/read_actions.dart'; import 'package:model/extensions/list_email_extension.dart'; import 'package:tmail_ui_user/features/base/isolate/background_isolate_binary_messenger/background_isolate_binary_messenger.dart'; @@ -27,6 +28,7 @@ import 'package:tmail_ui_user/features/thread/data/model/empty_mailbox_folder_ar import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/domain/exceptions/thread_exceptions.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_unread_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/move_all_selection_all_emails_state.dart'; import 'package:tmail_ui_user/main/exceptions/isolate_exception.dart'; @@ -141,15 +143,13 @@ class ThreadIsolateWorker { EmailComparator(EmailComparatorProperty.receivedAt) ..setIsAscending(false)), filter: EmailFilterCondition(inMailbox: mailboxId, before: lastEmail?.receivedAt), - properties: Properties({EmailProperty.id})); - - var newEmailList = emailsResponse.emailList ?? []; - if (lastEmail != null) { - newEmailList = newEmailList.where((email) => email.id != lastEmail!.id).toList(); - } - + properties: Properties({EmailProperty.id}) + ).then((response) => _removeDuplicatedLatestEmailFromEmailResponse( + emailsResponse: response, + latestEmailId: lastEmail?.id + )); + final newEmailList = emailsResponse.emailList ?? []; log('ThreadIsolateWorker::_emptyMailboxFolderOnWeb(): ${newEmailList.length}'); - if (newEmailList.isNotEmpty) { lastEmail = newEmailList.last; hasEmails = true; @@ -199,15 +199,10 @@ class ThreadIsolateWorker { EmailProperty.id, EmailProperty.receivedAt, }) - ).then((response) { - var listEmails = response.emailList; - if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) { - listEmails = listEmails - .where((email) => email.id != lastEmailId) - .toList(); - } - return EmailsResponse(emailList: listEmails, state: response.state); - }); + ).then((response) => _removeDuplicatedLatestEmailFromEmailResponse( + emailsResponse: response, + latestEmailId: lastEmailId + )); final listEmailRead = emailResponse.emailList; log('ThreadIsolateWorker::markAllAsUnreadForSelectionAllEmails: LIST_EMAIL_READ = ${listEmailRead?.length}'); if (listEmailRead == null || listEmailRead.isEmpty) { @@ -272,15 +267,10 @@ class ThreadIsolateWorker { EmailProperty.id, EmailProperty.receivedAt, }) - ).then((response) { - var listEmails = response.emailList; - if (listEmails != null && listEmails.isNotEmpty && lastEmailId != null) { - listEmails = listEmails - .where((email) => email.id != lastEmailId) - .toList(); - } - return EmailsResponse(emailList: listEmails, state: response.state); - }); + ).then((response) => _removeDuplicatedLatestEmailFromEmailResponse( + emailsResponse: response, + latestEmailId: lastEmailId + )); final listEmail = emailResponse.emailList; log('ThreadIsolateWorker::moveAllSelectionAllEmails: LIST_EMAIL = ${listEmail?.length}'); if (listEmail == null || listEmail.isEmpty) { @@ -355,4 +345,84 @@ class ThreadIsolateWorker { log('ThreadIsolateWorker::deleteAllPermanentlyEmails(): TOTAL_DELETED_PERMANENTLY: ${emailIdListCompleted.length}'); return emailIdListCompleted; } + + Future> markAllAsStarredForSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + int totalEmails, + StreamController> onProgressController + ) async { + List emailIdListCompleted = List.empty(growable: true); + try { + bool mailboxHasEmails = true; + UTCDate? lastReceivedDate; + EmailId? lastEmailId; + + while (mailboxHasEmails) { + final emailResponse = await _threadAPI.getAllEmail( + session, + accountId, + limit: UnsignedInt(30), + filter: EmailFilterCondition( + inMailbox: mailboxId, + notKeyword: KeyWordIdentifier.emailFlagged.value, + before: lastReceivedDate + ), + sort: {}..add( + EmailComparator(EmailComparatorProperty.receivedAt)..setIsAscending(false) + ), + properties: Properties({ + EmailProperty.id, + EmailProperty.receivedAt, + }) + ).then((response) => _removeDuplicatedLatestEmailFromEmailResponse( + emailsResponse: response, + latestEmailId: lastEmailId + )); + final listEmails = emailResponse.emailList; + + if (listEmails == null || listEmails.isEmpty) { + mailboxHasEmails = false; + } else { + lastEmailId = listEmails.last.id; + lastReceivedDate = listEmails.last.receivedAt; + + final listResult = await _emailAPI.markAsStar( + session, + accountId, + listEmails, + MarkStarAction.markStar + ); + + emailIdListCompleted.addAll(listResult.listEmailIds); + onProgressController.add( + dartz.Right(MarkAllAsStarredSelectionAllEmailsUpdating( + total: totalEmails, + countStarred: emailIdListCompleted.length + )) + ); + } + } + } catch (e) { + logError('ThreadIsolateWorker::markAllAsStarredForSelectionAllEmails(): ERROR: $e'); + } + return emailIdListCompleted; + } + + EmailsResponse _removeDuplicatedLatestEmailFromEmailResponse({ + required EmailsResponse emailsResponse, + EmailId? latestEmailId, + }) { + List listEmails = emailsResponse.emailList ?? []; + if (listEmails.isNotEmpty && latestEmailId != null) { + listEmails = listEmails + .where((email) => email.id != latestEmailId) + .toList(); + + return EmailsResponse(emailList: listEmails, state: emailsResponse.state); + } else { + return emailsResponse; + } + } } diff --git a/lib/features/thread/data/repository/thread_repository_impl.dart b/lib/features/thread/data/repository/thread_repository_impl.dart index 0905f0a775..6d7209172c 100644 --- a/lib/features/thread/data/repository/thread_repository_impl.dart +++ b/lib/features/thread/data/repository/thread_repository_impl.dart @@ -476,4 +476,21 @@ class ThreadRepositoryImpl extends ThreadRepository { return listEmailIdDeleted; } + + @override + Future> markAllAsStarredForSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + int totalEmails, + StreamController> onProgressController + ) { + return mapDataSource[DataSourceType.network]!.markAllAsStarredForSelectionAllEmails( + session, + accountId, + mailboxId, + totalEmails, + onProgressController + ); + } } \ No newline at end of file diff --git a/lib/features/thread/domain/repository/thread_repository.dart b/lib/features/thread/domain/repository/thread_repository.dart index 8c22050e2d..bf833c8c89 100644 --- a/lib/features/thread/domain/repository/thread_repository.dart +++ b/lib/features/thread/domain/repository/thread_repository.dart @@ -103,4 +103,12 @@ abstract class ThreadRepository { int totalEmails, StreamController> onProgressController, ); + + Future> markAllAsStarredForSelectionAllEmails( + Session session, + AccountId accountId, + MailboxId mailboxId, + int totalEmails, + StreamController> onProgressController + ); } \ No newline at end of file diff --git a/lib/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart b/lib/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart new file mode 100644 index 0000000000..f489219b5d --- /dev/null +++ b/lib/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart @@ -0,0 +1,56 @@ +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart' as jmap; +import 'package:tmail_ui_user/features/base/state/ui_action_state.dart'; + +class MarkAllAsStarredSelectionAllEmailsLoading extends LoadingState {} + +class MarkAllAsStarredSelectionAllEmailsUpdating extends UIState { + + final int total; + final int countStarred; + + MarkAllAsStarredSelectionAllEmailsUpdating({ + required this.total, + required this.countStarred + }); + + @override + List get props => [total, countStarred]; +} + +class MarkAllAsStarredSelectionAllEmailsAllSuccess extends UIActionState { + + MarkAllAsStarredSelectionAllEmailsAllSuccess({ + jmap.State? currentEmailState, + jmap.State? currentMailboxState, + }) : super(currentMailboxState, currentEmailState); +} + +class MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure extends UIActionState { + + final int countStarred; + + MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure( + this.countStarred, + { + jmap.State? currentEmailState, + jmap.State? currentMailboxState, + } + ) : super(currentMailboxState, currentEmailState); + + @override + List get props => [ + countStarred, + ...super.props + ]; +} + +class MarkAllAsStarredSelectionAllEmailsAllFailure extends FeatureFailure {} + +class MarkAllAsStarredSelectionAllEmailsFailure extends FeatureFailure { + + MarkAllAsStarredSelectionAllEmailsFailure({ + dynamic exception + }) : super(exception: exception); +} \ No newline at end of file diff --git a/lib/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart b/lib/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart new file mode 100644 index 0000000000..bbdb1707ad --- /dev/null +++ b/lib/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart @@ -0,0 +1,68 @@ +import 'dart:async'; + +import 'package:core/presentation/state/failure.dart'; +import 'package:core/presentation/state/success.dart'; +import 'package:dartz/dartz.dart'; +import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/repository/mailbox_repository.dart'; +import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; + +class MarkAllAsStarredSelectionAllEmailsInteractor { + final EmailRepository _emailRepository; + final MailboxRepository _mailboxRepository; + final ThreadRepository _threadRepository; + + MarkAllAsStarredSelectionAllEmailsInteractor( + this._emailRepository, + this._mailboxRepository, + this._threadRepository, + ); + + Stream> execute( + Session session, + AccountId accountId, + MailboxId mailboxId, + String mailboxDisplayName, + int totalEmails, + StreamController> onProgressController + ) async* { + try { + yield Right(MarkAllAsStarredSelectionAllEmailsLoading()); + onProgressController.add(Right(MarkAllAsStarredSelectionAllEmailsLoading())); + + final listState = await Future.wait([ + _mailboxRepository.getMailboxState(session, accountId), + _emailRepository.getEmailState(session, accountId), + ], eagerError: true); + + final currentMailboxState = listState.first; + final currentEmailState = listState.last; + + final listEmailId = await _threadRepository.markAllAsStarredForSelectionAllEmails( + session, + accountId, + mailboxId, + totalEmails, + onProgressController); + + if (totalEmails == listEmailId.length) { + yield Right(MarkAllAsStarredSelectionAllEmailsAllSuccess( + currentEmailState: currentEmailState, + currentMailboxState: currentMailboxState)); + } else if (listEmailId.isNotEmpty) { + yield Right(MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure( + listEmailId.length, + currentEmailState: currentEmailState, + currentMailboxState: currentMailboxState)); + } else { + yield Left(MarkAllAsStarredSelectionAllEmailsAllFailure()); + } + } catch (e) { + yield Left(MarkAllAsStarredSelectionAllEmailsFailure(exception: e)); + } + } +} \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 64e7b614c2..ef55e11e5b 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -62,6 +62,7 @@ import 'package:tmail_ui_user/features/thread/domain/state/empty_trash_folder_st import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_email_by_id_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/load_more_emails_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_unread_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_as_multiple_email_read_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_as_star_multiple_email_state.dart'; @@ -426,6 +427,12 @@ class ThreadController extends BaseController with EmailActionController, PopupM } else if (success is DeleteAllPermanentlyEmailsSuccess) { cancelSelectEmail(); _refreshEmailChanges(currentEmailState: success.currentEmailState); + } else if (success is MarkAllAsStarredSelectionAllEmailsAllSuccess) { + cancelSelectEmail(); + _refreshEmailChanges(currentEmailState: success.currentEmailState); + } else if (success is MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure) { + cancelSelectEmail(); + _refreshEmailChanges(currentEmailState: success.currentEmailState); } }); }); @@ -1522,6 +1529,15 @@ class ThreadController extends BaseController with EmailActionController, PopupM selectedMailbox, ); break; + case EmailActionType.markAllAsStarred: + mailboxDashBoardController.markAllAsStarredSelectionAllEmails( + _session!, + _accountId!, + selectedMailbox.mailboxId!, + selectedMailbox.getDisplayName(context), + selectedMailbox.countTotalEmails + ); + break; default: break; } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index cd23e6b6ef..1b7e2ea7fc 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4385,5 +4385,43 @@ "placeholders": { "reason": {} } + }, + "allStarred": "All starred", + "@allStarred": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageMarkAllAsStarredSelectionAllEmailsSuccess": "You’ve marked all mails as starred", + "@toastMessageMarkAllAsStarredSelectionAllEmailsSuccess": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageMarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure": "You’ve marked {count} mails as starred", + "@toastMessageMarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure": { + "type": "text", + "placeholders_order": [ + "count" + ], + "placeholders": { + "count": {} + } + }, + "toastMessageMarkAllAsStarredSelectionAllEmailsAllFailure": "All mails could not be marked as starred", + "@toastMessageMarkAllAsStarredSelectionAllEmailsAllFailure": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "toastMessageMarkAllAsStarredSelectionAllEmailsFailureWithReason": "All mails could not be marked as starred. Due \"{reason}\"", + "@toastMessageMarkAllAsStarredSelectionAllEmailsFailureWithReason": { + "type": "text", + "placeholders_order": [ + "reason" + ], + "placeholders": { + "reason": {} + } } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3ae621adb2..6a9bea9eb9 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -4565,4 +4565,38 @@ class AppLocalizations { args: [reason] ); } + + String get allStarred { + return Intl.message( + 'All starred', + name: 'allStarred', + ); + } + + String get toastMessageMarkAllAsStarredSelectionAllEmailsSuccess { + return Intl.message( + 'You’ve marked all mails as starred', + name: 'toastMessageMarkAllAsStarredSelectionAllEmailsSuccess'); + } + + String toastMessageMarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure(int count) { + return Intl.message( + 'You’ve marked $count mails as starred', + name: 'toastMessageMarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure', + args: [count]); + } + + String get toastMessageMarkAllAsStarredSelectionAllEmailsAllFailure { + return Intl.message( + 'All mails could not be marked as starred', + name: 'toastMessageMarkAllAsStarredSelectionAllEmailsAllFailure'); + } + + String toastMessageMarkAllAsStarredSelectionAllEmailsFailureWithReason(String reason) { + return Intl.message( + 'All mails could not be marked as starred. Due "$reason"', + name: 'toastMessageMarkAllAsStarredSelectionAllEmailsFailureWithReason', + args: [reason] + ); + } } \ No newline at end of file diff --git a/lib/main/utils/toast_manager.dart b/lib/main/utils/toast_manager.dart index 173f88ef9f..d6186e9d57 100644 --- a/lib/main/utils/toast_manager.dart +++ b/lib/main/utils/toast_manager.dart @@ -16,6 +16,7 @@ import 'package:tmail_ui_user/features/starting_page/domain/state/sign_in_twake_ import 'package:tmail_ui_user/features/starting_page/domain/state/sign_up_twake_workplace_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/delete_all_permanently_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/empty_spam_folder_state.dart'; +import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_starred_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/mark_all_as_unread_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/move_all_selection_all_emails_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/move_multiple_email_to_mailbox_state.dart'; @@ -143,6 +144,18 @@ class ToastManager { overlayContext, AppLocalizations.of(context).toast_message_empty_trash_folder_success, ); + } else if (success is MarkAllAsStarredSelectionAllEmailsAllSuccess) { + _appToast.showToastSuccessMessage( + overlayContext, + AppLocalizations.of(context).toastMessageMarkAllAsStarredSelectionAllEmailsSuccess, + leadingSVGIcon: _imagePaths.icUnreadToast, + ); + } else if (success is MarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure) { + _appToast.showToastSuccessMessage( + overlayContext, + AppLocalizations.of(context).toastMessageMarkAllAsStarredSelectionAllEmailsHasSomeEmailFailure(success.countStarred), + leadingSVGIcon: _imagePaths.icUnreadToast, + ); } } @@ -198,6 +211,18 @@ class ToastManager { failure.exception.toString(), ), ); + } else if (failure is MarkAllAsStarredSelectionAllEmailsFailure) { + _appToast.showToastErrorMessage( + overlayContext, + AppLocalizations.of(context).toastMessageMarkAllAsStarredSelectionAllEmailsFailureWithReason( + failure.exception.toString(), + ), + ); + } else if (failure is MarkAllAsStarredSelectionAllEmailsAllFailure) { + _appToast.showToastErrorMessage( + overlayContext, + AppLocalizations.of(context).toastMessageMarkAllAsStarredSelectionAllEmailsAllFailure, + ); } } } diff --git a/model/lib/email/email_action_type.dart b/model/lib/email/email_action_type.dart index d6ed60bb00..aaea2bb6f6 100644 --- a/model/lib/email/email_action_type.dart +++ b/model/lib/email/email_action_type.dart @@ -34,4 +34,5 @@ enum EmailActionType { moveAll, moveAllToTrash, deleteAllPermanently, + markAllAsStarred, } \ No newline at end of file diff --git a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart index 614681b1ac..914cd2f164 100644 --- a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart +++ b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart @@ -85,6 +85,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder import 'package:tmail_ui_user/features/thread/domain/usecases/get_email_by_id_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/load_more_emails_in_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_unread_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; @@ -184,6 +185,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), + MockSpec(), ]) void main() { // mock mailbox dashboard controller direct dependencies @@ -272,6 +274,7 @@ void main() { final markAllAsUnreadSelectionAllEmailsInteractor = MockMarkAllAsUnreadSelectionAllEmailsInteractor(); final moveAllSelectionAllEmailsInteractor = MockMoveAllSelectionAllEmailsInteractor(); final deleteAllPermanentlyEmailsInteractor = MockDeleteAllPermanentlyEmailsInteractor(); + final markAllAsStarredSelectionAllEmailsInteractor = MockMarkAllAsStarredSelectionAllEmailsInteractor(); late MailboxController mailboxController; // mock thread controller direct dependencies @@ -326,6 +329,7 @@ void main() { Get.put(markAllAsUnreadSelectionAllEmailsInteractor); Get.put(moveAllSelectionAllEmailsInteractor); Get.put(deleteAllPermanentlyEmailsInteractor); + Get.put(markAllAsStarredSelectionAllEmailsInteractor); searchController = SearchController( quickSearchEmailInteractor, @@ -364,6 +368,7 @@ void main() { markAllAsUnreadSelectionAllEmailsInteractor, moveAllSelectionAllEmailsInteractor, deleteAllPermanentlyEmailsInteractor, + markAllAsStarredSelectionAllEmailsInteractor, ); }); diff --git a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart index 161903891b..e24b0962c2 100644 --- a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart +++ b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart @@ -83,6 +83,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/empty_trash_folder import 'package:tmail_ui_user/features/thread/domain/usecases/get_email_by_id_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/get_emails_in_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/load_more_emails_in_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_starred_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_all_as_unread_selection_all_emails_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_multiple_email_read_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multiple_email_interactor.dart'; @@ -186,6 +187,7 @@ const fallbackGenerators = { MockSpec(), MockSpec(), MockSpec(), + MockSpec(), ]) void main() { final moveToMailboxInteractor = MockMoveToMailboxInteractor(); @@ -259,6 +261,7 @@ void main() { final markAllAsUnreadSelectionAllEmailsInteractor = MockMarkAllAsUnreadSelectionAllEmailsInteractor(); final moveAllSelectionAllEmailsInteractor = MockMoveAllSelectionAllEmailsInteractor(); final deleteAllPermanentlyEmailsInteractor = MockDeleteAllPermanentlyEmailsInteractor(); + final markAllAsStarredSelectionAllEmailsInteractor = MockMarkAllAsStarredSelectionAllEmailsInteractor(); final getEmailsInMailboxInteractor = MockGetEmailsInMailboxInteractor(); final refreshChangesEmailsInMailboxInteractor = MockRefreshChangesEmailsInMailboxInteractor(); @@ -324,6 +327,7 @@ void main() { Get.put(markAllAsUnreadSelectionAllEmailsInteractor); Get.put(moveAllSelectionAllEmailsInteractor); Get.put(deleteAllPermanentlyEmailsInteractor); + Get.put(markAllAsStarredSelectionAllEmailsInteractor); when(emailReceiveManager.pendingSharedFileInfo).thenAnswer((_) => BehaviorSubject.seeded([])); @@ -363,6 +367,7 @@ void main() { markAllAsUnreadSelectionAllEmailsInteractor, moveAllSelectionAllEmailsInteractor, deleteAllPermanentlyEmailsInteractor, + markAllAsStarredSelectionAllEmailsInteractor, ); Get.put(mailboxDashboardController); mailboxDashboardController.onReady();