TF-4368 Auto trigger load more when get all email return < 20 emails

This commit is contained in:
dab246
2026-03-17 12:55:02 +07:00
committed by Dat H. Pham
parent 7907df3140
commit 651115c304
2 changed files with 137 additions and 65 deletions
@@ -73,7 +73,6 @@ class ThreadConstants {
}); });
static const int defaultMaxHeightEmailItemOnBrowser = 40; static const int defaultMaxHeightEmailItemOnBrowser = 40;
static const int defaultMaxHeightBrowser = 1200;
static final propertiesParseEmailByBlobId = Properties({ static final propertiesParseEmailByBlobId = Properties({
EmailProperty.id, EmailProperty.id,
@@ -97,8 +97,8 @@ class ThreadController extends BaseController with EmailActionController {
final openingEmail = RxBool(false); final openingEmail = RxBool(false);
final loadingMoreStatus = Rx(LoadingMoreStatus.idle); final loadingMoreStatus = Rx(LoadingMoreStatus.idle);
bool canLoadMore = false; bool canLoadMore = true;
bool canSearchMore = false; bool canSearchMore = true;
MailboxId? _currentMemoryMailboxId; MailboxId? _currentMemoryMailboxId;
int _peakEmailCount = 0; int _peakEmailCount = 0;
final ScrollController listEmailController = ScrollController(); final ScrollController listEmailController = ScrollController();
@@ -203,6 +203,7 @@ class ThreadController extends BaseController with EmailActionController {
if (failure is SearchEmailFailure) { if (failure is SearchEmailFailure) {
mailboxDashBoardController.updateRefreshAllEmailState(Left(RefreshAllEmailFailure())); mailboxDashBoardController.updateRefreshAllEmailState(Left(RefreshAllEmailFailure()));
canSearchMore = false; canSearchMore = false;
loadingMoreStatus.value = LoadingMoreStatus.idle;
mailboxDashBoardController.emailsInCurrentMailbox.clear(); mailboxDashBoardController.emailsInCurrentMailbox.clear();
showRetryToast(failure); showRetryToast(failure);
} else if (failure is SearchMoreEmailFailure) { } else if (failure is SearchMoreEmailFailure) {
@@ -245,7 +246,7 @@ class ThreadController extends BaseController with EmailActionController {
}, },
(success) { (success) {
if (success is GetAllEmailSuccess) { if (success is GetAllEmailSuccess) {
_handleOnDoneGetAllEmailSuccess(); _handleOnDoneGetAllEmailSuccess(success);
} }
}, },
); );
@@ -411,7 +412,7 @@ class ThreadController extends BaseController with EmailActionController {
ever(mailboxDashBoardController.emailsInCurrentMailbox, (emails) { ever(mailboxDashBoardController.emailsInCurrentMailbox, (emails) {
final countEmails = emails.length; final countEmails = emails.length;
log( logTrace(
'ThreadController::Ever(mailboxDashBoardController.emailsInCurrentMailbox): ' 'ThreadController::Ever(mailboxDashBoardController.emailsInCurrentMailbox): '
'Count emails is $countEmails, ' 'Count emails is $countEmails, '
'_peakEmailCount is $_peakEmailCount', '_peakEmailCount is $_peakEmailCount',
@@ -472,27 +473,56 @@ class ThreadController extends BaseController with EmailActionController {
} }
void _validateBrowserHeight() { void _validateBrowserHeight() {
if (_isAutoLoadMore) {
_performAutomaticallyLoadMoreEmails();
}
}
bool get _isAutoLoadMore {
if (!PlatformInfo.isWeb) {
return _isNonWebAutoLoadMore;
}
final browserInnerHeight = html.window.innerHeight ?? 0; final browserInnerHeight = html.window.innerHeight ?? 0;
final currentListEmails = mailboxDashBoardController.emailsInCurrentMailbox; final currentListEmails = mailboxDashBoardController.emailsInCurrentMailbox;
final totalHeightListEmails = currentListEmails.isEmpty final totalHeightListEmails = currentListEmails.isEmpty
? 0 ? 0
: currentListEmails.length * ThreadConstants.defaultMaxHeightEmailItemOnBrowser; : currentListEmails.length *
final isAutoLoadMore = ThreadConstants.defaultMaxHeightEmailItemOnBrowser;
browserInnerHeight >= ThreadConstants.defaultMaxHeightBrowser && final isAutoLoadMore = totalHeightListEmails > 0 &&
totalHeightListEmails <= browserInnerHeight; totalHeightListEmails <= browserInnerHeight;
logTrace( logTrace(
'ThreadController::_validateBrowserHeight():' 'ThreadController::_isAutoLoadMore():'
'BrowserInnerHeight = $browserInnerHeight, ' 'BrowserInnerHeight = $browserInnerHeight, '
'TotalHeightListEmails = $totalHeightListEmails, ' 'TotalHeightListEmails = $totalHeightListEmails, '
'ThreadConstants.defaultMaxHeightBrowser = ${ThreadConstants.defaultMaxHeightBrowser}, '
'ThreadConstants.defaultMaxHeightEmailItemOnBrowser = ${ThreadConstants.defaultMaxHeightEmailItemOnBrowser}, ' 'ThreadConstants.defaultMaxHeightEmailItemOnBrowser = ${ThreadConstants.defaultMaxHeightEmailItemOnBrowser}, '
'CountCurrentListEmails = ${currentListEmails.length}, '
'CanLoadMore = $canLoadMore, ' 'CanLoadMore = $canLoadMore, '
'isAutoLoadMore = $isAutoLoadMore, ' 'isAutoLoadMore = $isAutoLoadMore ',
'CountCurrentListEmails = ${currentListEmails.length}',
); );
if (isAutoLoadMore) { return isAutoLoadMore;
_performAutomaticallyLoadMoreEmails(); }
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() { void _performAutomaticallyLoadMoreEmails() {
@@ -525,10 +555,14 @@ class ThreadController extends BaseController with EmailActionController {
mailboxDashBoardController.listEmailSelected.clear(); mailboxDashBoardController.listEmailSelected.clear();
mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE; mailboxDashBoardController.currentSelectMode.value = SelectMode.INACTIVE;
canLoadMore = true; canLoadMore = true;
canSearchMore = true;
loadingMoreStatus.value = LoadingMoreStatus.idle; 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}'); log('ThreadController::_getAllEmailSuccess: GetAllForMailboxId = ${success.currentMailboxId?.asString} | SELECTED_MAILBOX_ID = ${selectedMailboxId?.asString} | SELECTED_MAILBOX_NAME = ${selectedMailbox?.name?.name}');
mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess()));
final currentMailboxId = success.currentMailboxId; final currentMailboxId = success.currentMailboxId;
@@ -539,42 +573,54 @@ class ThreadController extends BaseController with EmailActionController {
return; return;
} }
mailboxDashBoardController.setCurrentEmailState(success.currentEmailState); mailboxDashBoardController.setCurrentEmailState(success.currentEmailState);
log('ThreadController::_getAllEmailSuccess():COUNT = ${success.emailList.length} | EMAIL_STATE = ${mailboxDashBoardController.currentEmailState}');
final newListEmail = success.emailList.syncPresentationEmail( final newListEmail = success.emailList.syncPresentationEmail(
mapMailboxById: mailboxDashBoardController.mapMailboxById, mapMailboxById: mailboxDashBoardController.mapMailboxById,
selectedMailbox: selectedMailbox, selectedMailbox: selectedMailbox,
searchQuery: searchController.searchQuery, searchQuery: searchController.searchQuery,
isSearchEmailRunning: searchController.isSearchEmailRunning isSearchEmailRunning: searchController.isSearchEmailRunning
); );
logTrace(
'ThreadController::_getAllEmailSuccess():'
'MailboxId = ${success.currentMailboxId?.asString}, '
'ServerEmailCount = ${success.emailList.length}, '
'DisplayedEmailCount = ${newListEmail.length}, '
'EmailState = ${success.currentEmailState?.value}',
);
mailboxDashBoardController.updateEmailList(newListEmail); mailboxDashBoardController.updateEmailList(newListEmail);
if (mailboxDashBoardController.isSelectionEnabled()) { if (mailboxDashBoardController.isSelectionEnabled()) {
mailboxDashBoardController.listEmailSelected.value = listEmailSelected; mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
} }
canLoadMore = newListEmail.length >= ThreadConstants.maxCountEmails;
loadingMoreStatus.value = LoadingMoreStatus.completed;
if (listEmailController.hasClients) { if (shouldJumpToFirstEmail && listEmailController.hasClients) {
listEmailController.jumpTo(0); listEmailController.jumpTo(0);
} }
} }
void _handleOnDoneGetAllEmailSuccess() { void _handleOnDoneGetAllEmailSuccess(GetAllEmailSuccess success) {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb && mailboxDashBoardController.isEmailListDisplayed) {
_validateBrowserHeight(); refocusMailShortcutFocus();
}
if (mailboxDashBoardController.isEmailListDisplayed) { final emailList = success.emailList;
refocusMailShortcutFocus(); log('ThreadController::_handleOnDoneGetAllEmailSuccess: EmailCount = ${emailList.length}');
} if (_isAutoLoadMore && emailList.isNotEmpty) {
_performAutomaticallyLoadMoreEmails();
} else {
canLoadMore = emailList.isNotEmpty;
} }
} }
void _handleOnDoneGetAllEmailFailure() { void _handleOnDoneGetAllEmailFailure() {
if (PlatformInfo.isWeb) { log('ThreadController::_handleOnDoneGetAllEmailFailure');
_validateBrowserHeight();
}
if (PlatformInfo.isWeb && mailboxDashBoardController.isEmailListDisplayed) { if (PlatformInfo.isWeb && mailboxDashBoardController.isEmailListDisplayed) {
refocusMailShortcutFocus(); refocusMailShortcutFocus();
} }
if (_isAutoLoadMore) {
_performAutomaticallyLoadMoreEmails();
} else {
canLoadMore = false;
loadingMoreStatus.value = LoadingMoreStatus.idle;
}
} }
void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) { void _refreshChangesAllEmailSuccess(RefreshChangesAllEmailSuccess success) {
@@ -602,8 +648,17 @@ class ThreadController extends BaseController with EmailActionController {
mailboxDashBoardController.listEmailSelected.value = listEmailSelected; mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
} }
if (PlatformInfo.isWeb) { logTrace(
_validateBrowserHeight(); '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(); await _refreshChangeListEmailCache();
log('ThreadController::_refreshChangeSearchEmail:'); log('ThreadController::_refreshChangeSearchEmail:');
canSearchMore = false; canSearchMore = true;
loadingMoreStatus.value = LoadingMoreStatus.idle;
searchController.updateFilterEmail( searchController.updateFilterEmail(
positionOption: option( positionOption: option(
_searchEmailFilter.sortOrderType.isScrollByPosition(), _searchEmailFilter.sortOrderType.isScrollByPosition(),
@@ -737,6 +793,7 @@ class ThreadController extends BaseController with EmailActionController {
mailboxDashBoardController.updateRefreshAllEmailState( mailboxDashBoardController.updateRefreshAllEmailState(
Left(RefreshAllEmailFailure())); Left(RefreshAllEmailFailure()));
canSearchMore = false; canSearchMore = false;
loadingMoreStatus.value = LoadingMoreStatus.completed;
mailboxDashBoardController.emailsInCurrentMailbox.clear(); mailboxDashBoardController.emailsInCurrentMailbox.clear();
if (searchState != null) { if (searchState != null) {
onDataFailureViewState(searchState); onDataFailureViewState(searchState);
@@ -820,7 +877,7 @@ class ThreadController extends BaseController with EmailActionController {
.foldSuccessWithResult<GetAllEmailSuccess>(); .foldSuccessWithResult<GetAllEmailSuccess>();
if (emailSuccessState is GetAllEmailSuccess) { if (emailSuccessState is GetAllEmailSuccess) {
_getAllEmailSuccess(emailSuccessState); _getAllEmailSuccess(emailSuccessState, shouldJumpToFirstEmail: false);
} else if (emailSuccessState != null) { } else if (emailSuccessState != null) {
onDataFailureViewState(emailSuccessState); onDataFailureViewState(emailSuccessState);
} }
@@ -831,16 +888,20 @@ class ThreadController extends BaseController with EmailActionController {
if (!canLoadMore) return; if (!canLoadMore) return;
if (_session != null && _accountId != null) { if (_session != null && _accountId != null) {
final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty final currentListEmail =
? mailboxDashBoardController.emailsInCurrentMailbox.last mailboxDashBoardController.emailsInCurrentMailbox;
: null; final oldestEmail =
currentListEmail.isNotEmpty ? currentListEmail.last : null;
final useCache = selectedMailbox?.isCacheable ?? false; final useCache = selectedMailbox?.isCacheable ?? false;
final filterOption = mailboxDashBoardController.filterMessageOption.value; final filterOption = mailboxDashBoardController.filterMessageOption.value;
logTrace( logTrace(
'ThreadController::_loadMoreEmails: OldestEmailID = ${oldestEmail?.id?.asString}, ' 'ThreadController::_loadMoreEmails: '
'OldestEmailID = ${oldestEmail?.id?.asString}, '
'useCache = $useCache, ' 'useCache = $useCache, '
'filterOption = ${filterOption.name}', 'filterOption = ${filterOption.name}',
); );
consumeState(_loadMoreEmailsInMailboxInteractor.execute( consumeState(_loadMoreEmailsInMailboxInteractor.execute(
GetEmailRequest( GetEmailRequest(
_session!, _session!,
@@ -851,7 +912,7 @@ class ThreadController extends BaseController with EmailActionController {
filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail), filter: getFilterConditionForLoadMailbox(oldestEmail: oldestEmail),
properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!),
lastEmailId: oldestEmail?.id, lastEmailId: oldestEmail?.id,
useCache: selectedMailbox?.isCacheable ?? false, useCache: useCache,
) )
)); ));
} else { } else {
@@ -879,18 +940,24 @@ class ThreadController extends BaseController with EmailActionController {
} }
void _loadMoreEmailsSuccess(LoadMoreEmailsSuccess success) { void _loadMoreEmailsSuccess(LoadMoreEmailsSuccess success) {
canLoadMore = success.emailList.isNotEmpty; final emailList = success.emailList;
loadingMoreStatus.value = LoadingMoreStatus.completed; final appendableList = validateListEmailsLoadMore(emailList);
final appendableList = validateListEmailsLoadMore(success.emailList);
logTrace( logTrace(
'ThreadController::_loadMoreEmailsSuccess: emailList = ${success.emailList.length}, ' 'ThreadController::_loadMoreEmailsSuccess: '
'appendableList = ${appendableList.length}', 'ServerEmailCount = ${emailList.length}, '
'EmailAppendableCount = ${appendableList.length}',
); );
if (appendableList.isNotEmpty) { if (appendableList.isNotEmpty) {
mailboxDashBoardController.emailsInCurrentMailbox.addAll(appendableList); 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) { if (!needRefreshSearchState) {
mailboxDashBoardController.emailsInCurrentMailbox.clear(); mailboxDashBoardController.emailsInCurrentMailbox.clear();
} }
canSearchMore = false; canSearchMore = true;
loadingMoreStatus.value = LoadingMoreStatus.idle;
searchController.updateFilterEmail( searchController.updateFilterEmail(
positionOption: option(_searchEmailFilter.sortOrderType.isScrollByPosition(), 0), positionOption: option(_searchEmailFilter.sortOrderType.isScrollByPosition(), 0),
@@ -1105,8 +1173,9 @@ class ThreadController extends BaseController with EmailActionController {
void _searchEmailsSuccess(SearchEmailSuccess success) { void _searchEmailsSuccess(SearchEmailSuccess success) {
mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess())); mailboxDashBoardController.updateRefreshAllEmailState(Right(RefreshAllEmailSuccess()));
log('ThreadController::_searchEmailsSuccess: COUNT = ${success.emailList.length}'); final emailList = success.emailList;
final resultEmailSearchList = success.emailList log('ThreadController::_searchEmailsSuccess: COUNT = ${emailList.length}');
final resultEmailSearchList = emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
.toList(); .toList();
@@ -1123,11 +1192,12 @@ class ThreadController extends BaseController with EmailActionController {
if (mailboxDashBoardController.isSelectionEnabled()) { if (mailboxDashBoardController.isSelectionEnabled()) {
mailboxDashBoardController.listEmailSelected.value = listEmailSelected; mailboxDashBoardController.listEmailSelected.value = listEmailSelected;
} }
canSearchMore = newEmailListSynced.length >= ThreadConstants.maxCountEmails;
loadingMoreStatus.value = LoadingMoreStatus.completed;
if (PlatformInfo.isWeb) { if (_isAutoLoadMore && emailList.isNotEmpty) {
_validateBrowserHeight(); _performAutomaticallyLoadMoreEmails();
} else {
canSearchMore = emailList.isNotEmpty;
loadingMoreStatus.value = LoadingMoreStatus.completed;
} }
} }
@@ -1139,12 +1209,13 @@ class ThreadController extends BaseController with EmailActionController {
if (!canSearchMore) return; if (!canSearchMore) return;
if (_session != null && _accountId != null) { if (_session != null && _accountId != null) {
final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty final currentEmailList =
? mailboxDashBoardController.emailsInCurrentMailbox.last mailboxDashBoardController.emailsInCurrentMailbox;
: null; final lastEmail =
currentEmailList.isNotEmpty ? currentEmailList.last : null;
if (_searchEmailFilter.sortOrderType.isScrollByPosition()) { if (_searchEmailFilter.sortOrderType.isScrollByPosition()) {
final nextPosition = mailboxDashBoardController.emailsInCurrentMailbox.length; final nextPosition = currentEmailList.length;
log('ThreadController::_searchMoreEmails:nextPosition: $nextPosition'); log('ThreadController::_searchMoreEmails:nextPosition: $nextPosition');
searchController.updateFilterEmail(positionOption: Some(nextPosition)); searchController.updateFilterEmail(positionOption: Some(nextPosition));
} else if (_searchEmailFilter.sortOrderType == EmailSortOrderType.oldest) { } else if (_searchEmailFilter.sortOrderType == EmailSortOrderType.oldest) {
@@ -1173,9 +1244,10 @@ class ThreadController extends BaseController with EmailActionController {
} }
void _searchMoreEmailsSuccess(SearchMoreEmailSuccess success) { void _searchMoreEmailsSuccess(SearchMoreEmailSuccess success) {
log('ThreadController::_searchMoreEmailsSuccess: COUNT = ${success.emailList.length}'); final emailList = success.emailList;
if (success.emailList.isNotEmpty) { log('ThreadController::_searchMoreEmailsSuccess: COUNT = ${emailList.length}');
final resultEmailSearchList = success.emailList if (emailList.isNotEmpty) {
final resultEmailSearchList = emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById)) .map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
.where((email) => mailboxDashBoardController.emailsInCurrentMailbox.every((emailInCurrentMailbox) => emailInCurrentMailbox.id != email.id)) .where((email) => mailboxDashBoardController.emailsInCurrentMailbox.every((emailInCurrentMailbox) => emailInCurrentMailbox.id != email.id))
.toList() .toList()
@@ -1187,11 +1259,12 @@ class ThreadController extends BaseController with EmailActionController {
); );
mailboxDashBoardController.emailsInCurrentMailbox.addAll(resultEmailSearchList); mailboxDashBoardController.emailsInCurrentMailbox.addAll(resultEmailSearchList);
} }
canSearchMore = success.emailList.isNotEmpty;
loadingMoreStatus.value = LoadingMoreStatus.completed;
if (PlatformInfo.isWeb) { if (_isAutoLoadMore && emailList.isNotEmpty) {
_validateBrowserHeight(); _performAutomaticallyLoadMoreEmails();
} else {
canSearchMore = emailList.isNotEmpty;
loadingMoreStatus.value = LoadingMoreStatus.completed;
} }
} }