diff --git a/lib/features/email/presentation/controller/email_supervisor_controller.dart b/lib/features/email/presentation/controller/email_supervisor_controller.dart index 04d21ecbf..e691fa898 100644 --- a/lib/features/email/presentation/controller/email_supervisor_controller.dart +++ b/lib/features/email/presentation/controller/email_supervisor_controller.dart @@ -20,6 +20,7 @@ class EmailSupervisorController extends BaseController { int currentIndexPageView = -1; final canGetNewerEmail = true.obs; final canGetOlderEmail = true.obs; + final supportedPageView = RxBool(true); Rxn get selectedEmail => mailboxDashBoardController.selectedEmail; Session? get sessionCurrent => mailboxDashBoardController.sessionCurrent; @@ -33,8 +34,6 @@ class EmailSupervisorController extends BaseController { } } - bool get supportedPageView => listEmail.isNotEmpty; - @override void onClose() { pageController?.dispose(); diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index 223e1f76c..d1c743b79 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -181,10 +181,12 @@ class SingleEmailController extends BaseController with AppLoaderMixin { if (presentationEmail is PresentationEmail) { if (_currentEmailId != presentationEmail.id) { _currentEmailId = presentationEmail.id; - if (emailSupervisorController.supportedPageView) { + if (emailSupervisorController.listEmail.isNotEmpty) { + emailSupervisorController.supportedPageView.value = true; emailSupervisorController.setCurrentPositionEmailInListEmail(_currentEmailId); _getEmailDeBouncer.value = emailSupervisorController.currentIndexPageView; } else { + emailSupervisorController.supportedPageView.value = false; _getEmailContentAction(presentationEmail.id); } _resetToOriginalValue(); @@ -364,9 +366,13 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } PresentationMailbox? getMailboxContain(PresentationEmail email) { - return mailboxDashBoardController.searchController.isSearchEmailRunning + if (mailboxDashBoardController.selectedMailbox.value == null) { + return email.findMailboxContain(mailboxDashBoardController.mapMailboxById); + } else { + return mailboxDashBoardController.searchController.isSearchEmailRunning ? email.findMailboxContain(mailboxDashBoardController.mapMailboxById) : mailboxDashBoardController.selectedMailbox.value; + } } void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions) async { @@ -378,6 +384,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _markAsEmailReadSuccess(Success success) { + log('SingleEmailController::_markAsEmailReadSuccess(): $success'); mailboxDashBoardController.dispatchState(Right(success)); if (success is MarkAsEmailReadSuccess @@ -744,7 +751,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void _markAsEmailStarSuccess(Success success) { if (success is MarkAsStarEmailSuccess) { - mailboxDashBoardController.setSelectedEmail(success.updatedEmail.toPresentationEmail(selectMode: SelectMode.ACTIVE)); + final selectedEmail = mailboxDashBoardController.selectedEmail.value; + mailboxDashBoardController.setSelectedEmail(selectedEmail?.updateKeywords(success.updatedEmail.keywords)); } mailboxDashBoardController.dispatchState(Right(success)); } @@ -992,7 +1000,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void closeEmailView(BuildContext context) { log('SingleEmailController::closeEmailView(): '); - if (emailSupervisorController.supportedPageView) { + if (emailSupervisorController.supportedPageView.isTrue) { emailSupervisorController.presentationEmailsLoaded.removeWhere((e) => e.emailCurrent?.id == currentEmail?.id); emailSupervisorController.currentIndexPageView = -1; _getEmailDeBouncer.value = null; @@ -1015,10 +1023,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } - bool get isOpenEmailNotMailboxFromRoute => !emailSupervisorController.supportedPageView + bool get isOpenEmailNotMailboxFromRoute => emailSupervisorController.supportedPageView.isFalse && mailboxDashBoardController.selectedMailbox.value == null; void _updateRouteOnBrowser() { + log('SingleEmailController::_updateRouteOnBrowser(): isSearchEmailRunning: ${mailboxDashBoardController.searchController.isSearchEmailRunning}'); if (BuildUtils.isWeb) { final selectedMailboxId = mailboxDashBoardController.selectedMailbox.value?.id; final route = RouteUtils.generateRouteBrowser( diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index e7b0a463f..2b7c4b82a 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -88,9 +88,11 @@ class EmailView extends GetWidget { _buildAppBar(context, email), _buildVacationNotificationMessage(context), const Divider(color: AppColor.colorDividerHorizontal, height: 1), - Expanded(child: controller.emailSupervisorController.supportedPageView - ? _buildMultipleEmailView(controller.emailSupervisorController.listEmail) - : _buildSingleEmailView(context, email), + Expanded(child: Obx(() { + return controller.emailSupervisorController.supportedPageView.isTrue + ? _buildMultipleEmailView(controller.emailSupervisorController.listEmail) + : _buildSingleEmailView(context, email); + }), ), const Divider(color: AppColor.colorDividerHorizontal, height: 1), _buildBottomBar(context, email), @@ -98,6 +100,7 @@ class EmailView extends GetWidget { } Widget _buildMultipleEmailView(List listEmails) { + log('EmailView::_buildMultipleEmailView(): '); return PageView.builder( physics: BuildUtils.isWeb ? const NeverScrollableScrollPhysics() : null, itemCount: listEmails.length, @@ -108,6 +111,7 @@ class EmailView extends GetWidget { } Widget _buildSingleEmailView(BuildContext context, PresentationEmail email) { + log('EmailView::_buildSingleEmailView(): '); return _buildEmailBody(context, email); } @@ -144,7 +148,7 @@ class EmailView extends GetWidget { Widget _buildAppBar(BuildContext context, PresentationEmail presentationEmail) { return Obx(() => AppBarMailWidgetBuilder( presentationEmail, - currentMailbox: controller.mailboxDashBoardController.selectedMailbox.value, + mailboxContain: _getMailboxContain(presentationEmail), isSearchIsRunning: controller.mailboxDashBoardController.searchController.isSearchEmailRunning, onBackActionClick: () => controller.closeEmailView(context), onEmailActionClick: (email, action) => @@ -161,12 +165,16 @@ class EmailView extends GetWidget { _popupMenuEmailActionTile(context, email)); } }, - optionsWidget: BuildUtils.isWeb && controller.emailSupervisorController.supportedPageView + optionsWidget: BuildUtils.isWeb && controller.emailSupervisorController.supportedPageView.isTrue ? _buildNavigatorPageViewWidgets(context) : null, )); } + PresentationMailbox? _getMailboxContain(PresentationEmail currentEmail) { + return currentEmail.findMailboxContain(controller.mailboxDashBoardController.mapMailboxById); + } + List _buildNavigatorPageViewWidgets(BuildContext context) { return [ buildIconWeb( diff --git a/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart b/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart index f0862a789..3587cc63b 100644 --- a/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart +++ b/lib/features/email/presentation/widgets/app_bar_mail_widget_builder.dart @@ -16,7 +16,7 @@ class AppBarMailWidgetBuilder extends StatelessWidget { final PresentationEmail _presentationEmail; final List? optionsWidget; - final PresentationMailbox? currentMailbox; + final PresentationMailbox? mailboxContain; final bool isSearchIsRunning; final OnBackActionClick? onBackActionClick; final OnEmailActionClick? onEmailActionClick; @@ -26,7 +26,7 @@ class AppBarMailWidgetBuilder extends StatelessWidget { this._presentationEmail, { Key? key, - this.currentMailbox, + this.mailboxContain, this.onBackActionClick, this.onEmailActionClick, this.onMoreActionClick, @@ -70,7 +70,7 @@ class AppBarMailWidgetBuilder extends StatelessWidget { constraints: BoxConstraints( maxWidth: _responsiveUtils.getSizeScreenWidth(context) - 250), child: Text( - currentMailbox?.name?.name.capitalizeFirstEach ?? '', + mailboxContain?.name?.name.capitalizeFirstEach ?? '', maxLines: 1, overflow: CommonTextStyle.defaultTextOverFlow, softWrap: CommonTextStyle.defaultSoftWrap, @@ -134,17 +134,17 @@ class AppBarMailWidgetBuilder extends StatelessWidget { buildIconWeb( icon: SvgPicture.asset( _imagePaths.icDeleteComposer, - color: currentMailbox?.role != PresentationMailbox.roleTrash + color: mailboxContain?.isTrash == false ? AppColor.colorTextButton : AppColor.colorDeletePermanentlyButton, width: BuildUtils.isWeb ? 18 : 20, height: BuildUtils.isWeb ? 18 : 20, fit: BoxFit.fill), - tooltip: currentMailbox?.role != PresentationMailbox.roleTrash + tooltip: mailboxContain?.isTrash == false ? AppLocalizations.of(context).move_to_trash : AppLocalizations.of(context).delete_permanently, onTap: () { - if (currentMailbox?.role != PresentationMailbox.roleTrash) { + if (mailboxContain?.isTrash == false) { onEmailActionClick?.call( _presentationEmail, EmailActionType.moveToTrash); diff --git a/lib/features/login/presentation/login_controller.dart b/lib/features/login/presentation/login_controller.dart index 340b8aab6..c9382b85b 100644 --- a/lib/features/login/presentation/login_controller.dart +++ b/lib/features/login/presentation/login_controller.dart @@ -194,7 +194,7 @@ class LoginController extends ReloadableController { @override void handleReloaded(Session session) { pushAndPop( - RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()), + RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()), arguments: session); } diff --git a/lib/features/mailbox/presentation/mailbox_controller.dart b/lib/features/mailbox/presentation/mailbox_controller.dart index a486a7b88..80f2a9552 100644 --- a/lib/features/mailbox/presentation/mailbox_controller.dart +++ b/lib/features/mailbox/presentation/mailbox_controller.dart @@ -177,8 +177,10 @@ class MailboxController extends BaseMailboxController { } }, (success) async { - if (success is GetAllMailboxSuccess || success is RefreshChangesAllMailboxSuccess) { + if (success is GetAllMailboxSuccess) { _initialMailboxVariableStorage(); + } else if (success is RefreshChangesAllMailboxSuccess) { + _initialMailboxVariableStorage(isRefreshChange: true); } else if (success is CreateNewMailboxSuccess) { _createNewMailboxSuccess(success); } else if (success is SearchMailboxSuccess) { @@ -315,10 +317,10 @@ class MailboxController extends BaseMailboxController { } } - void _initialMailboxVariableStorage() { + void _initialMailboxVariableStorage({bool isRefreshChange = false}) { _setMapMailbox(); _setOutboxMailbox(); - _selectMailboxDefault(); + _selectMailboxDefault(isRefreshChange: isRefreshChange); } void _setMapMailbox() { @@ -352,7 +354,7 @@ class MailboxController extends BaseMailboxController { } } - void _selectMailboxDefault() { + void _selectMailboxDefault({bool isRefreshChange = false}) { final mapDefaultMailbox = { for (var mailboxNode in defaultMailboxTree.value.root.childrenItems ?? List.empty()) mailboxNode.item.role!: mailboxNode.item @@ -385,24 +387,29 @@ class MailboxController extends BaseMailboxController { } } - if (isHasDataFromRoute) { - if (mailboxIdFromNavigationRouter != null) { - _selectMailboxFromRouter(); - } else if (emailIdFromNavigationRouter != null) { - mailboxDashBoardController.dispatchAction( - SelectEmailByIdAction( - emailIdFromNavigationRouter!, - mailboxIdFromNavigationRouter, - navigationRouter!.dashboardType - ) - ); + if (isRefreshChange) { + mailboxDashBoardController.setSelectedMailbox(mailboxSelected); + } else { + if (isHasDataFromRoute) { + log('MailboxController::_selectMailboxDefault(): isHasDataFromRoute is true:navigationRouter: $navigationRouter'); + if (mailboxIdFromNavigationRouter != null) { + _selectMailboxFromRouter(); + } else if (emailIdFromNavigationRouter != null) { + mailboxDashBoardController.dispatchAction(SelectEmailByIdAction(navigationRouter!)); + _clearNavigationRouter(); + } else if (searchQueryFromNavigationRouter != null) { + mailboxDashBoardController.dispatchAction(SearchEmailByQueryAction(navigationRouter!)); + _clearNavigationRouter(); + } else { + _clearNavigationRouter(); + mailboxDashBoardController.setSelectedMailbox(mailboxSelected); + _updateSelectedMailboxRouteOnBrowser(); + } } else { + log('MailboxController::_selectMailboxDefault(): isHasDataFromRoute is false'); mailboxDashBoardController.setSelectedMailbox(mailboxSelected); _updateSelectedMailboxRouteOnBrowser(); } - } else { - mailboxDashBoardController.setSelectedMailbox(mailboxSelected); - _updateSelectedMailboxRouteOnBrowser(); } } @@ -414,6 +421,8 @@ class MailboxController extends BaseMailboxController { EmailId? get emailIdFromNavigationRouter => navigationRouter?.emailId; + SearchQuery? get searchQueryFromNavigationRouter => navigationRouter?.searchQuery; + void _clearNavigationRouter() { mailboxDashBoardController.navigationRouter = null; } @@ -423,13 +432,7 @@ class MailboxController extends BaseMailboxController { if (matchedMailboxNode != null) { mailboxDashBoardController.setSelectedMailbox(matchedMailboxNode.item); if (emailIdFromNavigationRouter != null) { - mailboxDashBoardController.dispatchAction( - SelectEmailByIdAction( - emailIdFromNavigationRouter!, - mailboxIdFromNavigationRouter, - navigationRouter!.dashboardType - ) - ); + mailboxDashBoardController.dispatchAction(SelectEmailByIdAction(navigationRouter!)); } else { _updateSelectedMailboxRouteOnBrowser(); } @@ -443,6 +446,7 @@ class MailboxController extends BaseMailboxController { BuildContext context, PresentationMailbox presentationMailboxSelected ) { + log('MailboxController::_handleOpenMailbox(): '); FocusScope.of(context).unfocus(); mailboxDashBoardController.clearSelectedEmail(); @@ -584,6 +588,7 @@ class MailboxController extends BaseMailboxController { } void _searchMailboxAction(List allMailboxes, SearchQuery searchQuery) { + log('MailboxController::_searchMailboxAction():'); if (searchQuery.value.isNotEmpty) { consumeState(_searchMailboxInteractor.execute(allMailboxes, searchQuery)); } else { @@ -1112,7 +1117,12 @@ class MailboxController extends BaseMailboxController { AppRoutes.dashboard, NavigationRouter( mailboxId: selectedMailboxId, - dashboardType: DashboardType.normal + searchQuery: mailboxDashBoardController.searchController.isSearchEmailRunning + ? mailboxDashBoardController.searchController.searchQuery + : null, + dashboardType: mailboxDashBoardController.searchController.isSearchEmailRunning + ? DashboardType.search + : DashboardType.normal ) ); RouteUtils.updateRouteOnBrowser('Mailbox-${selectedMailboxId?.id.value}', route); diff --git a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart index b71a19c6f..0f0b63721 100644 --- a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart +++ b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart @@ -1,7 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/email/presentation_email.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.dart'; @@ -116,12 +114,20 @@ class SelectMailboxDefaultAction extends DashBoardAction { class SelectEmailByIdAction extends DashBoardAction { - final EmailId emailId; - final MailboxId? mailboxId; - final DashboardType dashboardType; + final NavigationRouter navigationRouter; - SelectEmailByIdAction(this.emailId, this.mailboxId, this.dashboardType); + SelectEmailByIdAction(this.navigationRouter); @override - List get props => [emailId, mailboxId, dashboardType]; + List get props => [navigationRouter]; +} + +class SearchEmailByQueryAction extends DashBoardAction { + + final NavigationRouter navigationRouter; + + SearchEmailByQueryAction(this.navigationRouter); + + @override + List get props => [navigationRouter]; } \ No newline at end of file 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 da9a5749d..b506cd109 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -391,6 +391,7 @@ class MailboxDashBoardController extends ReloadableController { } void setSelectedEmail(PresentationEmail? newPresentationEmail) { + log('MailboxDashBoardController::setSelectedEmail(): $newPresentationEmail'); selectedEmail.value = newPresentationEmail; } @@ -440,6 +441,7 @@ class MailboxDashBoardController extends ReloadableController { } void _closeEmailDetailedView() { + log('MailboxDashBoardController::_closeEmailDetailedView(): '); dispatchRoute(DashboardRoutes.thread); clearSelectedEmail(); } @@ -1012,6 +1014,7 @@ class MailboxDashBoardController extends ReloadableController { } void dispatchRoute(DashboardRoutes route) { + log('MailboxDashBoardController::dispatchRoute(): $route'); dashboardRoute.value = route; if (dashboardRoute.value == DashboardRoutes.searchEmail) { diff --git a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart index ff11280fa..95517a767 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart @@ -40,6 +40,7 @@ class SearchController extends BaseController { final emailReceiveTimeType = Rxn(); final simpleSearchIsActivated = RxBool(false); final advancedSearchIsActivated = RxBool(false); + final autoFocus = RxBool(true); SearchQuery? get searchQuery => searchEmailFilter.value.text; diff --git a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart index 8f9e7f5ab..1c2b5c040 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart @@ -55,7 +55,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { suggestionsBoxVerticalOffset: 0.0, textFieldConfiguration: QuickSearchTextFieldConfiguration( controller: controller.searchInputController, - autofocus: true, + autofocus: controller.autoFocus.value, enabled: controller.isAdvancedSearchViewOpen.isFalse, focusNode: controller.searchFocus, textInputAction: TextInputAction.done, diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart index 6a770cad0..835711e1b 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart @@ -227,7 +227,7 @@ class ManageAccountDashBoardController extends ReloadableController { } else { log('ManageAccountDashBoardController::backToMailboxDashBoard(): canBack: FALSE'); pushAndPopAll( - RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()), + RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()), arguments: sessionCurrent); } } diff --git a/lib/features/search/presentation/search_email_controller.dart b/lib/features/search/presentation/search_email_controller.dart index 9694c0135..a2da184eb 100644 --- a/lib/features/search/presentation/search_email_controller.dart +++ b/lib/features/search/presentation/search_email_controller.dart @@ -584,6 +584,7 @@ class SearchEmailController extends BaseController } void closeSearchView(BuildContext context) { + log('SearchEmailController::closeSearchView(): '); clearAllTextInputSearchForm(); clearAllResultSearch(); FocusScope.of(context).unfocus(); @@ -623,17 +624,17 @@ class SearchEmailController extends BaseController markAsStarEmail(selectedEmail, MarkStarAction.unMarkStar); break; case EmailActionType.moveToMailbox: - moveToMailbox(context, selectedEmail); + moveToMailbox(context, selectedEmail, mailboxContain: mailboxContain); break; case EmailActionType.moveToTrash: - moveToTrash(selectedEmail); + moveToTrash(selectedEmail, mailboxContain: mailboxContain); break; case EmailActionType.deletePermanently: deleteEmailPermanently(context, selectedEmail); break; case EmailActionType.moveToSpam: popBack(); - moveToSpam(selectedEmail); + moveToSpam(selectedEmail, mailboxContain: mailboxContain); break; case EmailActionType.unSpam: popBack(); @@ -735,6 +736,7 @@ class SearchEmailController extends BaseController AppRoutes.dashboard, NavigationRouter( emailId: currentEmail.id, + searchQuery: searchQuery, dashboardType: DashboardType.search ) ); diff --git a/lib/features/session/presentation/session_controller.dart b/lib/features/session/presentation/session_controller.dart index 074f903d7..a5d295aa3 100644 --- a/lib/features/session/presentation/session_controller.dart +++ b/lib/features/session/presentation/session_controller.dart @@ -58,7 +58,7 @@ class SessionController extends ReloadableController { @override void handleReloaded(Session session) { pushAndPop( - RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()), + RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()), arguments: session); } @@ -108,7 +108,7 @@ class SessionController extends ReloadableController { if (apiUrl.isNotEmpty) { _dynamicUrlInterceptors.changeBaseUrl(apiUrl); pushAndPop( - RouteUtils.generateRouteMobile(AppRoutes.dashboard, NavigationRouter()), + RouteUtils.generateNavigationRoute(AppRoutes.dashboard, NavigationRouter()), arguments: success.session); } else { _goToLogin(); diff --git a/lib/features/thread/domain/state/get_email_by_id_state.dart b/lib/features/thread/domain/state/get_email_by_id_state.dart index 16b3cc6b1..1bca59403 100644 --- a/lib/features/thread/domain/state/get_email_by_id_state.dart +++ b/lib/features/thread/domain/state/get_email_by_id_state.dart @@ -1,20 +1,16 @@ import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; -import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/presentation_email.dart'; -import 'package:tmail_ui_user/main/routes/navigation_router.dart'; class GetEmailByIdLoading extends LoadingState {} class GetEmailByIdSuccess extends UIState { final PresentationEmail email; - final MailboxId? mailboxId; - final DashboardType dashboardType; - GetEmailByIdSuccess(this.email, this.mailboxId, this.dashboardType); + GetEmailByIdSuccess(this.email); @override - List get props => [email, mailboxId, dashboardType]; + List get props => [email]; } class GetEmailByIdFailure extends FeatureFailure { diff --git a/lib/features/thread/domain/usecases/get_email_by_id_interactor.dart b/lib/features/thread/domain/usecases/get_email_by_id_interactor.dart index 1416797e7..91c2a9f30 100644 --- a/lib/features/thread/domain/usecases/get_email_by_id_interactor.dart +++ b/lib/features/thread/domain/usecases/get_email_by_id_interactor.dart @@ -4,10 +4,8 @@ import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/state/get_email_by_id_state.dart'; -import 'package:tmail_ui_user/main/routes/navigation_router.dart'; class GetEmailByIdInteractor { final ThreadRepository _threadRepository; @@ -18,15 +16,13 @@ class GetEmailByIdInteractor { AccountId accountId, EmailId emailId, { - MailboxId? mailboxId, - DashboardType dashboardType = DashboardType.normal, Properties? properties, } ) async* { try { yield Right(GetEmailByIdLoading()); final email = await _threadRepository.getEmailById(accountId, emailId, properties: properties); - yield Right(GetEmailByIdSuccess(email, mailboxId, dashboardType)); + yield Right(GetEmailByIdSuccess(email)); } catch (e) { yield Left(GetEmailByIdFailure(e)); } diff --git a/lib/features/thread/presentation/mixin/email_action_controller.dart b/lib/features/thread/presentation/mixin/email_action_controller.dart index 832b9d572..a6a60ea65 100644 --- a/lib/features/thread/presentation/mixin/email_action_controller.dart +++ b/lib/features/thread/presentation/mixin/email_action_controller.dart @@ -4,6 +4,7 @@ import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:core/utils/build_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -46,6 +47,7 @@ mixin EmailActionController on ViewAsDialogActionMixin { } void previewEmail(BuildContext context, PresentationEmail presentationEmail) { + log('EmailActionController::previewEmail():presentationEmailId: ${presentationEmail.id}'); mailboxDashBoardController.setSelectedEmail(presentationEmail); mailboxDashBoardController.dispatchRoute(DashboardRoutes.emailDetailed); if (BuildUtils.isWeb && presentationEmail.routeWeb != null) { @@ -55,14 +57,13 @@ mixin EmailActionController on ViewAsDialogActionMixin { } } - void moveToTrash(PresentationEmail email) async { - final currentMailbox = mailboxDashBoardController.selectedMailbox.value; + void moveToTrash(PresentationEmail email, {PresentationMailbox? mailboxContain}) async { final accountId = mailboxDashBoardController.accountId.value; final trashMailboxId = mailboxDashBoardController.mapDefaultMailboxIdByRole[PresentationMailbox.roleTrash]; - if (currentMailbox != null && accountId != null && trashMailboxId != null) { + if (mailboxContain != null && accountId != null && trashMailboxId != null) { _moveToTrashAction(accountId, MoveToMailboxRequest( - {currentMailbox.id: [email.id]}, + {mailboxContain.id: [email.id]}, trashMailboxId, MoveAction.moving, mailboxDashBoardController.sessionCurrent!, @@ -75,14 +76,13 @@ mixin EmailActionController on ViewAsDialogActionMixin { mailboxDashBoardController.moveToMailbox(accountId, moveRequest); } - void moveToSpam(PresentationEmail email) async { - final currentMailbox = mailboxDashBoardController.selectedMailbox.value; + void moveToSpam(PresentationEmail email, {PresentationMailbox? mailboxContain}) async { final accountId = mailboxDashBoardController.accountId.value; final spamMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleSpam); - if (currentMailbox != null && accountId != null && spamMailboxId != null) { + if (mailboxContain != null && accountId != null && spamMailboxId != null) { moveToSpamAction(accountId, MoveToMailboxRequest( - {currentMailbox.id: [email.id]}, + {mailboxContain.id: [email.id]}, spamMailboxId, MoveAction.moving, mailboxDashBoardController.sessionCurrent!, @@ -111,11 +111,14 @@ mixin EmailActionController on ViewAsDialogActionMixin { mailboxDashBoardController.moveToMailbox(accountId, moveRequest); } - void moveToMailbox(BuildContext context, PresentationEmail email) async { - final currentMailbox = mailboxDashBoardController.selectedMailbox.value; + void moveToMailbox( + BuildContext context, + PresentationEmail email, + {PresentationMailbox? mailboxContain} + ) async { final accountId = mailboxDashBoardController.accountId.value; - if (currentMailbox != null && accountId != null) { + if (mailboxContain != null && accountId != null) { final arguments = DestinationPickerArguments(accountId, MailboxActions.moveEmail); if (BuildUtils.isWeb) { @@ -129,7 +132,7 @@ mixin EmailActionController on ViewAsDialogActionMixin { accountId, mailboxDashBoardController.sessionCurrent!, email, - currentMailbox, + mailboxContain, destinationMailbox); } }); @@ -146,7 +149,7 @@ mixin EmailActionController on ViewAsDialogActionMixin { accountId, mailboxDashBoardController.sessionCurrent!, email, - currentMailbox, + mailboxContain, destinationMailbox); } } diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index bbeba73f4..7457fd7fb 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -90,9 +90,9 @@ class ThreadController extends BaseController with EmailActionController { bool canLoadMore = true; bool canSearchMore = true; bool _isLoadingMore = false; - get isLoadingMore => _isLoadingMore; MailboxId? _currentMailboxId; jmap.State? _currentEmailState; + NavigationRouter? _navigationRouter; final ScrollController listEmailController = ScrollController(); final FocusNode focusNodeKeyBoard = FocusNode(); final latestEmailSelectedOrUnselected = Rxn(); @@ -102,6 +102,8 @@ class ThreadController extends BaseController with EmailActionController { ..add(EmailComparator(EmailComparatorProperty.receivedAt) ..setIsAscending(false)); + bool get isLoadingMore => _isLoadingMore; + AccountId? get _accountId => mailboxDashBoardController.accountId.value; PresentationMailbox? get currentMailbox => mailboxDashBoardController.selectedMailbox.value; @@ -157,6 +159,7 @@ class ThreadController extends BaseController with EmailActionController { _isLoadingMore = false; } else if (failure is GetEmailByIdFailure) { openingEmail.value = false; + _navigationRouter = null; } }, (success) { @@ -176,7 +179,7 @@ class ThreadController extends BaseController with EmailActionController { openingEmail.value = true; } else if (success is GetEmailByIdSuccess) { openingEmail.value = false; - _openEmailDetailView(success.email, success.mailboxId, success.dashboardType); + _openEmailDetailView(success.email); } } ); @@ -246,13 +249,22 @@ class ThreadController extends BaseController with EmailActionController { mailboxDashBoardController.clearDashBoardAction(); } else if (action is StartSearchEmailAction) { cancelSelectEmail(); + _updateSearchRouteOnBrowser(); _searchEmail(); mailboxDashBoardController.clearDashBoardAction(); } else if (action is EmptyTrashAction) { deleteSelectionEmailsPermanently(action.context, DeleteActionType.all); mailboxDashBoardController.clearDashBoardAction(); } else if (action is SelectEmailByIdAction) { - _getEmailByIdAction(action.emailId, action.mailboxId, action.dashboardType); + _navigationRouter = action.navigationRouter; + if (_navigationRouter!.searchQuery != null) { + _activateSearchFromRouter(); + } + _getEmailByIdAction(_navigationRouter!.emailId!); + mailboxDashBoardController.clearDashBoardAction(); + } else if (action is SearchEmailByQueryAction) { + _navigationRouter = action.navigationRouter; + _activateSearchFromRouter(); mailboxDashBoardController.clearDashBoardAction(); } }); @@ -312,6 +324,18 @@ class ThreadController extends BaseController with EmailActionController { viewStateWorker.dispose(); } + void _activateSearchFromRouter() { + searchController.autoFocus.value = false; + searchController.enableSearch(); + searchController.updateTextSearch(_navigationRouter!.searchQuery!.value); + searchController.updateFilterEmail(text: _navigationRouter!.searchQuery!); + if (currentContext != null) { + FocusScope.of(currentContext!).unfocus(); + } + searchController.searchFocus.unfocus(); + _searchEmail(); + } + void _handleErrorGetAllOrRefreshChangesEmail(dynamic error) async { logError('ThreadController::_handleErrorGetAllOrRefreshChangesEmail():Error: $error'); if (error is CannotCalculateChangesMethodResponseException) { @@ -334,7 +358,6 @@ class ThreadController extends BaseController with EmailActionController { canLoadMore = true; _isLoadingMore = false; cancelSelectEmail(); - mailboxDashBoardController.dispatchRoute(DashboardRoutes.thread); } void _getAllEmailSuccess(GetAllEmailSuccess success) { @@ -613,6 +636,18 @@ class ThreadController extends BaseController with EmailActionController { } } + void _updateSearchRouteOnBrowser() { + if (BuildUtils.isWeb) { + final route = RouteUtils.generateRouteBrowser( + AppRoutes.dashboard, + NavigationRouter( + searchQuery: searchQuery, + dashboardType: DashboardType.search) + ); + RouteUtils.updateRouteOnBrowser('SearchEmail', route); + } + } + void _searchEmailsSuccess(SearchEmailSuccess success) { final resultEmailSearchList = success.emailList .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) @@ -622,6 +657,7 @@ class ThreadController extends BaseController with EmailActionController { final emailsSearchAfterChanges = resultEmailSearchList; final newListEmailSearch = emailsSearchAfterChanges.combine(emailsSearchBeforeChanges); emailList.value = newListEmailSearch; + searchController.autoFocus.value = true; } void searchMoreEmails() { @@ -750,17 +786,17 @@ class ThreadController extends BaseController with EmailActionController { markAsStarEmail(selectedEmail, MarkStarAction.unMarkStar); break; case EmailActionType.moveToMailbox: - moveToMailbox(context, selectedEmail); + moveToMailbox(context, selectedEmail, mailboxContain: mailboxContain); break; case EmailActionType.moveToTrash: - moveToTrash(selectedEmail); + moveToTrash(selectedEmail, mailboxContain: mailboxContain); break; case EmailActionType.deletePermanently: deleteEmailPermanently(context, selectedEmail); break; case EmailActionType.moveToSpam: popBack(); - moveToSpam(selectedEmail); + moveToSpam(selectedEmail, mailboxContain: mailboxContain); break; case EmailActionType.unSpam: popBack(); @@ -815,6 +851,9 @@ class ThreadController extends BaseController with EmailActionController { NavigationRouter( emailId: currentEmail.id, mailboxId: currentMailbox?.id, + searchQuery: searchController.isSearchEmailRunning + ? searchQuery + : null, dashboardType: searchController.isSearchEmailRunning ? DashboardType.search : DashboardType.normal @@ -827,30 +866,29 @@ class ThreadController extends BaseController with EmailActionController { } } - void _getEmailByIdAction(EmailId emailId, MailboxId? mailboxId, DashboardType dashboardType) { + PresentationMailbox? getMailboxContain(PresentationEmail currentEmail) { + return currentEmail.findMailboxContain(mailboxDashBoardController.mapMailboxById); + } + + void _getEmailByIdAction(EmailId emailId) { if (_accountId != null) { consumeState(_getEmailByIdInteractor.execute( _accountId!, emailId, - mailboxId: mailboxId, - dashboardType: dashboardType, properties: ThreadConstants.propertiesDefault)); } } - void _openEmailDetailView( - PresentationEmail email, - MailboxId? mailboxId, - DashboardType dashboardType - ) { + void _openEmailDetailView(PresentationEmail email) { if (currentContext != null) { final mailboxContain = email.findMailboxContain(mailboxDashBoardController.mapMailboxById); final route = RouteUtils.generateRouteBrowser( AppRoutes.dashboard, NavigationRouter( emailId: email.id, - mailboxId: mailboxId, - dashboardType: dashboardType + mailboxId: _navigationRouter?.mailboxId, + searchQuery: _navigationRouter?.searchQuery, + dashboardType: _navigationRouter?.dashboardType ?? DashboardType.normal ) ); pressEmailAction( @@ -860,5 +898,6 @@ class ThreadController extends BaseController with EmailActionController { mailboxContain: mailboxContain ); } + _navigationRouter = null; } } \ No newline at end of file diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 7e7326973..d281a729d 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -335,7 +335,7 @@ class ThreadView extends GetWidget with AppLoaderMixin, itemExtent: _getItemExtent(context), itemCount: listPresentationEmail.length, itemBuilder: (context, index) { - final mailboxContain = _getMailboxContain(listPresentationEmail[index]); + final mailboxContain = controller.getMailboxContain(listPresentationEmail[index]); final newPresentationEmail = controller.generateEmailByPlatform(listPresentationEmail[index]); return Obx(() => Draggable>( maxSimultaneousDrags: kIsWeb ? null : 0, @@ -375,12 +375,6 @@ class ThreadView extends GetWidget with AppLoaderMixin, ); } - PresentationMailbox? _getMailboxContain(PresentationEmail currentEmail) { - return controller.searchController.isSearchEmailRunning - ? currentEmail.findMailboxContain(controller.mailboxDashBoardController.mapMailboxById) - : controller.currentMailbox; - } - Widget _buildFeedBackWidget(BuildContext context) { return SizedBox( height: 60, @@ -508,7 +502,7 @@ class ThreadView extends GetWidget with AppLoaderMixin, } Widget _markAsEmailSpamOrUnSpamAction(BuildContext context, PresentationEmail email) { - final mailboxContain = _getMailboxContain(email); + final mailboxContain = controller.getMailboxContain(email); return (EmailActionCupertinoActionSheetActionBuilder( const Key('mark_as_spam_or_un_spam_action'), SvgPicture.asset( diff --git a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart index 27c30c1c7..635927ed8 100644 --- a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart @@ -421,7 +421,7 @@ class EmailTileBuilder with BaseEmailItemTile { : EmailActionType.markAsRead, _presentationEmail)), const SizedBox(width: 5), - if (mailboxContain?.isDrafts == false) + if (mailboxContain != null && mailboxContain?.isDrafts == false) ... [ buildIconWeb( minSize: 18, diff --git a/lib/main/routes/navigation_router.dart b/lib/main/routes/navigation_router.dart index 799592f25..368836fbb 100644 --- a/lib/main/routes/navigation_router.dart +++ b/lib/main/routes/navigation_router.dart @@ -2,6 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; enum DashboardType { normal, @@ -12,13 +13,15 @@ class NavigationRouter with EquatableMixin { final EmailId? emailId; final MailboxId? mailboxId; final DashboardType dashboardType; + final SearchQuery? searchQuery; NavigationRouter({ this.emailId, this.mailboxId, + this.searchQuery, this.dashboardType = DashboardType.normal }); @override - List get props => [emailId, mailboxId, dashboardType]; + List get props => [emailId, mailboxId, searchQuery, dashboardType]; } \ No newline at end of file diff --git a/lib/main/routes/route_utils.dart b/lib/main/routes/route_utils.dart index fec274944..a086f0380 100644 --- a/lib/main/routes/route_utils.dart +++ b/lib/main/routes/route_utils.dart @@ -1,4 +1,5 @@ +import 'package:core/core.dart'; import 'package:core/data/model/query/query_parameter.dart'; import 'package:core/data/network/config/service_path.dart'; import 'package:core/utils/app_logger.dart'; @@ -6,6 +7,7 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:tmail_ui_user/features/login/data/extensions/service_path_extension.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/main/routes/navigation_router.dart'; import 'package:universal_html/html.dart' as html; @@ -15,18 +17,23 @@ abstract class RouteUtils { static String get baseUrl => Uri.base.path; - static String generateRouteMobile(String route, NavigationRouter router) { + static String generateNavigationRoute(String route, NavigationRouter router) { ServicePath servicePath = ServicePath(route); - if (router.emailId != null) { - servicePath = servicePath.withPathParameter(router.emailId!.id.value); + if (BuildUtils.isWeb) { + if (router.emailId != null) { + servicePath = servicePath.withPathParameter(router.emailId!.id.value); + } + servicePath = servicePath.withQueryParameters([ + StringQueryParameter('type', router.dashboardType.name), + if (router.mailboxId != null) + StringQueryParameter('context', router.mailboxId!.id.value), + if (router.searchQuery != null) + StringQueryParameter('q', router.searchQuery!.value), + ]); + return servicePath.path; + } else { + return servicePath.path; } - servicePath = servicePath.withQueryParameters([ - StringQueryParameter('type', router.dashboardType.name), - if (router.mailboxId != null) - StringQueryParameter('context', router.mailboxId!.id.value), - ]); - - return servicePath.path; } static Uri generateRouteBrowser(String route, NavigationRouter router) { @@ -39,6 +46,8 @@ abstract class RouteUtils { StringQueryParameter('type', router.dashboardType.name), if (router.mailboxId != null) StringQueryParameter('context', router.mailboxId!.id.value), + if (router.searchQuery != null) + StringQueryParameter('q', router.searchQuery!.value), ]); return Uri.parse(servicePath.path); @@ -48,9 +57,11 @@ abstract class RouteUtils { final idParam = parameters['id']; final typeParam = parameters['type']; final contextPram = parameters['context']; + final queryParam = parameters['q']; final emailId = idParam != null ? EmailId(Id(idParam)) : null; final mailboxId = contextPram != null ? MailboxId(Id(contextPram)) : null; + final searchQuery = queryParam != null ? SearchQuery(queryParam) : null; final dashboardType = typeParam == DashboardType.search.name ? DashboardType.search : DashboardType.normal; @@ -58,6 +69,7 @@ abstract class RouteUtils { return NavigationRouter( emailId: emailId, mailboxId: mailboxId, + searchQuery: searchQuery, dashboardType: dashboardType, ); } diff --git a/model/lib/extensions/presentation_email_extension.dart b/model/lib/extensions/presentation_email_extension.dart index 70ad97ba1..462ada2ce 100644 --- a/model/lib/extensions/presentation_email_extension.dart +++ b/model/lib/extensions/presentation_email_extension.dart @@ -5,6 +5,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.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_action_type.dart'; import 'package:model/email/presentation_email.dart'; @@ -192,4 +193,26 @@ extension PresentationEmailExtension on PresentationEmail { routeWeb: routeWeb ); } + + PresentationEmail updateKeywords(Map? newKeywords) { + return PresentationEmail( + this.id, + keywords: newKeywords, + size: size, + receivedAt: receivedAt, + hasAttachment: hasAttachment, + preview: preview, + subject: subject, + sentAt: sentAt, + from: from, + to: to, + cc: cc, + bcc: bcc, + replyTo: replyTo, + mailboxIds: mailboxIds, + mailboxNames: mailboxNames, + selectMode: selectMode, + routeWeb: routeWeb + ); + } } \ No newline at end of file