From 651115c3046f0403d127cba5baf5b761c197f8c6 Mon Sep 17 00:00:00 2001 From: dab246 Date: Tue, 17 Mar 2026 12:55:02 +0700 Subject: [PATCH] TF-4368 Auto trigger load more when get all email return < 20 emails --- .../domain/constants/thread_constants.dart | 1 - .../presentation/thread_controller.dart | 201 ++++++++++++------ 2 files changed, 137 insertions(+), 65 deletions(-) diff --git a/lib/features/thread/domain/constants/thread_constants.dart b/lib/features/thread/domain/constants/thread_constants.dart index 539d18425..46e4360c3 100644 --- a/lib/features/thread/domain/constants/thread_constants.dart +++ b/lib/features/thread/domain/constants/thread_constants.dart @@ -73,7 +73,6 @@ class ThreadConstants { }); static const int defaultMaxHeightEmailItemOnBrowser = 40; - static const int defaultMaxHeightBrowser = 1200; static final propertiesParseEmailByBlobId = Properties({ EmailProperty.id, diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 3f225eaa4..55022756d 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -97,8 +97,8 @@ class ThreadController extends BaseController with EmailActionController { final openingEmail = RxBool(false); final loadingMoreStatus = Rx(LoadingMoreStatus.idle); - bool canLoadMore = false; - bool canSearchMore = false; + bool canLoadMore = true; + bool canSearchMore = true; MailboxId? _currentMemoryMailboxId; int _peakEmailCount = 0; final ScrollController listEmailController = ScrollController(); @@ -203,6 +203,7 @@ class ThreadController extends BaseController with EmailActionController { if (failure is SearchEmailFailure) { mailboxDashBoardController.updateRefreshAllEmailState(Left(RefreshAllEmailFailure())); canSearchMore = false; + loadingMoreStatus.value = LoadingMoreStatus.idle; mailboxDashBoardController.emailsInCurrentMailbox.clear(); showRetryToast(failure); } else if (failure is SearchMoreEmailFailure) { @@ -245,7 +246,7 @@ class ThreadController extends BaseController with EmailActionController { }, (success) { if (success is GetAllEmailSuccess) { - _handleOnDoneGetAllEmailSuccess(); + _handleOnDoneGetAllEmailSuccess(success); } }, ); @@ -411,7 +412,7 @@ class ThreadController extends BaseController with EmailActionController { ever(mailboxDashBoardController.emailsInCurrentMailbox, (emails) { final countEmails = emails.length; - log( + logTrace( 'ThreadController::Ever(mailboxDashBoardController.emailsInCurrentMailbox): ' 'Count emails is $countEmails, ' '_peakEmailCount is $_peakEmailCount', @@ -472,27 +473,56 @@ class ThreadController extends BaseController with EmailActionController { } void _validateBrowserHeight() { + if (_isAutoLoadMore) { + _performAutomaticallyLoadMoreEmails(); + } + } + + bool get _isAutoLoadMore { + if (!PlatformInfo.isWeb) { + return _isNonWebAutoLoadMore; + } final browserInnerHeight = html.window.innerHeight ?? 0; final currentListEmails = mailboxDashBoardController.emailsInCurrentMailbox; final totalHeightListEmails = currentListEmails.isEmpty - ? 0 - : currentListEmails.length * ThreadConstants.defaultMaxHeightEmailItemOnBrowser; - final isAutoLoadMore = - browserInnerHeight >= ThreadConstants.defaultMaxHeightBrowser && - totalHeightListEmails <= browserInnerHeight; + ? 0 + : currentListEmails.length * + ThreadConstants.defaultMaxHeightEmailItemOnBrowser; + final isAutoLoadMore = totalHeightListEmails > 0 && + totalHeightListEmails <= browserInnerHeight; logTrace( - 'ThreadController::_validateBrowserHeight():' + 'ThreadController::_isAutoLoadMore():' 'BrowserInnerHeight = $browserInnerHeight, ' 'TotalHeightListEmails = $totalHeightListEmails, ' - 'ThreadConstants.defaultMaxHeightBrowser = ${ThreadConstants.defaultMaxHeightBrowser}, ' 'ThreadConstants.defaultMaxHeightEmailItemOnBrowser = ${ThreadConstants.defaultMaxHeightEmailItemOnBrowser}, ' + 'CountCurrentListEmails = ${currentListEmails.length}, ' 'CanLoadMore = $canLoadMore, ' - 'isAutoLoadMore = $isAutoLoadMore, ' - 'CountCurrentListEmails = ${currentListEmails.length}', + 'isAutoLoadMore = $isAutoLoadMore ', ); - if (isAutoLoadMore) { - _performAutomaticallyLoadMoreEmails(); + return isAutoLoadMore; + } + + bool get _isNonWebAutoLoadMore { + if (!listEmailController.hasClients) { + logTrace( + 'ThreadController::_isNonWebAutoLoadMore(): listEmailController.hasClients = false', + ); + return false; } + + final maxScroll = listEmailController.position.maxScrollExtent; + final viewport = listEmailController.position.viewportDimension; + final isAutoLoadMore = maxScroll <= viewport; + + logTrace( + 'ThreadController::_isNonWebAutoLoadMore():' + 'maxScroll = $maxScroll, ' + 'viewport = $viewport, ' + 'CanLoadMore = $canLoadMore, ' + 'isAutoLoadMore = $isAutoLoadMore ', + ); + + return isAutoLoadMore; } void _performAutomaticallyLoadMoreEmails() { @@ -525,10 +555,14 @@ class ThreadController extends BaseController with EmailActionController { mailboxDashBoardController.listEmailSelected.clear(); mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE; canLoadMore = true; + canSearchMore = true; loadingMoreStatus.value = LoadingMoreStatus.idle; } - void _getAllEmailSuccess(GetAllEmailSuccess success) { + void _getAllEmailSuccess( + GetAllEmailSuccess success, { + bool shouldJumpToFirstEmail = true, + }) { log('ThreadController::_getAllEmailSuccess: GetAllForMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}'); mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); final currentMailboxId = success.currentMailboxId; @@ -539,42 +573,54 @@ class ThreadController extends BaseController with EmailActionController { return; } mailboxDashBoardController.setCurrentEmailState(success.currentEmailState); - log('ThreadController::_getAllEmailSuccess():COUNT = ${success.emailList.length} | EMAIL_STATE = ${mailboxDashBoardController.currentEmailState}'); final newListEmail = success.emailList.syncPresentationEmail( mapMailboxById: mailboxDashBoardController.mapMailboxById, selectedMailbox: selectedMailbox, searchQuery: searchController.searchQuery, isSearchEmailRunning: searchController.isSearchEmailRunning ); + logTrace( + 'ThreadController::_getAllEmailSuccess():' + 'MailboxId = ${success.currentMailboxId?.asString}, ' + 'ServerEmailCount = ${success.emailList.length}, ' + 'DisplayedEmailCount = ${newListEmail.length}, ' + 'EmailState = ${success.currentEmailState?.value}', + ); mailboxDashBoardController.updateEmailList(newListEmail); if (mailboxDashBoardController.isSelectionEnabled()) { mailboxDashBoardController.listEmailSelected.value = listEmailSelected; } - canLoadMore = newListEmail.length >= ThreadConstants.maxCountEmails; - loadingMoreStatus.value = LoadingMoreStatus.completed; - if (listEmailController.hasClients) { + if (shouldJumpToFirstEmail && listEmailController.hasClients) { listEmailController.jumpTo(0); } } - void _handleOnDoneGetAllEmailSuccess() { - if (PlatformInfo.isWeb) { - _validateBrowserHeight(); - - if (mailboxDashBoardController.isEmailListDisplayed) { - refocusMailShortcutFocus(); - } + void _handleOnDoneGetAllEmailSuccess(GetAllEmailSuccess success) { + if (PlatformInfo.isWeb && mailboxDashBoardController.isEmailListDisplayed) { + refocusMailShortcutFocus(); + } + final emailList = success.emailList; + log('ThreadController::_handleOnDoneGetAllEmailSuccess: EmailCount = ${emailList.length}'); + if (_isAutoLoadMore && emailList.isNotEmpty) { + _performAutomaticallyLoadMoreEmails(); + } else { + canLoadMore = emailList.isNotEmpty; } } void _handleOnDoneGetAllEmailFailure() { - if (PlatformInfo.isWeb) { - _validateBrowserHeight(); - } + log('ThreadController::_handleOnDoneGetAllEmailFailure'); if (PlatformInfo.isWeb && mailboxDashBoardController.isEmailListDisplayed) { refocusMailShortcutFocus(); } + + if (_isAutoLoadMore) { + _performAutomaticallyLoadMoreEmails(); + } else { + canLoadMore = false; + loadingMoreStatus.value = LoadingMoreStatus.idle; + } } void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) { @@ -602,8 +648,17 @@ class ThreadController extends BaseController with EmailActionController { mailboxDashBoardController.listEmailSelected.value = listEmailSelected; } - if (PlatformInfo.isWeb) { - _validateBrowserHeight(); + logTrace( + 'ThreadController::_refreshChangesAllEmailSuccess():' + 'MailboxId = ${success.currentMailboxId?.asString}, ' + 'CurrentEmailCount = ${emailsBeforeChanges.length}, ' + 'ServerEmailCount = ${success.emailList.length}, ' + 'DisplayedEmailCount = ${emailListSynced.length}, ' + 'EmailState = ${success.currentEmailState?.value}', + ); + + if (_isAutoLoadMore) { + _performAutomaticallyLoadMoreEmails(); } } @@ -700,7 +755,8 @@ class ThreadController extends BaseController with EmailActionController { await _refreshChangeListEmailCache(); log('ThreadController::_refreshChangeSearchEmail:'); - canSearchMore = false; + canSearchMore = true; + loadingMoreStatus.value = LoadingMoreStatus.idle; searchController.updateFilterEmail( positionOption: option( _searchEmailFilter.sortOrderType.isScrollByPosition(), @@ -737,6 +793,7 @@ class ThreadController extends BaseController with EmailActionController { mailboxDashBoardController.updateRefreshAllEmailState( Left(RefreshAllEmailFailure())); canSearchMore = false; + loadingMoreStatus.value = LoadingMoreStatus.completed; mailboxDashBoardController.emailsInCurrentMailbox.clear(); if (searchState != null) { onDataFailureViewState(searchState); @@ -820,7 +877,7 @@ class ThreadController extends BaseController with EmailActionController { .foldSuccessWithResult(); if (emailSuccessState is GetAllEmailSuccess) { - _getAllEmailSuccess(emailSuccessState); + _getAllEmailSuccess(emailSuccessState, shouldJumpToFirstEmail: false); } else if (emailSuccessState != null) { onDataFailureViewState(emailSuccessState); } @@ -831,16 +888,20 @@ class ThreadController extends BaseController with EmailActionController { if (!canLoadMore) return; if (_session != null && _accountId != null) { - final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty - ? mailboxDashBoardController.emailsInCurrentMailbox.last - : null; + final currentListEmail = + mailboxDashBoardController.emailsInCurrentMailbox; + final oldestEmail = + currentListEmail.isNotEmpty ? currentListEmail.last : null; final useCache = selectedMailbox?.isCacheable ?? false; final filterOption = mailboxDashBoardController.filterMessageOption.value; + logTrace( - 'ThreadController::_loadMoreEmails: OldestEmailID = ${oldestEmail?.id?.asString}, ' + 'ThreadController::_loadMoreEmails: ' + 'OldestEmailID = ${oldestEmail?.id?.asString}, ' 'useCache = $useCache, ' 'filterOption = ${filterOption.name}', ); + consumeState(_loadMoreEmailsInMailboxInteractor.execute( GetEmailRequest( _session!, @@ -851,7 +912,7 @@ class ThreadController extends BaseController with EmailActionController { filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), lastEmailId: oldestEmail?.id, - useCache: selectedMailbox?.isCacheable ?? false, + useCache: useCache, ) )); } else { @@ -879,18 +940,24 @@ class ThreadController extends BaseController with EmailActionController { } void _loadMoreEmailsSuccess(LoadMoreEmailsSuccess success) { - canLoadMore = success.emailList.isNotEmpty; - loadingMoreStatus.value = LoadingMoreStatus.completed; - final appendableList = validateListEmailsLoadMore(success.emailList); + final emailList = success.emailList; + final appendableList = validateListEmailsLoadMore(emailList); + logTrace( - 'ThreadController::_loadMoreEmailsSuccess: emailList = ${success.emailList.length}, ' - 'appendableList = ${appendableList.length}', + 'ThreadController::_loadMoreEmailsSuccess: ' + 'ServerEmailCount = ${emailList.length}, ' + 'EmailAppendableCount = ${appendableList.length}', ); + if (appendableList.isNotEmpty) { mailboxDashBoardController.emailsInCurrentMailbox.addAll(appendableList); } - if (PlatformInfo.isWeb) { - _validateBrowserHeight(); + + if (_isAutoLoadMore && emailList.isNotEmpty) { + _performAutomaticallyLoadMoreEmails(); + } else { + canLoadMore = emailList.isNotEmpty; + loadingMoreStatus.value = LoadingMoreStatus.completed; } } @@ -1059,7 +1126,8 @@ class ThreadController extends BaseController with EmailActionController { if (!needRefreshSearchState) { mailboxDashBoardController.emailsInCurrentMailbox.clear(); } - canSearchMore = false; + canSearchMore = true; + loadingMoreStatus.value = LoadingMoreStatus.idle; searchController.updateFilterEmail( positionOption: option(_searchEmailFilter.sortOrderType.isScrollByPosition(), 0), @@ -1105,8 +1173,9 @@ class ThreadController extends BaseController with EmailActionController { void _searchEmailsSuccess(SearchEmailSuccess success) { mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); - log('ThreadController::_searchEmailsSuccess: COUNT = ${success.emailList.length}'); - final resultEmailSearchList = success.emailList + final emailList = success.emailList; + log('ThreadController::_searchEmailsSuccess: COUNT = ${emailList.length}'); + final resultEmailSearchList = emailList .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) .toList(); @@ -1123,11 +1192,12 @@ class ThreadController extends BaseController with EmailActionController { if (mailboxDashBoardController.isSelectionEnabled()) { mailboxDashBoardController.listEmailSelected.value = listEmailSelected; } - canSearchMore = newEmailListSynced.length >= ThreadConstants.maxCountEmails; - loadingMoreStatus.value = LoadingMoreStatus.completed; - if (PlatformInfo.isWeb) { - _validateBrowserHeight(); + if (_isAutoLoadMore && emailList.isNotEmpty) { + _performAutomaticallyLoadMoreEmails(); + } else { + canSearchMore = emailList.isNotEmpty; + loadingMoreStatus.value = LoadingMoreStatus.completed; } } @@ -1139,12 +1209,13 @@ class ThreadController extends BaseController with EmailActionController { if (!canSearchMore) return; if (_session != null && _accountId != null) { - final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty - ? mailboxDashBoardController.emailsInCurrentMailbox.last - : null; + final currentEmailList = + mailboxDashBoardController.emailsInCurrentMailbox; + final lastEmail = + currentEmailList.isNotEmpty ? currentEmailList.last : null; if (_searchEmailFilter.sortOrderType.isScrollByPosition()) { - final nextPosition = mailboxDashBoardController.emailsInCurrentMailbox.length; + final nextPosition = currentEmailList.length; log('ThreadController::_searchMoreEmails:nextPosition: $nextPosition'); searchController.updateFilterEmail(positionOption: Some(nextPosition)); } else if (_searchEmailFilter.sortOrderType == EmailSortOrderType.oldest) { @@ -1173,9 +1244,10 @@ class ThreadController extends BaseController with EmailActionController { } void _searchMoreEmailsSuccess(SearchMoreEmailSuccess success) { - log('ThreadController::_searchMoreEmailsSuccess: COUNT = ${success.emailList.length}'); - if (success.emailList.isNotEmpty) { - final resultEmailSearchList = success.emailList + final emailList = success.emailList; + log('ThreadController::_searchMoreEmailsSuccess: COUNT = ${emailList.length}'); + if (emailList.isNotEmpty) { + final resultEmailSearchList = emailList .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) .where((email) => mailboxDashBoardController.emailsInCurrentMailbox.every((emailInCurrentMailbox) => emailInCurrentMailbox.id != email.id)) .toList() @@ -1187,11 +1259,12 @@ class ThreadController extends BaseController with EmailActionController { ); mailboxDashBoardController.emailsInCurrentMailbox.addAll(resultEmailSearchList); } - canSearchMore = success.emailList.isNotEmpty; - loadingMoreStatus.value = LoadingMoreStatus.completed; - if (PlatformInfo.isWeb) { - _validateBrowserHeight(); + if (_isAutoLoadMore && emailList.isNotEmpty) { + _performAutomaticallyLoadMoreEmails(); + } else { + canSearchMore = emailList.isNotEmpty; + loadingMoreStatus.value = LoadingMoreStatus.completed; } }