From bc102dd9ec9e312f166c86ad722ee8dc57f63692 Mon Sep 17 00:00:00 2001 From: ManhNTX Date: Thu, 27 Oct 2022 16:23:36 +0700 Subject: [PATCH] TF-996: add previous / Next message of a mailbox on mobile/tablet --- .../email/domain/model/email_loaded.dart | 25 +++++++++ .../get_email_content_interactor.dart | 51 +++++++++++-------- .../email/presentation/email_controller.dart | 28 ++++++++-- .../email/presentation/email_view.dart | 16 ++++-- .../mailbox_dashboard_controller.dart | 1 + .../presentation/thread_controller.dart | 3 +- 6 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 lib/features/email/domain/model/email_loaded.dart diff --git a/lib/features/email/domain/model/email_loaded.dart b/lib/features/email/domain/model/email_loaded.dart new file mode 100644 index 000000000..9afa427f8 --- /dev/null +++ b/lib/features/email/domain/model/email_loaded.dart @@ -0,0 +1,25 @@ +import 'package:equatable/equatable.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:model/model.dart'; + +class EmailLoaded with EquatableMixin { + final List emailContents; + final List emailContentsDisplayed; + final List attachments; + final Email? emailCurrent; + + EmailLoaded( + this.emailContents, + this.emailContentsDisplayed, + this.attachments, + this.emailCurrent + ); + + @override + List get props => [ + emailContents, + emailContentsDisplayed, + attachments, + emailCurrent + ]; +} diff --git a/lib/features/email/domain/usecases/get_email_content_interactor.dart b/lib/features/email/domain/usecases/get_email_content_interactor.dart index 92dc0a600..646ba8ae9 100644 --- a/lib/features/email/domain/usecases/get_email_content_interactor.dart +++ b/lib/features/email/domain/usecases/get_email_content_interactor.dart @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/model.dart'; +import 'package:tmail_ui_user/features/email/domain/model/email_loaded.dart'; import 'package:tmail_ui_user/features/email/domain/repository/email_repository.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; @@ -12,31 +13,41 @@ class GetEmailContentInteractor { GetEmailContentInteractor(this.emailRepository); - Stream> execute(AccountId accountId, EmailId emailId, String? baseDownloadUrl) async* { + Stream> execute(AccountId accountId, EmailId emailId, String? baseDownloadUrl, {EmailLoaded? emailLoaded}) async* { try { yield Right(GetEmailContentLoading()); - final email = await emailRepository.getEmailContent(accountId, emailId); - if (email.emailContentList.isNotEmpty) { - final newEmailContents = await emailRepository.transformEmailContent( - email.emailContentList, - email.allAttachments.listAttachmentsDisplayedInContent, - baseDownloadUrl, - accountId); - final newEmailContentsDisplayed = kIsWeb - ? await emailRepository.addTooltipWhenHoverOnLink(newEmailContents) - : newEmailContents; + if(emailLoaded != null) { + await Future.delayed(const Duration(milliseconds: 300)); yield Right(GetEmailContentSuccess( - newEmailContents, - newEmailContentsDisplayed, - email.allAttachments, - email)); - } else if (email.allAttachments.isNotEmpty) { - yield Right(GetEmailContentSuccess([], [], email.allAttachments, email)); - } else if (email.headers?.isNotEmpty == true) { - yield Right(GetEmailContentSuccess([], [], [], email)); + emailLoaded.emailContents, + emailLoaded.emailContentsDisplayed, + emailLoaded.attachments, + emailLoaded.emailCurrent)); } else { - yield Left(GetEmailContentFailure(null)); + final email = await emailRepository.getEmailContent(accountId, emailId); + + if (email.emailContentList.isNotEmpty) { + final newEmailContents = await emailRepository.transformEmailContent( + email.emailContentList, + email.allAttachments.listAttachmentsDisplayedInContent, + baseDownloadUrl, + accountId); + final newEmailContentsDisplayed = kIsWeb + ? await emailRepository.addTooltipWhenHoverOnLink(newEmailContents) + : newEmailContents; + yield Right(GetEmailContentSuccess( + newEmailContents, + newEmailContentsDisplayed, + email.allAttachments, + email)); + } else if (email.allAttachments.isNotEmpty) { + yield Right(GetEmailContentSuccess([], [], email.allAttachments, email)); + } else if (email.headers?.isNotEmpty == true) { + yield Right(GetEmailContentSuccess([], [], [], email)); + } else { + yield Left(GetEmailContentFailure(null)); + } } } catch (e) { log('GetEmailContentInteractor::execute(): exception = $e'); diff --git a/lib/features/email/presentation/email_controller.dart b/lib/features/email/presentation/email_controller.dart index f6b18e0b1..0c9b19f24 100644 --- a/lib/features/email/presentation/email_controller.dart +++ b/lib/features/email/presentation/email_controller.dart @@ -26,6 +26,7 @@ import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; +import 'package:tmail_ui_user/features/email/domain/model/email_loaded.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/move_to_mailbox_request.dart'; import 'package:tmail_ui_user/features/email/domain/model/send_receipt_to_sender_request.dart'; @@ -89,9 +90,9 @@ class EmailController extends BaseController with AppLoaderMixin { EmailId? _currentEmailId; Identity? _identitySelected; List? initialEmailContents; - late Worker emailWorker; - + final Map presentationEmailsLoaded = {}; + PageController? pageController; final StreamController> _downloadProgressStateController = StreamController>.broadcast(); Stream> get downloadProgressState => _downloadProgressStateController.stream; @@ -141,18 +142,29 @@ class EmailController extends BaseController with AppLoaderMixin { super.onClose(); } + void _setCurrentPositionEmailInListEmail() { + pageController ??= PageController(initialPage: mailboxDashBoardController.emailList.indexOf(mailboxDashBoardController.selectedEmail.value)); + } + + void onPageChanged(int index) { + mailboxDashBoardController.selectedEmail.value = mailboxDashBoardController.emailList[index]; + } + void _initWorker() { emailWorker = ever(mailboxDashBoardController.selectedEmail, (presentationEmail) { log('EmailController::_initWorker(): $presentationEmail'); if (presentationEmail is PresentationEmail) { - if (_currentEmailId != presentationEmail.id) { + _setCurrentPositionEmailInListEmail(); + if (_currentEmailId != presentationEmail.id) { _currentEmailId = presentationEmail.id; _resetToOriginalValue(); _getEmailContentAction(presentationEmail.id); if (!presentationEmail.hasRead) { markAsEmailRead(presentationEmail, ReadActions.markAsRead); } - _getAllIdentities(); + if(_identitySelected == null) { + _getAllIdentities(); + } } } }); @@ -222,8 +234,13 @@ class EmailController extends BaseController with AppLoaderMixin { void _getEmailContentAction(EmailId emailId) async { final accountId = mailboxDashBoardController.accountId.value; final baseDownloadUrl = mailboxDashBoardController.sessionCurrent?.getDownloadUrl(); + final listEmailIdLoaded = presentationEmailsLoaded.keys.toList(); + EmailLoaded? emailLoaded; + if(listEmailIdLoaded.contains(_currentEmailId)) { + emailLoaded = presentationEmailsLoaded[_currentEmailId]; + } if (accountId != null && baseDownloadUrl != null) { - consumeState(_getEmailContentInteractor.execute(accountId, emailId, baseDownloadUrl)); + consumeState(_getEmailContentInteractor.execute(accountId, emailId, baseDownloadUrl, emailLoaded: emailLoaded)); } } @@ -263,6 +280,7 @@ class EmailController extends BaseController with AppLoaderMixin { } void _getEmailContentSuccess(GetEmailContentSuccess success) { + presentationEmailsLoaded[success.emailCurrent!.id] = EmailLoaded(success.emailContents.toList(), success.emailContentsDisplayed.toList(), success.attachments.toList(), success.emailCurrent); emailContents.value = success.emailContentsDisplayed; initialEmailContents = success.emailContents; attachments.value = success.attachments; diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index 2ea3a3f5c..51251907e 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -48,9 +48,9 @@ class EmailView extends GetWidget { child: Container( decoration: responsiveUtils.isWebDesktop(context) ? BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all(color: AppColor.colorBorderBodyThread, width: 1), - color: Colors.white) + borderRadius: BorderRadius.circular(20), + border: Border.all(color: AppColor.colorBorderBodyThread, width: 1), + color: Colors.white) : const BoxDecoration(color: Colors.white), margin: _getMarginEmailView(context), child: Obx(() { @@ -89,7 +89,15 @@ class EmailView extends GetWidget { _buildAppBar(context, email), _buildVacationNotificationMessage(context), const Divider(color: AppColor.colorDividerHorizontal, height: 1), - Expanded(child: _buildEmailBody(context, email)), + Expanded( + child: PageView.builder( + itemCount: controller.mailboxDashBoardController.emailList.length, + controller: controller.pageController, + onPageChanged: controller.onPageChanged, + itemBuilder: (context, _) { + return _buildEmailBody(context, email); + }), + ), const Divider(color: AppColor.colorDividerHorizontal, height: 1), _buildBottomBar(context, email), ]); 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 7d405be5b..b34de62e0 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -126,6 +126,7 @@ class MailboxDashBoardController extends ReloadableController { Session? sessionCurrent; Map mapDefaultMailboxIdByRole = {}; Map mapMailboxById = {}; + final emailList = [].obs; PresentationMailbox? outboxMailbox; RouterArguments? routerArguments; diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 4b14b3494..8abdd0686 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -99,7 +99,6 @@ class ThreadController extends BaseController { final MoveToMailboxInteractor _moveToMailboxInteractor; final CachingManager _cachingManager; - final emailList = [].obs; final listEmailDrag = [].obs; bool canLoadMore = true; @@ -128,6 +127,8 @@ class ThreadController extends BaseController { SearchQuery? get searchQuery => searchController.searchEmailFilter.value.text; + RxList get emailList => mailboxDashBoardController.emailList; + ThreadController( this._getEmailsInMailboxInteractor, this._markAsMultipleEmailReadInteractor,