From d5f646af7997d7cc9bf8857b9caaa38befab9c13 Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 18 Dec 2023 11:26:14 +0700 Subject: [PATCH] TF-2323 Use `position` to load more emails when sort by `Subject` & `Sender` Signed-off-by: dab246 (cherry picked from commit 847a56bfd331dc29f05493a861fb6f21da2b2cde) --- contact/pubspec.lock | 44 +++++++++- .../controller/search_controller.dart | 2 + .../model/search/email_sort_order_type.dart | 9 +- .../model/search/search_email_filter.dart | 21 ++++- ...fresh_changes_search_email_interactor.dart | 4 +- .../model/simple_search_filter.dart | 22 +++-- .../presentation/search_email_controller.dart | 83 ++++++++++++++----- .../data/datasource/thread_datasource.dart | 1 + .../local_thread_datasource_impl.dart | 1 + .../thread_datasource_impl.dart | 4 +- .../thread/data/network/thread_api.dart | 3 + .../repository/thread_repository_impl.dart | 8 ++ .../domain/model/get_email_request.dart | 5 +- .../domain/repository/thread_repository.dart | 1 + .../usecases/search_email_interactor.dart | 8 +- .../search_more_email_interactor.dart | 10 ++- .../presentation/thread_controller.dart | 42 ++++++++-- model/pubspec.lock | 44 +++++++++- 18 files changed, 257 insertions(+), 55 deletions(-) diff --git a/contact/pubspec.lock b/contact/pubspec.lock index 8f44330c1..cac99f353 100644 --- a/contact/pubspec.lock +++ b/contact/pubspec.lock @@ -168,6 +168,14 @@ packages: relative: true source: path version: "1.0.0+1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + url: "https://pub.dev" + source: hosted + version: "0.3.3+7" crypto: dependency: transitive description: @@ -297,10 +305,42 @@ packages: dependency: transitive description: name: flutter_image_compress - sha256: "37f1b26399098e5f97b74c1483f534855e7dff68ead6ddaccf747029fb03f29f" + sha256: f159d2e8c4ed04b8e36994124fd4a5017a0f01e831ae3358c74095c340e9ae5e url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "2.1.0" + flutter_image_compress_common: + dependency: transitive + description: + name: flutter_image_compress_common + sha256: "7cad12802628706655920089cfe9ee1d1098300e7f39a079eb160458bbc47652" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + flutter_image_compress_macos: + dependency: transitive + description: + name: flutter_image_compress_macos + sha256: fea1e3d71150d03373916b832c49b5c2f56c3e7e13da82a929274a2c6f88251e + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter_image_compress_platform_interface: + dependency: transitive + description: + name: flutter_image_compress_platform_interface + sha256: eb4f055138b29b04498ebcb6d569aaaee34b64d75fb74ea0d40f9790bf47ee9d + url: "https://pub.dev" + source: hosted + version: "1.0.3" + flutter_image_compress_web: + dependency: transitive + description: + name: flutter_image_compress_web + sha256: da41cc3859f19d11c7d10be615f6a9dcf0907e7daffde7442bf4cc2486663660 + url: "https://pub.dev" + source: hosted + version: "0.1.3+2" flutter_inappwebview: dependency: transitive description: diff --git a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart index caf5578a9..117b37f6b 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart @@ -194,6 +194,7 @@ class SearchController extends BaseController with DateRangePickerMixin { Option? startDateOption, Option? endDateOption, Option>? sortOrderOption, + Option? positionOption, }) { searchEmailFilter.value = searchEmailFilter.value.copyWith( fromOption: fromOption, @@ -208,6 +209,7 @@ class SearchController extends BaseController with DateRangePickerMixin { startDateOption: startDateOption, endDateOption: endDateOption, sortOrderOption: sortOrderOption, + positionOption: positionOption, ); searchEmailFilter.refresh(); } diff --git a/lib/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart b/lib/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart index 742b8faac..0753b01ff 100644 --- a/lib/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart +++ b/lib/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart @@ -1,9 +1,9 @@ import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; +import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_comparator_property.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; enum EmailSortOrderType { mostRecent, @@ -83,4 +83,11 @@ enum EmailSortOrderType { color: Colors.black, ); } + + bool isScrollByPosition() { + return this == EmailSortOrderType.subjectDescending || + this == EmailSortOrderType.subjectAscending || + this == EmailSortOrderType.senderDescending || + this == EmailSortOrderType.senderAscending; + } } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart b/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart index f7f6f5724..fa3edc137 100644 --- a/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart +++ b/lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart @@ -3,14 +3,15 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart'; +import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; import 'package:model/extensions/email_filter_condition_extension.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; -import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; class SearchEmailFilter with EquatableMixin { final Set from; @@ -25,6 +26,7 @@ class SearchEmailFilter with EquatableMixin { final UTCDate? startDate; final UTCDate? endDate; final Set? sortOrder; + final int? position; factory SearchEmailFilter.initial() => SearchEmailFilter(); @@ -41,6 +43,7 @@ class SearchEmailFilter with EquatableMixin { this.startDate, this.endDate, this.sortOrder, + this.position, }) : from = from ?? {}, to = to ?? {}, notKeyword = notKeyword ?? {}, @@ -61,6 +64,7 @@ class SearchEmailFilter with EquatableMixin { Option? startDateOption, Option? endDateOption, Option>? sortOrderOption, + Option? positionOption, }) { return SearchEmailFilter( from: _getOptionParam(fromOption, from), @@ -75,6 +79,7 @@ class SearchEmailFilter with EquatableMixin { startDate: _getOptionParam(startDateOption, startDate), endDate: _getOptionParam(endDateOption, endDate), sortOrder: _getOptionParam(sortOrderOption, sortOrder), + position: _getOptionParam(positionOption, position), ); } @@ -86,18 +91,25 @@ class SearchEmailFilter with EquatableMixin { } } - Filter? mappingToEmailFilterCondition({EmailFilterCondition? moreFilterCondition}) { + Filter? mappingToEmailFilterCondition({ + required EmailSortOrderType sortOrderType, + EmailFilterCondition? moreFilterCondition + }) { final emailEmailFilterConditionShared = EmailFilterCondition( text: text?.value.trim().isNotEmpty == true ? text?.value : null, inMailbox: mailbox?.mailboxId, - after: emailReceiveTimeType.getAfterDate(startDate), + after: sortOrderType.isScrollByPosition() + ? null + : emailReceiveTimeType.getAfterDate(startDate), hasAttachment: hasAttachment == false ? null : hasAttachment, subject: subject?.trim().isNotEmpty == true ? subject : null, - before: emailReceiveTimeType.getBeforeDate(endDate, before) + before: sortOrderType.isScrollByPosition() + ? null + : emailReceiveTimeType.getBeforeDate(endDate, before) ); final listEmailCondition = { @@ -138,5 +150,6 @@ class SearchEmailFilter with EquatableMixin { startDate, endDate, sortOrder, + position, ]; } \ No newline at end of file diff --git a/lib/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart b/lib/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart index b783044ab..75d4f579b 100644 --- a/lib/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart +++ b/lib/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart @@ -6,8 +6,8 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; -import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:model/extensions/email_extension.dart'; import 'package:tmail_ui_user/features/search/email/domain/state/refresh_changes_search_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; @@ -23,6 +23,7 @@ class RefreshChangesSearchEmailInteractor { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties, @@ -35,6 +36,7 @@ class RefreshChangesSearchEmailInteractor { session, accountId, limit: limit, + position: position, sort: sort, filter: filter, properties: properties); diff --git a/lib/features/search/email/presentation/model/simple_search_filter.dart b/lib/features/search/email/presentation/model/simple_search_filter.dart index d2e919baf..7f368ca5a 100644 --- a/lib/features/search/email/presentation/model/simple_search_filter.dart +++ b/lib/features/search/email/presentation/model/simple_search_filter.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart'; import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart'; +import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart'; import 'package:model/email/prefix_email_address.dart'; @@ -11,9 +12,9 @@ import 'package:model/extensions/email_filter_condition_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; class SimpleSearchFilter with EquatableMixin { final Set from; @@ -26,6 +27,7 @@ class SimpleSearchFilter with EquatableMixin { final UTCDate? startDate; final UTCDate? endDate; final Set? sortOrder; + final int? position; SimpleSearchFilter({ Set? from, @@ -38,6 +40,7 @@ class SimpleSearchFilter with EquatableMixin { this.startDate, this.endDate, this.sortOrder, + this.position, }) : from = from ?? {}, to = to ?? {}, hasAttachment = hasAttachment ?? false, @@ -54,6 +57,7 @@ class SimpleSearchFilter with EquatableMixin { Option? startDateOption, Option? endDateOption, Option>? sortOrderOption, + Option? positionOption, }) { return SimpleSearchFilter( from: _getOptionParam(fromOption, from), @@ -65,7 +69,8 @@ class SimpleSearchFilter with EquatableMixin { before: _getOptionParam(beforeOption, before), startDate: _getOptionParam(startDateOption, startDate), endDate: _getOptionParam(endDateOption, endDate), - sortOrder: _getOptionParam(sortOrderOption, sortOrder) + sortOrder: _getOptionParam(sortOrderOption, sortOrder), + position: _getOptionParam(positionOption, position), ); } @@ -77,15 +82,19 @@ class SimpleSearchFilter with EquatableMixin { } } - Filter? mappingToEmailFilterCondition() { + Filter? mappingToEmailFilterCondition({required EmailSortOrderType sortOrderType}) { final emailEmailFilterConditionShared = EmailFilterCondition( text: text?.value.trim().isNotEmpty == true ? text?.value : null, inMailbox: mailbox?.id, - after: emailReceiveTimeType.getAfterDate(startDate), + after: sortOrderType.isScrollByPosition() + ? null + : emailReceiveTimeType.getAfterDate(startDate), hasAttachment: hasAttachment == false ? null : hasAttachment, - before: emailReceiveTimeType.getBeforeDate(endDate, before) + before: sortOrderType.isScrollByPosition() + ? null + : emailReceiveTimeType.getBeforeDate(endDate, before) ); final listEmailCondition = { @@ -117,7 +126,8 @@ class SimpleSearchFilter with EquatableMixin { before, startDate, endDate, - sortOrder + sortOrder, + position, ]; } diff --git a/lib/features/search/email/presentation/search_email_controller.dart b/lib/features/search/email/presentation/search_email_controller.dart index b3a3ef584..42fb85132 100644 --- a/lib/features/search/email/presentation/search_email_controller.dart +++ b/lib/features/search/email/presentation/search_email_controller.dart @@ -176,7 +176,8 @@ class SearchEmailController extends BaseController currentSearchText.value = value; _updateSimpleSearchFilter( textOption: value.isNotEmpty ? Some(SearchQuery(value)) : const None(), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); if (value.isNotEmpty && session != null && accountId != null) { listSuggestionSearch.value = await quickSearchEmails(session: session!, accountId: accountId!); @@ -240,13 +241,17 @@ class SearchEmailController extends BaseController final limit = listResultSearch.isNotEmpty ? UnsignedInt(listResultSearch.length) : ThreadConstants.defaultLimit; - _updateSimpleSearchFilter(beforeOption: const None()); + _updateSimpleSearchFilter( + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() + ); consumeState(_refreshChangesSearchEmailInteractor.execute( session!, accountId!, limit: limit, + position: simpleSearchFilter.value.position, sort: emailSortOrderType.value.getSortOrder().toNullable(), - filter: simpleSearchFilter.value.mappingToEmailFilterCondition(), + filter: simpleSearchFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), properties: EmailUtils.getPropertiesForEmailGetMethod(session!, accountId!), )); } @@ -288,8 +293,8 @@ class SearchEmailController extends BaseController session, accountId, limit: UnsignedInt(5), - sort: emailSortOrderType.value.getSortOrder().toNullable(), - filter: simpleSearchFilter.value.mappingToEmailFilterCondition(), + sort: emailSortOrderType.value.getSortOrder().toNullable(), + filter: simpleSearchFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), properties: ThreadConstants.propertiesQuickSearch) .then((result) => result.fold( (failure) => [], @@ -321,12 +326,26 @@ class SearchEmailController extends BaseController ) ); } + + if (emailSortOrderType.value.isScrollByPosition()) { + _updateSimpleSearchFilter( + positionOption: const Some(0), + beforeOption: const None(), + ); + } else { + _updateSimpleSearchFilter( + positionOption: const None(), + beforeOption: const None(), + ); + } + consumeState(_searchEmailInteractor.execute( session!, accountId!, limit: ThreadConstants.defaultLimit, + position: simpleSearchFilter.value.position, sort: emailSortOrderType.value.getSortOrder().toNullable(), - filter: simpleSearchFilter.value.mappingToEmailFilterCondition(), + filter: simpleSearchFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), properties: EmailUtils.getPropertiesForEmailGetMethod(session!, accountId!), )); } @@ -362,9 +381,14 @@ class SearchEmailController extends BaseController void searchMoreEmailsAction() { if (canSearchMore && session != null && accountId != null) { final lastEmail = listResultSearch.last; - final firstEmail = listResultSearch.first; - if (emailSortOrderType.value == EmailSortOrderType.oldest) { - _updateSimpleSearchFilter(beforeOption: optionOf(firstEmail.receivedAt)); + + if (emailSortOrderType.value.isScrollByPosition()) { + _updateSimpleSearchFilter( + positionOption: Some(listResultSearch.length), + beforeOption: const None() + ); + } else if (emailSortOrderType.value == EmailSortOrderType.oldest) { + _updateSimpleSearchFilter(startDateOption: optionOf(lastEmail.receivedAt)); } else { _updateSimpleSearchFilter(beforeOption: optionOf(lastEmail.receivedAt)); } @@ -374,7 +398,8 @@ class SearchEmailController extends BaseController accountId!, limit: ThreadConstants.defaultLimit, sort: simpleSearchFilter.value.sortOrder, - filter: simpleSearchFilter.value.mappingToEmailFilterCondition(), + position: simpleSearchFilter.value.position, + filter: simpleSearchFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), properties: EmailUtils.getPropertiesForEmailGetMethod(session!, accountId!), lastEmailId: lastEmail.id )); @@ -407,7 +432,8 @@ class SearchEmailController extends BaseController setTextInputSearchForm(query); _updateSimpleSearchFilter( textOption: Some(SearchQuery(query)), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); _searchEmailAction(context); } @@ -416,7 +442,8 @@ class SearchEmailController extends BaseController setTextInputSearchForm(recentSearch.value); _updateSimpleSearchFilter( textOption: Some(SearchQuery(recentSearch.value)), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); _searchEmailAction(context); } @@ -424,7 +451,8 @@ class SearchEmailController extends BaseController void submitSearchAction(BuildContext context, String query) { _updateSimpleSearchFilter( textOption: Some(SearchQuery(query)), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); _searchEmailAction(context); } @@ -453,19 +481,22 @@ class SearchEmailController extends BaseController case QuickSearchFilter.hasAttachment: _updateSimpleSearchFilter( hasAttachmentOption: Some(!filterSelected), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); break; case QuickSearchFilter.last7Days: _updateSimpleSearchFilter( emailReceiveTimeTypeOption: optionOf(emailReceiveTimeType.value), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); break; case QuickSearchFilter.sortBy: _updateSimpleSearchFilter( sortOrderOption: emailSortOrderType.value.getSortOrder(), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); default: break; @@ -493,6 +524,7 @@ class SearchEmailController extends BaseController beforeOption: const None(), startDateOption: optionOf(newStartDate?.toUTCDate()), endDateOption: optionOf(newEndDate?.toUTCDate()), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); _setEmailReceiveTimeType(emailReceiveTimeType); @@ -507,7 +539,8 @@ class SearchEmailController extends BaseController : optionOf(simpleSearchFilter.value.text), beforeOption: const None(), startDateOption: const None(), - endDateOption: const None() + endDateOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); _setEmailReceiveTimeType(emailReceiveTimeType); @@ -519,7 +552,8 @@ class SearchEmailController extends BaseController popBack(); _updateSimpleSearchFilter( sortOrderOption: sortOrderType.getSortOrder(), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); emailSortOrderType.value = sortOrderType; _searchEmailAction(context); @@ -541,7 +575,8 @@ class SearchEmailController extends BaseController if (mailboxSelected != null && mailbox?.id != mailboxSelected.id) { _updateSimpleSearchFilter( mailboxOption: Some(mailboxSelected), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); if (context.mounted) { @@ -615,13 +650,15 @@ class SearchEmailController extends BaseController case PrefixEmailAddress.from: _updateSimpleSearchFilter( fromOption: Some(simpleSearchFilter.value.from), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); break; case PrefixEmailAddress.to: _updateSimpleSearchFilter( toOption: Some(simpleSearchFilter.value.to), - beforeOption: const None() + beforeOption: const None(), + positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() ); break; default: @@ -642,6 +679,7 @@ class SearchEmailController extends BaseController Option? startDateOption, Option? endDateOption, Option>? sortOrderOption, + Option? positionOption, }) { simpleSearchFilter.value = simpleSearchFilter.value.copyWith( fromOption: fromOption, @@ -653,7 +691,8 @@ class SearchEmailController extends BaseController beforeOption: beforeOption, startDateOption: startDateOption, endDateOption: endDateOption, - sortOrderOption: sortOrderOption + sortOrderOption: sortOrderOption, + positionOption: positionOption, ); simpleSearchFilter.refresh(); } diff --git a/lib/features/thread/data/datasource/thread_datasource.dart b/lib/features/thread/data/datasource/thread_datasource.dart index ac6c1b02c..aa602acc3 100644 --- a/lib/features/thread/data/datasource/thread_datasource.dart +++ b/lib/features/thread/data/datasource/thread_datasource.dart @@ -21,6 +21,7 @@ abstract class ThreadDataSource { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties diff --git a/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart b/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart index 6047005d0..21d6f9987 100644 --- a/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart +++ b/lib/features/thread/data/datasource_impl/local_thread_datasource_impl.dart @@ -31,6 +31,7 @@ class LocalThreadDataSourceImpl extends ThreadDataSource { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties diff --git a/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart b/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart index 1175f8dc0..f7933b068 100644 --- a/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart +++ b/lib/features/thread/data/datasource_impl/thread_datasource_impl.dart @@ -14,9 +14,9 @@ import 'package:model/email/presentation_email.dart'; import 'package:model/extensions/email_extension.dart'; import 'package:tmail_ui_user/features/thread/data/datasource/thread_datasource.dart'; import 'package:tmail_ui_user/features/thread/data/model/email_change_response.dart'; +import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/data/network/thread_isolate_worker.dart'; import 'package:tmail_ui_user/features/thread/domain/model/email_response.dart'; -import 'package:tmail_ui_user/features/thread/data/network/thread_api.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/main/exceptions/exception_thrower.dart'; @@ -38,6 +38,7 @@ class ThreadDataSourceImpl extends ThreadDataSource { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties, @@ -48,6 +49,7 @@ class ThreadDataSourceImpl extends ThreadDataSource { session, accountId, limit: limit, + position: position, sort: sort, filter: filter, properties: properties); diff --git a/lib/features/thread/data/network/thread_api.dart b/lib/features/thread/data/network/thread_api.dart index a8737ae4d..93cc0ff5c 100644 --- a/lib/features/thread/data/network/thread_api.dart +++ b/lib/features/thread/data/network/thread_api.dart @@ -31,6 +31,7 @@ class ThreadAPI { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties @@ -44,6 +45,8 @@ class ThreadAPI { if (limit != null) queryEmailMethod.addLimit(limit); + if (position != null) queryEmailMethod.addPosition(position); + if (sort != null) queryEmailMethod.addSorts(sort); if (filter != null) queryEmailMethod.addFilters(filter); diff --git a/lib/features/thread/data/repository/thread_repository_impl.dart b/lib/features/thread/data/repository/thread_repository_impl.dart index acd9a2a8a..a3721f83e 100644 --- a/lib/features/thread/data/repository/thread_repository_impl.dart +++ b/lib/features/thread/data/repository/thread_repository_impl.dart @@ -39,6 +39,7 @@ class ThreadRepositoryImpl extends ThreadRepository { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, EmailFilter? emailFilter, Properties? propertiesCreated, @@ -67,6 +68,7 @@ class ThreadRepositoryImpl extends ThreadRepository { session, accountId, limit: limit, + position: position, sort: sort, filter: emailFilter?.filter, properties: propertiesCreated); @@ -75,6 +77,7 @@ class ThreadRepositoryImpl extends ThreadRepository { session, accountId, sort: sort, + position: position, mailboxId: emailFilter?.mailboxId, propertiesCreated: propertiesCreated, ); @@ -131,6 +134,7 @@ class ThreadRepositoryImpl extends ThreadRepository { AccountId accountId, { Set? sort, + int? position, MailboxId? mailboxId, Properties? propertiesCreated, Filter? filter, @@ -140,6 +144,7 @@ class ThreadRepositoryImpl extends ThreadRepository { session, accountId, limit: ThreadConstants.defaultLimit, + position: position, sort: sort, filter: filter ?? EmailFilterCondition(inMailbox: mailboxId), properties: propertiesCreated, @@ -266,6 +271,7 @@ class ThreadRepositoryImpl extends ThreadRepository { emailRequest.session, emailRequest.accountId, limit: emailRequest.limit, + position: emailRequest.position, sort: emailRequest.sort, filter: emailRequest.filter, properties: emailRequest.properties) @@ -283,6 +289,7 @@ class ThreadRepositoryImpl extends ThreadRepository { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties @@ -292,6 +299,7 @@ class ThreadRepositoryImpl extends ThreadRepository { session, accountId, limit: limit, + position: position, sort: sort, filter: filter, properties: properties); diff --git a/lib/features/thread/domain/model/get_email_request.dart b/lib/features/thread/domain/model/get_email_request.dart index d443288c4..429fa7b18 100644 --- a/lib/features/thread/domain/model/get_email_request.dart +++ b/lib/features/thread/domain/model/get_email_request.dart @@ -3,15 +3,16 @@ import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; class GetEmailRequest with EquatableMixin { final Session session; final AccountId accountId; final UnsignedInt? limit; + final int? position; final Set? sort; final Filter? filter; final FilterMessageOption? filterOption; @@ -23,6 +24,7 @@ class GetEmailRequest with EquatableMixin { this.accountId, { this.limit, + this.position, this.sort, this.filter, this.filterOption, @@ -36,6 +38,7 @@ class GetEmailRequest with EquatableMixin { session, accountId, limit, + position, sort, filter, properties, diff --git a/lib/features/thread/domain/repository/thread_repository.dart b/lib/features/thread/domain/repository/thread_repository.dart index 90cbd1712..c1ba1e180 100644 --- a/lib/features/thread/domain/repository/thread_repository.dart +++ b/lib/features/thread/domain/repository/thread_repository.dart @@ -46,6 +46,7 @@ abstract class ThreadRepository { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties, diff --git a/lib/features/thread/domain/usecases/search_email_interactor.dart b/lib/features/thread/domain/usecases/search_email_interactor.dart index a84318bb8..2646f834d 100644 --- a/lib/features/thread/domain/usecases/search_email_interactor.dart +++ b/lib/features/thread/domain/usecases/search_email_interactor.dart @@ -1,13 +1,13 @@ import 'package:core/core.dart'; -import 'package:jmap_dart_client/jmap/core/session/session.dart'; -import 'package:model/model.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; -import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:model/model.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart'; @@ -22,6 +22,7 @@ class SearchEmailInteractor { AccountId accountId, { UnsignedInt? limit, + int? position, Set? sort, Filter? filter, Properties? properties, @@ -34,6 +35,7 @@ class SearchEmailInteractor { session, accountId, limit: limit, + position: position, sort: sort, filter: filter, properties: properties); diff --git a/lib/features/thread/domain/usecases/search_more_email_interactor.dart b/lib/features/thread/domain/usecases/search_more_email_interactor.dart index c25ef39f5..20163320f 100644 --- a/lib/features/thread/domain/usecases/search_more_email_interactor.dart +++ b/lib/features/thread/domain/usecases/search_more_email_interactor.dart @@ -1,14 +1,14 @@ import 'package:core/core.dart'; -import 'package:jmap_dart_client/jmap/core/session/session.dart'; -import 'package:jmap_dart_client/jmap/mail/email/email.dart'; -import 'package:model/model.dart'; import 'package:dartz/dartz.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/filter/filter.dart'; import 'package:jmap_dart_client/jmap/core/properties/properties.dart'; -import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/core/sort/comparator.dart'; +import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email.dart'; +import 'package:model/model.dart'; import 'package:tmail_ui_user/features/thread/domain/repository/thread_repository.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart'; @@ -24,6 +24,7 @@ class SearchMoreEmailInteractor { { UnsignedInt? limit, Set? sort, + int? position, Filter? filter, Properties? properties, EmailId? lastEmailId @@ -36,6 +37,7 @@ class SearchMoreEmailInteractor { session, accountId, limit: limit, + position: position, sort: sort, filter: filter, properties: properties); diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index ef2e015c0..b498aab27 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -536,6 +536,7 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, limit: ThreadConstants.defaultLimit, + position: _searchEmailFilter.position, sort: _searchEmailFilter.sortOrder ?? _sortOrder, filterOption: mailboxDashBoardController.filterMessageOption.value, filter: _getFilterCondition(oldestEmail: oldestEmail, mailboxIdSelected: _currentMailboxId), @@ -726,7 +727,18 @@ class ThreadController extends BaseController with EmailActionController { } mailboxDashBoardController.emailsInCurrentMailbox.clear(); canSearchMore = true; - searchController.updateFilterEmail(beforeOption: const None()); + + if (searchController.sortOrderFiltered.value.isScrollByPosition()) { + searchController.updateFilterEmail( + positionOption: const Some(0), + beforeOption: const None(), + ); + } else { + searchController.updateFilterEmail( + positionOption: const None(), + beforeOption: const None(), + ); + } searchController.activateSimpleSearch(); @@ -734,8 +746,12 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, limit: limit ?? ThreadConstants.defaultLimit, + position: _searchEmailFilter.position, sort: _searchEmailFilter.sortOrder, - filter: _searchEmailFilter.mappingToEmailFilterCondition(moreFilterCondition: _getFilterCondition()), + filter: _searchEmailFilter.mappingToEmailFilterCondition( + sortOrderType: searchController.sortOrderFiltered.value, + moreFilterCondition: _getFilterCondition() + ), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), )); } else { @@ -783,20 +799,30 @@ class ThreadController extends BaseController with EmailActionController { final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty ? mailboxDashBoardController.emailsInCurrentMailbox.last : null; - final firstEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty - ? mailboxDashBoardController.emailsInCurrentMailbox.first - : null; - if (optionOf(_searchEmailFilter.sortOrder).toString() == EmailSortOrderType.oldest.getSortOrder().toString()) { - searchController.updateFilterEmail(beforeOption: optionOf(firstEmail?.receivedAt)); + + if (searchController.sortOrderFiltered.value.isScrollByPosition()) { + final nextPosition = mailboxDashBoardController.emailsInCurrentMailbox.length; + log('ThreadController::searchMoreEmails:nextPosition: $nextPosition'); + searchController.updateFilterEmail( + positionOption: Some(nextPosition), + beforeOption: const None() + ); + } else if (searchController.sortOrderFiltered.value == EmailSortOrderType.oldest) { + searchController.updateFilterEmail(startDateOption: optionOf(lastEmail?.receivedAt)); } else { searchController.updateFilterEmail(beforeOption: optionOf(lastEmail?.receivedAt)); } + consumeState(_searchMoreEmailInteractor.execute( _session!, _accountId!, limit: ThreadConstants.defaultLimit, sort: _searchEmailFilter.sortOrder ?? _sortOrder, - filter: _searchEmailFilter.mappingToEmailFilterCondition(moreFilterCondition: _getFilterCondition()), + position: _searchEmailFilter.position, + filter: _searchEmailFilter.mappingToEmailFilterCondition( + sortOrderType: searchController.sortOrderFiltered.value, + moreFilterCondition: _getFilterCondition() + ), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), lastEmailId: lastEmail?.id )); diff --git a/model/pubspec.lock b/model/pubspec.lock index 4a07b3bd0..d46b67865 100644 --- a/model/pubspec.lock +++ b/model/pubspec.lock @@ -168,6 +168,14 @@ packages: relative: true source: path version: "1.0.0+1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "2f9d2cbccb76127ba28528cb3ae2c2326a122446a83de5a056aaa3880d3882c5" + url: "https://pub.dev" + source: hosted + version: "0.3.3+7" crypto: dependency: transitive description: @@ -297,10 +305,42 @@ packages: dependency: transitive description: name: flutter_image_compress - sha256: "37f1b26399098e5f97b74c1483f534855e7dff68ead6ddaccf747029fb03f29f" + sha256: f159d2e8c4ed04b8e36994124fd4a5017a0f01e831ae3358c74095c340e9ae5e url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "2.1.0" + flutter_image_compress_common: + dependency: transitive + description: + name: flutter_image_compress_common + sha256: "7cad12802628706655920089cfe9ee1d1098300e7f39a079eb160458bbc47652" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + flutter_image_compress_macos: + dependency: transitive + description: + name: flutter_image_compress_macos + sha256: fea1e3d71150d03373916b832c49b5c2f56c3e7e13da82a929274a2c6f88251e + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter_image_compress_platform_interface: + dependency: transitive + description: + name: flutter_image_compress_platform_interface + sha256: eb4f055138b29b04498ebcb6d569aaaee34b64d75fb74ea0d40f9790bf47ee9d + url: "https://pub.dev" + source: hosted + version: "1.0.3" + flutter_image_compress_web: + dependency: transitive + description: + name: flutter_image_compress_web + sha256: da41cc3859f19d11c7d10be615f6a9dcf0907e7daffde7442bf4cc2486663660 + url: "https://pub.dev" + source: hosted + version: "0.1.3+2" flutter_inappwebview: dependency: transitive description: