diff --git a/lib/features/search/presentation/search_email_controller.dart b/lib/features/search/presentation/search_email_controller.dart index fcc43c130..400faee64 100644 --- a/lib/features/search/presentation/search_email_controller.dart +++ b/lib/features/search/presentation/search_email_controller.dart @@ -50,12 +50,11 @@ import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.da import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart'; +import 'package:tmail_ui_user/features/thread/presentation/extensions/list_presentation_email_extensions.dart'; import 'package:tmail_ui_user/features/thread/presentation/mixin/email_action_controller.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; -import 'package:tmail_ui_user/main/routes/navigation_router.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; -import 'package:tmail_ui_user/main/routes/route_utils.dart'; class SearchEmailController extends BaseController with EmailActionController { @@ -232,7 +231,11 @@ class SearchEmailController extends BaseController final emailsAfterChanges = resultEmailSearchList; final newListEmail = emailsAfterChanges.combine(emailsBeforeChanges); - listResultSearch.value = newListEmail; + listResultSearch.value = newListEmail.syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + searchQuery: searchQuery, + isSearchEmailRunning: true + ); listResultSearch.refresh(); } @@ -295,7 +298,11 @@ class SearchEmailController extends BaseController final emailsAfterChanges = resultEmailSearchList; final newListEmail = emailsAfterChanges.combine(emailsBeforeChanges); - listResultSearch.value = newListEmail; + listResultSearch.value = newListEmail.syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + searchQuery: searchQuery, + isSearchEmailRunning: true + ); if (resultSearchScrollController.hasClients) { resultSearchScrollController.animateTo( @@ -336,7 +343,12 @@ class SearchEmailController extends BaseController final resultEmailSearchList = success.emailList .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) .where((email) => !listResultSearch.contains(email)) - .toList(); + .toList() + .syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + searchQuery: searchQuery, + isSearchEmailRunning: true + ); listResultSearch.addAll(resultEmailSearchList); } else { canSearchMore = false; @@ -646,7 +658,7 @@ class SearchEmailController extends BaseController if (mailboxContain?.isDrafts == true) { editEmail(selectedEmail); } else { - previewEmail(context, selectedEmail); + previewEmail(selectedEmail); } break; case EmailActionType.selection: @@ -771,23 +783,6 @@ class SearchEmailController extends BaseController } } - PresentationEmail generateEmailByPlatform(PresentationEmail currentEmail) { - if (BuildUtils.isWeb) { - final route = RouteUtils.generateRouteBrowser( - AppRoutes.dashboard, - NavigationRouter( - emailId: currentEmail.id, - searchQuery: searchQuery, - dashboardType: DashboardType.search - ) - ); - final emailOnWeb = currentEmail.withRouteWeb(route); - return emailOnWeb; - } else { - return currentEmail; - } - } - @override void onClose() { textInputSearchController.dispose(); diff --git a/lib/features/search/presentation/search_email_view.dart b/lib/features/search/presentation/search_email_view.dart index ddbacddac..4f51c66d9 100644 --- a/lib/features/search/presentation/search_email_view.dart +++ b/lib/features/search/presentation/search_email_view.dart @@ -421,20 +421,19 @@ class SearchEmailView extends GetWidget itemExtent: _getItemExtent(context), itemCount: listPresentationEmail.length, itemBuilder: (context, index) { - final mailboxContain = _getMailboxContain(listPresentationEmail[index]); - final newPresentationEmail = controller.generateEmailByPlatform(listPresentationEmail[index]); + final currentPresentationEmail = listPresentationEmail[index]; return Obx(() => (EmailTileBuilder( context, - newPresentationEmail, + currentPresentationEmail, controller.selectionMode.value, controller.searchQuery, - controller.mailboxDashBoardController.selectedEmail.value?.id == newPresentationEmail.id, + controller.mailboxDashBoardController.selectedEmail.value?.id == currentPresentationEmail.id, isSearchEmailRunning: true, padding: SearchEmailUtils.getPaddingSearchResultList(context, _responsiveUtils), paddingDivider: SearchEmailUtils.getPaddingDividerSearchResultList(context, _responsiveUtils), - mailboxContain: mailboxContain) + mailboxContain: currentPresentationEmail.mailboxContain) ..addOnPressEmailActionClick((action, email) => - controller.pressEmailAction(context, action, email, mailboxContain: mailboxContain)) + controller.pressEmailAction(context, action, email, mailboxContain: currentPresentationEmail.mailboxContain)) ..addOnMoreActionClick((email, position) => _responsiveUtils.isScreenWithShortestSide(context) ? controller.openContextMenuAction(context, _contextMenuActionTile(context, email)) : controller.openPopupMenuAction(context, position, _popupMenuActionTile(context, email))) @@ -443,10 +442,6 @@ class SearchEmailView extends GetWidget ); } - PresentationMailbox? _getMailboxContain(PresentationEmail currentEmail) { - return currentEmail.findMailboxContain(controller.mailboxDashBoardController.mapMailboxById); - } - double? _getItemExtent(BuildContext context) { if (BuildUtils.isWeb) { return _responsiveUtils.isDesktop(context) ? 52 : 95; @@ -472,7 +467,7 @@ class SearchEmailView extends GetWidget } Widget _markAsEmailSpamOrUnSpamAction(BuildContext context, PresentationEmail email) { - final mailboxContain = _getMailboxContain(email); + final mailboxContain = email.mailboxContain; return (EmailActionCupertinoActionSheetActionBuilder( const Key('mark_as_spam_or_un_spam_action'), diff --git a/lib/features/thread/presentation/extensions/list_presentation_email_extensions.dart b/lib/features/thread/presentation/extensions/list_presentation_email_extensions.dart new file mode 100644 index 000000000..5a4a44110 --- /dev/null +++ b/lib/features/thread/presentation/extensions/list_presentation_email_extensions.dart @@ -0,0 +1,59 @@ + +import 'package:core/utils/build_utils.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:model/extensions/presentation_email_extension.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; +import 'package:tmail_ui_user/main/routes/app_routes.dart'; +import 'package:tmail_ui_user/main/routes/navigation_router.dart'; +import 'package:tmail_ui_user/main/routes/route_utils.dart'; + +extension ListPresentationEmailExtensions on List { + + List syncPresentationEmail({ + required Map mapMailboxById, + PresentationMailbox? selectedMailbox, + bool isSearchEmailRunning = false, + SearchQuery? searchQuery + }) { + final newEmailList = map((presentationEmail) { + final routeUri = _generateNavigationRoute( + currentEmail: presentationEmail, + selectedMailbox: selectedMailbox, + isSearchEmailRunning: isSearchEmailRunning, + searchQuery: searchQuery + ); + final mailboxContain = presentationEmail.findMailboxContain(mapMailboxById); + + return presentationEmail.syncPresentationEmail( + mailboxContain: mailboxContain, + routeWeb: routeUri + ); + }).toList(); + + return newEmailList; + } + + Uri? _generateNavigationRoute({ + required PresentationEmail currentEmail, + PresentationMailbox? selectedMailbox, + bool isSearchEmailRunning = false, + SearchQuery? searchQuery, + }) { + if (BuildUtils.isWeb) { + final route = RouteUtils.generateRouteBrowser( + AppRoutes.dashboard, + NavigationRouter( + emailId: currentEmail.id, + mailboxId: selectedMailbox?.id, + searchQuery: isSearchEmailRunning ? searchQuery : null, + dashboardType: isSearchEmailRunning ? DashboardType.search : DashboardType.normal + ) + ); + return route; + } else { + return null; + } + } +} \ No newline at end of file diff --git a/lib/features/thread/presentation/mixin/email_action_controller.dart b/lib/features/thread/presentation/mixin/email_action_controller.dart index a0f7203c6..6723c32a3 100644 --- a/lib/features/thread/presentation/mixin/email_action_controller.dart +++ b/lib/features/thread/presentation/mixin/email_action_controller.dart @@ -24,12 +24,10 @@ import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_reques import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; -import 'package:tmail_ui_user/main/routes/route_utils.dart'; import 'package:url_launcher/url_launcher.dart'; mixin EmailActionController on ViewAsDialogActionMixin { @@ -47,15 +45,9 @@ mixin EmailActionController on ViewAsDialogActionMixin { mailboxDashBoardController.goToComposer(arguments); } - void previewEmail(BuildContext context, PresentationEmail presentationEmail) { + void previewEmail(PresentationEmail presentationEmail) { log('EmailActionController::previewEmail():presentationEmailId: ${presentationEmail.id}'); - mailboxDashBoardController.setSelectedEmail(presentationEmail); - mailboxDashBoardController.dispatchRoute(DashboardRoutes.emailDetailed); - if (BuildUtils.isWeb && presentationEmail.routeWeb != null) { - RouteUtils.updateRouteOnBrowser( - 'Email-${presentationEmail.id.id.value}', - presentationEmail.routeWeb!); - } + mailboxDashBoardController.openEmailDetailedView(presentationEmail); } void moveToTrash(PresentationEmail email, {PresentationMailbox? mailboxContain}) async { diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 584bb82b8..f1a92ee6e 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -57,6 +57,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/load_more_emails_i import 'package:tmail_ui_user/features/thread/domain/usecases/refresh_changes_emails_in_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart'; import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart'; +import 'package:tmail_ui_user/features/thread/presentation/extensions/list_presentation_email_extensions.dart'; import 'package:tmail_ui_user/features/thread/presentation/mixin/email_action_controller.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart'; @@ -369,7 +370,13 @@ class ThreadController extends BaseController with EmailActionController { void _getAllEmailSuccess(GetAllEmailSuccess success) { _currentEmailState = success.currentEmailState; log('ThreadController::_getAllEmailSuccess():_currentEmailState: $_currentEmailState'); - emailList.value = success.emailList; + emailList.value = success.emailList.syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + selectedMailbox: currentMailbox, + searchQuery: searchController.searchQuery, + isSearchEmailRunning: searchController.isSearchEmailRunning + ); + if (listEmailController.hasClients) { listEmailController.animateTo(0, duration: const Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); } @@ -381,7 +388,12 @@ class ThreadController extends BaseController with EmailActionController { final emailsBeforeChanges = emailList; final emailsAfterChanges = success.emailList; final newListEmail = emailsAfterChanges.combine(emailsBeforeChanges); - emailList.value = newListEmail; + emailList.value = newListEmail.syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + selectedMailbox: currentMailbox, + searchQuery: searchController.searchQuery, + isSearchEmailRunning: searchController.isSearchEmailRunning + ); if (emailList.isEmpty) { refreshAllEmail(); @@ -497,7 +509,14 @@ class ThreadController extends BaseController with EmailActionController { if (success.emailList.isNotEmpty) { final appendableList = success.emailList .where(_belongToCurrentMailboxId) - .where(_notDuplicatedInCurrentList); + .where(_notDuplicatedInCurrentList) + .toList() + .syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + selectedMailbox: currentMailbox, + searchQuery: searchController.searchQuery, + isSearchEmailRunning: searchController.isSearchEmailRunning + ); emailList.addAll(appendableList); } else { @@ -662,7 +681,12 @@ class ThreadController extends BaseController with EmailActionController { final emailsSearchBeforeChanges = emailList; final emailsSearchAfterChanges = resultEmailSearchList; final newListEmailSearch = emailsSearchAfterChanges.combine(emailsSearchBeforeChanges); - emailList.value = newListEmailSearch; + emailList.value = newListEmailSearch.syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + selectedMailbox: currentMailbox, + searchQuery: searchController.searchQuery, + isSearchEmailRunning: searchController.isSearchEmailRunning + ); searchController.autoFocus.value = true; } @@ -685,7 +709,13 @@ class ThreadController extends BaseController with EmailActionController { final resultEmailSearchList = success.emailList .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) .where((email) => !emailList.contains(email)) - .toList(); + .toList() + .syncPresentationEmail( + mapMailboxById: mailboxDashBoardController.mapMailboxById, + selectedMailbox: currentMailbox, + searchQuery: searchController.searchQuery, + isSearchEmailRunning: searchController.isSearchEmailRunning + ); emailList.addAll(resultEmailSearchList); } else { canSearchMore = false; @@ -773,7 +803,7 @@ class ThreadController extends BaseController with EmailActionController { if (mailboxContain?.isDrafts == true) { editEmail(selectedEmail); } else { - previewEmail(context, selectedEmail); + previewEmail(selectedEmail); } break; case EmailActionType.selection: @@ -875,10 +905,6 @@ class ThreadController extends BaseController with EmailActionController { } } - PresentationMailbox? getMailboxContain(PresentationEmail currentEmail) { - return currentEmail.findMailboxContain(mailboxDashBoardController.mapMailboxById); - } - void _getEmailByIdAction(EmailId emailId) { if (_accountId != null) { consumeState(_getEmailByIdInteractor.execute( diff --git a/lib/features/thread/presentation/thread_view.dart b/lib/features/thread/presentation/thread_view.dart index 1bea91487..fa084421f 100644 --- a/lib/features/thread/presentation/thread_view.dart +++ b/lib/features/thread/presentation/thread_view.dart @@ -339,21 +339,20 @@ class ThreadView extends GetWidget itemExtent: _getItemExtent(context), itemCount: listPresentationEmail.length, itemBuilder: (context, index) { - final mailboxContain = controller.getMailboxContain(listPresentationEmail[index]); - final newPresentationEmail = controller.generateEmailByPlatform(listPresentationEmail[index]); + final currentPresentationEmail = listPresentationEmail[index]; return Obx(() => Draggable>( maxSimultaneousDrags: kIsWeb ? null : 0, data: controller.listEmailDrag, child: (EmailTileBuilder( context, - newPresentationEmail, + currentPresentationEmail, controller.mailboxDashBoardController.currentSelectMode.value, controller.searchQuery, - controller.mailboxDashBoardController.selectedEmail.value?.id == newPresentationEmail.id, - mailboxContain: mailboxContain, + controller.mailboxDashBoardController.selectedEmail.value?.id == currentPresentationEmail.id, + mailboxContain: currentPresentationEmail.mailboxContain, isSearchEmailRunning: controller.searchController.isSearchEmailRunning) ..addOnPressEmailActionClick((action, email) => - controller.pressEmailAction(context, action, email, mailboxContain: mailboxContain)) + controller.pressEmailAction(context, action, email, mailboxContain: currentPresentationEmail.mailboxContain)) ..addOnMoreActionClick((email, position) => _responsiveUtils.isScreenWithShortestSide(context) ? controller.openContextMenuAction(context, _contextMenuActionTile(context, email)) : controller.openPopupMenuAction(context, position, _popupMenuActionTile(context, email))) @@ -361,17 +360,17 @@ class ThreadView extends GetWidget feedback: _buildFeedBackWidget(context), childWhenDragging: (EmailTileBuilder( context, - newPresentationEmail, + currentPresentationEmail, controller.mailboxDashBoardController.currentSelectMode.value, controller.searchQuery, - controller.mailboxDashBoardController.selectedEmail.value?.id == newPresentationEmail.id, - mailboxContain: mailboxContain, + controller.mailboxDashBoardController.selectedEmail.value?.id == currentPresentationEmail.id, + mailboxContain: currentPresentationEmail.mailboxContain, isSearchEmailRunning: controller.searchController.isSearchEmailRunning, isDrag: true) ).build(), dragAnchorStrategy: pointerDragAnchorStrategy, onDragStarted: () { - controller.calculateDragValue(newPresentationEmail); + controller.calculateDragValue(currentPresentationEmail); }, )); }), @@ -500,7 +499,7 @@ class ThreadView extends GetWidget } List _contextMenuActionTile(BuildContext context, PresentationEmail email) { - final mailboxContain = controller.getMailboxContain(email); + final mailboxContain = email.mailboxContain; return [ _openInNewTabContextMenuItemAction(context, email), @@ -565,7 +564,7 @@ class ThreadView extends GetWidget } List _popupMenuActionTile(BuildContext context, PresentationEmail email) { - final mailboxContain = controller.getMailboxContain(email); + final mailboxContain = email.mailboxContain; return [ _buildOpenInNewTabPopupMenuItem(context, email, mailboxContain), diff --git a/model/lib/email/presentation_email.dart b/model/lib/email/presentation_email.dart index f78fc51f4..532f6b214 100644 --- a/model/lib/email/presentation_email.dart +++ b/model/lib/email/presentation_email.dart @@ -8,6 +8,7 @@ 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/extensions/email_address_extension.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/select_mode.dart'; class PresentationEmail with EquatableMixin { @@ -29,6 +30,7 @@ class PresentationEmail with EquatableMixin { final List? mailboxNames; final SelectMode selectMode; final Uri? routeWeb; + final PresentationMailbox? mailboxContain; PresentationEmail( this.id, @@ -48,7 +50,8 @@ class PresentationEmail with EquatableMixin { this.mailboxIds, this.mailboxNames, this.selectMode = SelectMode.INACTIVE, - this.routeWeb + this.routeWeb, + this.mailboxContain } ); @@ -95,6 +98,7 @@ class PresentationEmail with EquatableMixin { mailboxIds, mailboxNames, selectMode, - routeWeb + routeWeb, + mailboxContain ]; } \ No newline at end of file diff --git a/model/lib/extensions/email_extension.dart b/model/lib/extensions/email_extension.dart index b67b78a00..f525f561a 100644 --- a/model/lib/extensions/email_extension.dart +++ b/model/lib/extensions/email_extension.dart @@ -1,5 +1,4 @@ -import 'package:http_parser/http_parser.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/email/email_body_part.dart'; @@ -25,7 +24,7 @@ extension EmailExtension on Email { } Set getRecipientEmailAddressList() { - final listEmailAddress = Set(); + final listEmailAddress = {}; final listToAddress = to.getListAddress() ?? []; final listCcAddress = cc.getListAddress() ?? []; final listBccAddress = bcc.getListAddress() ?? []; @@ -100,11 +99,7 @@ extension EmailExtension on Email { ?.where((emailBody) => emailBody.partId != null && emailBody.type != null) .toList() ?? []; - final mapHtmlBody = Map.fromIterable( - newHtmlBody, - key: (emailBody) => emailBody.partId!, - value: (emailBody) => emailBody.type!, - ); + final mapHtmlBody = { for (var emailBody in newHtmlBody) emailBody.partId! : emailBody.type! }; final emailContents = bodyValues?.entries .map((entries) => EmailContent(mapHtmlBody[entries.key].toEmailContentType(), entries.value.value)) diff --git a/model/lib/extensions/presentation_email_extension.dart b/model/lib/extensions/presentation_email_extension.dart index 59fb398eb..857626eed 100644 --- a/model/lib/extensions/presentation_email_extension.dart +++ b/model/lib/extensions/presentation_email_extension.dart @@ -35,23 +35,24 @@ extension PresentationEmailExtension on PresentationEmail { PresentationEmail toggleSelect() { return PresentationEmail( - this.id, - keywords: keywords, - 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 == SelectMode.INACTIVE ? SelectMode.ACTIVE : SelectMode.INACTIVE, - routeWeb: routeWeb + this.id, + keywords: keywords, + 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 == SelectMode.INACTIVE ? SelectMode.ACTIVE : SelectMode.INACTIVE, + routeWeb: routeWeb, + mailboxContain: mailboxContain ); } @@ -73,7 +74,8 @@ extension PresentationEmailExtension on PresentationEmail { mailboxIds: mailboxIds, mailboxNames: mailboxNames, selectMode: selectMode, - routeWeb: routeWeb + routeWeb: routeWeb, + mailboxContain: mailboxContain ); } @@ -155,7 +157,8 @@ extension PresentationEmailExtension on PresentationEmail { mailboxIds: mailboxIds, mailboxNames: listMailboxName, selectMode: selectMode, - routeWeb: routeWeb + routeWeb: routeWeb, + mailboxContain: mailboxContain ); } @@ -190,7 +193,8 @@ extension PresentationEmailExtension on PresentationEmail { mailboxIds: mailboxIds, mailboxNames: mailboxNames, selectMode: selectMode, - routeWeb: routeWeb + routeWeb: routeWeb, + mailboxContain: mailboxContain ); } @@ -212,7 +216,31 @@ extension PresentationEmailExtension on PresentationEmail { mailboxIds: mailboxIds, mailboxNames: mailboxNames, selectMode: selectMode, - routeWeb: routeWeb + routeWeb: routeWeb, + mailboxContain: mailboxContain + ); + } + + PresentationEmail syncPresentationEmail({PresentationMailbox? mailboxContain, Uri? routeWeb}) { + return PresentationEmail( + this.id, + keywords: keywords, + 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, + mailboxContain: mailboxContain ); } } \ No newline at end of file