diff --git a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart index b1686a61f4..2ba5d48bc7 100644 --- a/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart +++ b/lib/features/mailbox_dashboard/presentation/action/dashboard_action.dart @@ -6,7 +6,6 @@ import 'package:model/email/presentation_email.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/base/action/ui_action.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/quick_search_filter.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; @@ -56,15 +55,6 @@ class OpenEmailDetailedFromSuggestionQuickSearchAction extends DashBoardAction { class StartSearchEmailAction extends DashBoardAction {} -class StartSearchEmailBySearchFilterAction extends DashBoardAction { - final QuickSearchFilter searchFilter; - - StartSearchEmailBySearchFilterAction(this.searchFilter); - - @override - List get props => [searchFilter]; -} - class EmptyTrashAction extends DashBoardAction {} class ClearSearchEmailAction extends DashBoardAction {} @@ -139,11 +129,11 @@ class ClearDateRangeToAdvancedSearch extends DashBoardAction { List get props => [receiveTime]; } -class SearchEmailByFromFieldsAction extends DashBoardAction { +class QuickSearchEmailByFromAction extends DashBoardAction { final EmailAddress emailAddress; - SearchEmailByFromFieldsAction(this.emailAddress); + QuickSearchEmailByFromAction(this.emailAddress); @override List get props => [emailAddress]; diff --git a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart index be86cd3ef9..e91de1fd39 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart @@ -3,6 +3,7 @@ import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/model.dart'; import 'package:super_tag_editor/tag_editor.dart'; @@ -20,7 +21,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.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/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart'; import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; @@ -32,10 +32,11 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class AdvancedFilterController extends BaseController { GetAutoCompleteInteractor? _getAutoCompleteInteractor; - final dateFilterSelectedFormAdvancedSearch = EmailReceiveTimeType.allTime.obs; + final receiveTimeType = EmailReceiveTimeType.allTime.obs; final hasAttachment = false.obs; final startDate = Rxn(); final endDate = Rxn(); + final sortOrderType = EmailSortOrderType.mostRecent.obs; final GlobalKey keyFromEmailTagEditor = GlobalKey(); final GlobalKey keyToEmailTagEditor = GlobalKey(); @@ -55,10 +56,8 @@ class AdvancedFilterController extends BaseController { final search.SearchController searchController = Get.find(); final MailboxDashBoardController _mailboxDashBoardController = Get.find(); - SearchEmailFilter get searchEmailFilter => - searchController.searchEmailFilter.value; - final focusManager = InputFieldFocusManager.initial(); + SearchEmailFilter _memorySearchFilter = SearchEmailFilter.initial(); PresentationMailbox? _destinationMailboxSelected; @@ -80,87 +79,144 @@ class AdvancedFilterController extends BaseController { } void clearSearchFilter() { + _memorySearchFilter = SearchEmailFilter.initial(); _resetAllToOriginalValue(); _clearAllTextFieldInput(); _mailboxDashBoardController.handleClearAdvancedSearchFilterEmail(); } - void _updateFilterEmailFromAdvancedSearchView() { - if (hasKeyWordFilterInputController.text.isNotEmpty) { - searchController.updateFilterEmail( - textOption: Some(SearchQuery(hasKeyWordFilterInputController.text))); - searchController.searchInputController.text = hasKeyWordFilterInputController.text; - } else { - searchController.updateFilterEmail( - textOption: Some(SearchQuery.initial())); - } - - if (notKeyWordFilterInputController.text.isNotEmpty) { - searchController.updateFilterEmail( - notKeywordOption: Some(notKeyWordFilterInputController.text.split(',').toSet())); - } else { - searchController.updateFilterEmail(notKeywordOption: const None()); - } - - if (listFromEmailAddress.isNotEmpty) { - final listAddress = listFromEmailAddress.map((emailAddress) => emailAddress.emailAddress).toSet(); - searchController.updateFilterEmail(fromOption: Some(listAddress)); - } else { - searchController.updateFilterEmail(fromOption: const None()); - } - if (listToEmailAddress.isNotEmpty) { - final listAddress = listToEmailAddress.map((emailAddress) => emailAddress.emailAddress).toSet(); - searchController.updateFilterEmail(toOption: Some(listAddress)); - } else { - searchController.updateFilterEmail(toOption: const None()); - } - - searchController.updateFilterEmail( - mailboxOption: optionOf(_destinationMailboxSelected), - subjectOption: optionOf(subjectFilterInputController.text), - emailReceiveTimeTypeOption: optionOf(dateFilterSelectedFormAdvancedSearch.value), - hasAttachmentOption: optionOf(hasAttachment.value), - startDateOption: optionOf(startDate.value?.toUTCDate()), - endDateOption: optionOf(endDate.value?.toUTCDate()) + @visibleForTesting + void setDestinationMailboxSelected(PresentationMailbox? presentationMailbox) { + _destinationMailboxSelected = presentationMailbox; + } + + @visibleForTesting + SearchEmailFilter get memorySearchFilter => _memorySearchFilter; + + @visibleForTesting + void setMemorySearchFilter(SearchEmailFilter searchFilter) { + _memorySearchFilter = searchFilter; + } + + @visibleForTesting + MailboxDashBoardController get mailboxDashBoardController => _mailboxDashBoardController; + + void _updateMemorySearchFilter({ + Option>? fromOption, + Option>? toOption, + Option? textOption, + Option? subjectOption, + Option>? notKeywordOption, + Option? mailboxOption, + Option? emailReceiveTimeTypeOption, + Option? hasAttachmentOption, + Option? beforeOption, + Option? startDateOption, + Option? endDateOption, + Option? positionOption, + Option? sortOrderTypeOption, + }) { + _memorySearchFilter = _memorySearchFilter.copyWith( + fromOption: fromOption, + toOption: toOption, + textOption: textOption, + subjectOption: subjectOption, + notKeywordOption: notKeywordOption, + mailboxOption: mailboxOption, + emailReceiveTimeTypeOption: emailReceiveTimeTypeOption, + hasAttachmentOption: hasAttachmentOption, + beforeOption: beforeOption, + startDateOption: startDateOption, + endDateOption: endDateOption, + positionOption: positionOption, + sortOrderTypeOption: sortOrderTypeOption); + } + + void _synchronizeSearchFilter() { + final textOption = option( + hasKeyWordFilterInputController.text.trim().isNotEmpty, + SearchQuery(hasKeyWordFilterInputController.text.trim())); + + final notKeywordsOption = option( + notKeyWordFilterInputController.text.trim().isNotEmpty, + notKeyWordFilterInputController.text.trim().split(',').map((value) => value.trim()).toSet()); + + final fromOption = option( + listFromEmailAddress.isNotEmpty, + listFromEmailAddress.asSetAddress()); + + final toOption = option( + listToEmailAddress.isNotEmpty, + listToEmailAddress.asSetAddress()); + + final sortOrderTypeOption = Some(sortOrderType.value); + + final mailboxOption = optionOf(_destinationMailboxSelected); + + final subjectOption = option( + subjectFilterInputController.text.trim().isNotEmpty, + subjectFilterInputController.text.trim()); + + final emailReceiveTimeTypeOption = Some(receiveTimeType.value); + + final hasAttachmentOption = Some(hasAttachment.value); + + final startDateOption = optionOf(startDate.value?.toUTCDate()); + + final endDateOption = optionOf(endDate.value?.toUTCDate()); + + _updateMemorySearchFilter( + textOption: textOption, + notKeywordOption: notKeywordsOption, + fromOption: fromOption, + toOption: toOption, + sortOrderTypeOption: sortOrderTypeOption, + mailboxOption: mailboxOption, + subjectOption: subjectOption, + emailReceiveTimeTypeOption: emailReceiveTimeTypeOption, + hasAttachmentOption: hasAttachmentOption, + startDateOption: startDateOption, + endDateOption: endDateOption ); + + searchController.synchronizeSearchFilter(_memorySearchFilter); } void selectedMailBox(BuildContext context) async { final accountId = _mailboxDashBoardController.accountId.value; final session = _mailboxDashBoardController.sessionCurrent; - if (accountId != null && session != null) { - final arguments = DestinationPickerArguments( - accountId, - MailboxActions.select, - session, - mailboxIdSelected: _destinationMailboxSelected?.id - ); - final destinationMailbox = PlatformInfo.isWeb - ? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.destinationPicker, arguments: arguments) - : await push(AppRoutes.destinationPicker, arguments: arguments); - - if (destinationMailbox is PresentationMailbox) { - _destinationMailboxSelected = destinationMailbox; - String? mailboxName; - if (context.mounted) { - mailboxName = _destinationMailboxSelected?.getDisplayName(context); - } else { - mailboxName = _destinationMailboxSelected?.name?.name; - } - mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(mailboxName); - } - } + if (session == null || accountId == null) return; + + final arguments = DestinationPickerArguments( + accountId, + MailboxActions.select, + session, + mailboxIdSelected: _destinationMailboxSelected?.id + ); + + final destinationMailbox = PlatformInfo.isWeb + ? await DialogRouter.pushGeneralDialog( + routeName: AppRoutes.destinationPicker, + arguments: arguments) + : await push(AppRoutes.destinationPicker, arguments: arguments); + + if (destinationMailbox is! PresentationMailbox) return; + + _destinationMailboxSelected = destinationMailbox; + final mailboxName = context.mounted + ? _destinationMailboxSelected?.getDisplayName(context) + : _destinationMailboxSelected?.name?.name; + mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(mailboxName); + _updateMemorySearchFilter(mailboxOption: optionOf(_destinationMailboxSelected)); } void applyAdvancedSearchFilter() { - _updateFilterEmailFromAdvancedSearchView(); - if (isAdvancedSearchHasApplied) { + _synchronizeSearchFilter(); + if (searchController.searchEmailFilter.value.isApplied) { searchController.activateAdvancedSearch(); } else { searchController.deactivateAdvancedSearch(); - } - if (!isAdvancedSearchHasApplied) { searchController.updateFilterEmail(beforeOption: const None()); } searchController.isAdvancedSearchViewOpen.value = false; @@ -183,43 +239,48 @@ class AdvancedFilterController extends BaseController { )) ?? []; } - bool get isAdvancedSearchHasApplied { - return searchEmailFilter.from.isNotEmpty || - searchEmailFilter.to.isNotEmpty || - subjectFilterInputController.text.isNotEmpty || - hasKeyWordFilterInputController.text.isNotEmpty || - notKeyWordFilterInputController.text.isNotEmpty || - searchEmailFilter.emailReceiveTimeType != EmailReceiveTimeType.allTime || - searchEmailFilter.mailbox != PresentationMailbox.unifiedMailbox || - hasAttachment.isTrue; - } - - void initSearchFilterField() { - subjectFilterInputController.text = StringConvert.writeNullToEmpty(searchEmailFilter.subject); - hasKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(searchEmailFilter.text?.value); - notKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(searchEmailFilter.notKeyword.firstOrNull); - dateFilterSelectedFormAdvancedSearch.value = searchEmailFilter.emailReceiveTimeType; - _destinationMailboxSelected = searchEmailFilter.mailbox; - if (currentContext != null) { - if (searchEmailFilter.mailbox == null) { - mailBoxFilterInputController.text = AppLocalizations.of(currentContext!).allFolders; - } else { - mailBoxFilterInputController.text = StringConvert.writeNullToEmpty( - searchEmailFilter.mailbox?.getDisplayName(currentContext!) - ); - } - } - hasAttachment.value = searchEmailFilter.hasAttachment; - if (searchEmailFilter.from.isEmpty) { + void initSearchFilterField(BuildContext? context) { + subjectFilterInputController.text = StringConvert.writeNullToEmpty( + _memorySearchFilter.subject); + + hasKeyWordFilterInputController.text = StringConvert.writeNullToEmpty( + _memorySearchFilter.text?.value); + + notKeyWordFilterInputController.text = StringConvert.writeNullToEmpty( + _memorySearchFilter.notKeyword.join(',')); + + receiveTimeType.value = _memorySearchFilter.emailReceiveTimeType; + + sortOrderType.value = _memorySearchFilter.sortOrderType; + + _destinationMailboxSelected = _memorySearchFilter.mailbox; + + hasAttachment.value = _memorySearchFilter.hasAttachment; + + if (_memorySearchFilter.from.isEmpty) { listFromEmailAddress.clear(); } else { + final listEmailAddress = _memorySearchFilter.from + .map((email) => EmailAddress(null, email)); + listFromEmailAddress = List.from(listEmailAddress); fromAddressExpandMode.value = ExpandMode.COLLAPSE; } - if (searchEmailFilter.to.isEmpty) { + + if (_memorySearchFilter.to.isEmpty) { listToEmailAddress.clear(); } else { + final listEmailAddress = _memorySearchFilter.to + .map((email) => EmailAddress(null, email)); + listToEmailAddress = List.from(listEmailAddress); toAddressExpandMode.value = ExpandMode.COLLAPSE; } + + if (context != null) { + mailBoxFilterInputController.text = _memorySearchFilter.mailbox == null + ? AppLocalizations.of(context).allFolders + : StringConvert.writeNullToEmpty( + _memorySearchFilter.mailbox?.getDisplayName(context)); + } } void selectDateRange(BuildContext context) { @@ -239,7 +300,13 @@ class AdvancedFilterController extends BaseController { void _updateDateRangeTime(EmailReceiveTimeType receiveTime, {DateTime? newStartDate, DateTime? newEndDate}) { startDate.value = newStartDate; endDate.value = newEndDate; - dateFilterSelectedFormAdvancedSearch.value = receiveTime; + receiveTimeType.value = receiveTime; + + _updateMemorySearchFilter( + emailReceiveTimeTypeOption: Some(receiveTimeType.value), + startDateOption: optionOf(startDate.value?.toUTCDate()), + endDateOption: optionOf(endDate.value?.toUTCDate()) + ); } void updateReceiveDateSearchFilter(BuildContext context, EmailReceiveTimeType receiveTime) { @@ -314,9 +381,17 @@ class AdvancedFilterController extends BaseController { switch(field) { case AdvancedSearchFilterField.from: listFromEmailAddress = List.from(listEmailAddress); + _updateMemorySearchFilter( + fromOption: option( + listFromEmailAddress.isNotEmpty, + listFromEmailAddress.asSetAddress())); break; case AdvancedSearchFilterField.to: listToEmailAddress = List.from(listEmailAddress); + _updateMemorySearchFilter( + toOption: option( + listToEmailAddress.isNotEmpty, + listToEmailAddress.asSetAddress())); break; default: break; @@ -339,6 +414,7 @@ class AdvancedFilterController extends BaseController { if (!_isDuplicatedEmailAddress(inputEmail, listFromEmailAddress)) { final emailAddress = EmailAddress(null, inputEmail); listFromEmailAddress.add(emailAddress); + _updateMemorySearchFilter(fromOption: Some(listFromEmailAddress.asSetAddress())); keyFromEmailTagEditor.currentState?.resetTextField(); Future.delayed(const Duration(milliseconds: 300), () { keyFromEmailTagEditor.currentState?.closeSuggestionBox(); @@ -353,8 +429,8 @@ class AdvancedFilterController extends BaseController { } if (!_isDuplicatedEmailAddress(inputEmail, listToEmailAddress)) { - final emailAddress = EmailAddress(null, inputEmail); - listToEmailAddress.add(emailAddress); + listToEmailAddress.add(EmailAddress(null, inputEmail)); + _updateMemorySearchFilter(toOption: Some(listToEmailAddress.asSetAddress())); keyToEmailTagEditor.currentState?.resetTextField(); Future.delayed(const Duration(milliseconds: 300), () { keyToEmailTagEditor.currentState?.closeSuggestionBox(); @@ -364,12 +440,15 @@ class AdvancedFilterController extends BaseController { void updateSortOrder(EmailSortOrderType? sortOrder) { if (sortOrder != null) { - searchController.sortOrderFiltered.value = sortOrder; + sortOrderType.value = sortOrder; + _updateMemorySearchFilter(sortOrderTypeOption: Some(sortOrder)); } } void _resetAllToOriginalValue() { - _updateDateRangeTime(EmailReceiveTimeType.allTime); + startDate.value = null; + endDate.value = null; + receiveTimeType.value = EmailReceiveTimeType.allTime; hasAttachment.value = false; listFromEmailAddress.clear(); listToEmailAddress.clear(); @@ -399,23 +478,12 @@ class AdvancedFilterController extends BaseController { ); } else if (action is ClearDateRangeToAdvancedSearch) { _updateDateRangeTime(action.receiveTime); - } else if (action is StartSearchEmailBySearchFilterAction) { - _handleSearchEmailBySearchFilterAction(action.searchFilter); - } else if (action is SearchEmailByFromFieldsAction) { - searchController.clearSearchFilter(); - _resetAllToOriginalValue(); - _clearAllTextFieldInput(); - searchController.searchInputController.clear(); - searchController.deactivateAdvancedSearch(); - searchController.isAdvancedSearchViewOpen.value = false; - - listFromEmailAddress = List.from({action.emailAddress}); - final listAddress = listFromEmailAddress.map((emailAddress) => emailAddress.emailAddress).toSet(); - searchController.updateFilterEmail(fromOption: Some(listAddress)); - - _mailboxDashBoardController.dispatchAction(StartSearchEmailAction()); + } else if (action is StartSearchEmailAction) { + _handleStartSearchEmailAction(); + } else if (action is QuickSearchEmailByFromAction) { + _handleQuickSearchEmailByFromAction(action.emailAddress); } else if (action is OpenAdvancedSearchViewAction) { - initSearchFilterField(); + initSearchFilterField(currentContext); } else if (action is ClearSearchFilterAppliedAction) { clearSearchFilter(); } @@ -440,38 +508,41 @@ class AdvancedFilterController extends BaseController { void _handleClearAllFieldOfAdvancedSearch() { _resetAllToOriginalValue(); _clearAllTextFieldInput(); + _memorySearchFilter = SearchEmailFilter.initial(); } - void _updateFromField() { - if (searchEmailFilter.from.isNotEmpty) { - listFromEmailAddress = List.from( - searchEmailFilter.from.map((address) => EmailAddress(null, address))); - } else { - listFromEmailAddress.clear(); - } + void onSearchAction() { + FocusManager.instance.primaryFocus?.unfocus(); + applyAdvancedSearchFilter(); } - void _updateToField() { - if (searchEmailFilter.to.isNotEmpty) { - listToEmailAddress = List.from( - searchEmailFilter.to.map((address) => EmailAddress(null, address))); - } else { - listToEmailAddress.clear(); - } + void _handleStartSearchEmailAction() { + _memorySearchFilter = searchController.searchEmailFilter.value; + initSearchFilterField(currentContext); } - void onSearchAction() { - FocusManager.instance.primaryFocus?.unfocus(); - applyAdvancedSearchFilter(); + void onHasAttachmentCheckboxChanged(bool? isChecked) { + hasAttachment.value = isChecked ?? false; + _updateMemorySearchFilter(hasAttachmentOption: Some(hasAttachment.value)); } - void _handleSearchEmailBySearchFilterAction(QuickSearchFilter searchFilter) { - switch(searchFilter) { - case QuickSearchFilter.from: - _updateFromField(); + void onTextChanged(AdvancedSearchFilterField filterField, String value) { + switch (filterField) { + case AdvancedSearchFilterField.subject: + final subjectOption = option(value.trim().isNotEmpty, value.trim()); + _updateMemorySearchFilter(subjectOption: subjectOption); break; - case QuickSearchFilter.to: - _updateToField(); + case AdvancedSearchFilterField.hasKeyword: + final textOption = option( + value.trim().isNotEmpty, + SearchQuery(value.trim())); + _updateMemorySearchFilter(textOption: textOption); + break; + case AdvancedSearchFilterField.notKeyword: + final notKeywordsOption = option( + value.trim().isNotEmpty, + value.trim().split(',').map((value) => value.trim()).toSet()); + _updateMemorySearchFilter(notKeywordOption: notKeywordsOption); break; default: break; @@ -496,6 +567,20 @@ class AdvancedFilterController extends BaseController { } } + void _handleQuickSearchEmailByFromAction(EmailAddress emailAddress) { + searchController.clearSearchFilter(); + _memorySearchFilter = SearchEmailFilter.initial(); + _resetAllToOriginalValue(); + _clearAllTextFieldInput(); + searchController.searchInputController.clear(); + searchController.deactivateAdvancedSearch(); + searchController.isAdvancedSearchViewOpen.value = false; + listFromEmailAddress = List.from({emailAddress}); + searchController.updateFilterEmail(fromOption: Some(listFromEmailAddress.asSetAddress())); + _updateMemorySearchFilter(fromOption: Some(listFromEmailAddress.asSetAddress())); + _mailboxDashBoardController.dispatchAction(StartSearchEmailAction()); + } + @override void onClose() { _removeFocusListener(); @@ -507,6 +592,8 @@ class AdvancedFilterController extends BaseController { toEmailAddressController.dispose(); fromEmailAddressController.dispose(); _unregisterWorkerListener(); + _resetAllToOriginalValue(); + _memorySearchFilter = SearchEmailFilter.initial(); super.onClose(); } } 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 75e48815ea..23191f91cf 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -669,7 +669,6 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo void handleAdvancedSearchEmail() { log('MailboxDashBoardController::handleAdvancedSearchEmail:'); - clearFilterMessageOption(); if (_searchInsideEmailDetailedViewIsActive()) { _closeEmailDetailedView(); } @@ -711,11 +710,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo FocusManager.instance.primaryFocus?.unfocus(); - if (isMailAddress) { - dispatchAction(StartSearchEmailBySearchFilterAction(QuickSearchFilter.from)); - } else { - dispatchAction(StartSearchEmailAction()); - } + dispatchAction(StartSearchEmailAction()); } bool _searchInsideEmailDetailedViewIsActive() { @@ -1715,7 +1710,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo .map((emailAddress) => emailAddress.emailAddress) .toSet(); searchController.updateFilterEmail(fromOption: Some(listMailAddress)); - dispatchAction(StartSearchEmailBySearchFilterAction(QuickSearchFilter.from)); + dispatchAction(StartSearchEmailAction()); } } @@ -1738,7 +1733,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo .map((emailAddress) => emailAddress.emailAddress) .toSet(); searchController.updateFilterEmail(toOption: Some(listMailAddress)); - dispatchAction(StartSearchEmailBySearchFilterAction(QuickSearchFilter.to)); + dispatchAction(StartSearchEmailAction()); } } @@ -1805,7 +1800,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo void selectSortOrderQuickSearchFilter(EmailSortOrderType sortOrder) { log('MailboxDashBoardController::selectSortOrderQuickSearchFilter():sortOrder: $sortOrder'); popBack(); - searchController.sortOrderFiltered.value = sortOrder; + searchController.updateFilterEmail(sortOrderTypeOption: Some(sortOrder)); dispatchAction(StartSearchEmailAction()); } @@ -1820,18 +1815,19 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo } void _deleteSortOrderSearchFilter() { - searchController.sortOrderFiltered.value = EmailSortOrderType.mostRecent; + searchController.updateFilterEmail( + sortOrderTypeOption: const Some(EmailSortOrderType.mostRecent)); dispatchAction(StartSearchEmailAction()); } void _deleteFromSearchFilter() { searchController.updateFilterEmail(fromOption: const None()); - dispatchAction(StartSearchEmailBySearchFilterAction(QuickSearchFilter.from)); + dispatchAction(StartSearchEmailAction()); } void _deleteToSearchFilter() { searchController.updateFilterEmail(toOption: const None()); - dispatchAction(StartSearchEmailBySearchFilterAction(QuickSearchFilter.to)); + dispatchAction(StartSearchEmailAction()); } void _deleteHasAttachmentSearchFilter() { @@ -2514,7 +2510,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo return listEmailAddress; } - void searchEmailByFromFields(EmailAddress emailAddress) { + void quickSearchEmailByFrom(EmailAddress emailAddress) { FocusManager.instance.primaryFocus?.unfocus(); clearFilterMessageOption(); searchController.clearFilterSuggestion(); @@ -2522,7 +2518,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo _closeEmailDetailedView(); } _unSelectedMailbox(); - dispatchAction(SearchEmailByFromFieldsAction(emailAddress)); + dispatchAction(QuickSearchEmailByFromAction(emailAddress)); } void unsubscribeMail(EmailId emailId) { @@ -2843,7 +2839,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo } bool get isSearchFilterHasApplied { - return searchController.isSearchFilterHasApplied || + return searchController.searchEmailFilter.value.isApplied || filterMessageOption.value != FilterMessageOption.all; } diff --git a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart index 2cccca6449..65f6d88836 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/search_controller.dart @@ -47,7 +47,6 @@ class SearchController extends BaseController with DateRangePickerMixin { final listFilterOnSuggestionForm = RxList(); final simpleSearchIsActivated = RxBool(false); final advancedSearchIsActivated = RxBool(false); - final sortOrderFiltered = EmailSortOrderType.mostRecent.obs; SearchQuery? get searchQuery => searchEmailFilter.value.text; @@ -71,6 +70,10 @@ class SearchController extends BaseController with DateRangePickerMixin { searchEmailFilter.value = SearchEmailFilter.initial(); } + void synchronizeSearchFilter(SearchEmailFilter searchFilter) { + searchEmailFilter.value = searchFilter; + } + void addQuickSearchFilterToSuggestionSearchView(QuickSearchFilter searchFilter) { if (!listFilterOnSuggestionForm.contains(searchFilter)) { listFilterOnSuggestionForm.add(searchFilter); @@ -164,6 +167,7 @@ class SearchController extends BaseController with DateRangePickerMixin { Option? textOption, Option? subjectOption, Option>? notKeywordOption, + Option>? hasKeywordOption, Option? mailboxOption, Option? emailReceiveTimeTypeOption, Option? hasAttachmentOption, @@ -171,6 +175,7 @@ class SearchController extends BaseController with DateRangePickerMixin { Option? startDateOption, Option? endDateOption, Option? positionOption, + Option? sortOrderTypeOption, }) { searchEmailFilter.value = searchEmailFilter.value.copyWith( fromOption: fromOption, @@ -178,6 +183,7 @@ class SearchController extends BaseController with DateRangePickerMixin { textOption: textOption, subjectOption: subjectOption, notKeywordOption: notKeywordOption, + hasKeywordOption: hasKeywordOption, mailboxOption: mailboxOption, emailReceiveTimeTypeOption: emailReceiveTimeTypeOption, hasAttachmentOption: hasAttachmentOption, @@ -185,6 +191,7 @@ class SearchController extends BaseController with DateRangePickerMixin { startDateOption: startDateOption, endDateOption: endDateOption, positionOption: positionOption, + sortOrderTypeOption: sortOrderTypeOption, ); searchEmailFilter.refresh(); } @@ -201,20 +208,13 @@ class SearchController extends BaseController with DateRangePickerMixin { Set get listAddressOfFromFiltered => searchEmailFilter.value.from; + EmailSortOrderType get sortOrderFiltered => searchEmailFilter.value.sortOrderType; + bool isSearchActive() => searchState.value.searchStatus == SearchStatus.ACTIVE; bool get isSearchEmailRunning => simpleSearchIsActivated.isTrue || advancedSearchIsActivated.isTrue; - bool get isSearchFilterHasApplied { - return searchEmailFilter.value.from.isNotEmpty || - searchEmailFilter.value.to.isNotEmpty || - searchEmailFilter.value.emailReceiveTimeType != EmailReceiveTimeType.allTime || - (searchEmailFilter.value.mailbox != PresentationMailbox.unifiedMailbox && searchEmailFilter.value.mailbox != null) || - searchEmailFilter.value.hasAttachment == true || - sortOrderFiltered.value != EmailSortOrderType.mostRecent; - } - void enableSearch() { searchState.value = searchState.value.enableSearchState(); } @@ -277,14 +277,9 @@ class SearchController extends BaseController with DateRangePickerMixin { searchInputController.clear(); searchFocus.unfocus(); } - - void clearSortOrder() { - sortOrderFiltered.value = EmailSortOrderType.mostRecent; - } void clearAllFilterSearch() { _clearAllTextInputSimpleSearch(); - clearSortOrder(); clearFilterSuggestion(); clearSearchFilter(); deactivateAdvancedSearch(); @@ -296,7 +291,6 @@ class SearchController extends BaseController with DateRangePickerMixin { deactivateSimpleSearch(); hideSimpleSearchFormView(); - clearSortOrder(); clearSearchFilter(); deactivateAdvancedSearch(); hideAdvancedSearchFormView(); diff --git a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart index 13b013db16..9b3e329e20 100644 --- a/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart +++ b/lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart @@ -533,7 +533,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { ) { return Obx(() { final searchEmailFilter = controller.searchController.searchEmailFilter.value; - final sortOrderType = controller.searchController.sortOrderFiltered.value; + final sortOrderType = controller.searchController.sortOrderFiltered; final listAddressOfFrom = controller.searchController.listAddressOfFromFiltered; final userName = controller.sessionCurrent?.username; final startDate = controller.searchController.startDateFiltered; @@ -668,7 +668,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView { position, popupMenuEmailSortOrderType( context, - controller.searchController.sortOrderFiltered.value, + controller.searchController.sortOrderFiltered, onCallBack: controller.selectSortOrderQuickSearchFilter ) ); 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 19b428a718..6b5139244a 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 @@ -28,30 +28,33 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin { final UTCDate? startDate; final UTCDate? endDate; final int? position; + final EmailSortOrderType sortOrderType; factory SearchEmailFilter.initial() => SearchEmailFilter(); SearchEmailFilter({ - Set? from, - Set? to, - EmailReceiveTimeType? emailReceiveTimeType, - bool? hasAttachment, this.text, this.subject, - Set? notKeyword, - Set? hasKeyword, this.mailbox, this.before, this.startDate, this.endDate, this.position, + Set? from, + Set? to, + EmailReceiveTimeType? emailReceiveTimeType, + bool? hasAttachment, + Set? notKeyword, + Set? hasKeyword, + EmailSortOrderType? sortOrderType, }) : from = from ?? {}, to = to ?? {}, notKeyword = notKeyword ?? {}, hasKeyword = hasKeyword ?? {}, hasAttachment = hasAttachment ?? false, emailReceiveTimeType = - emailReceiveTimeType ?? EmailReceiveTimeType.allTime; + emailReceiveTimeType ?? EmailReceiveTimeType.allTime, + sortOrderType = sortOrderType ?? EmailSortOrderType.mostRecent; SearchEmailFilter copyWith({ Option>? fromOption, @@ -67,6 +70,7 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin { Option? startDateOption, Option? endDateOption, Option? positionOption, + Option? sortOrderTypeOption, }) { return SearchEmailFilter( from: getOptionParam(fromOption, from), @@ -82,24 +86,24 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin { startDate: getOptionParam(startDateOption, startDate), endDate: getOptionParam(endDateOption, endDate), position: getOptionParam(positionOption, position), + sortOrderType: getOptionParam(sortOrderTypeOption, sortOrderType), ); } Filter? mappingToEmailFilterCondition({ - required EmailSortOrderType sortOrderType, EmailFilterCondition? moreFilterCondition }) { final emailEmailFilterConditionShared = EmailFilterCondition( text: text?.value.trim().isNotEmpty == true - ? text?.value + ? text?.value.trim() : null, inMailbox: mailbox?.mailboxId, after: sortOrderType.isScrollByPosition() ? null : emailReceiveTimeType.getAfterDate(startDate), - hasAttachment: hasAttachment == false ? null : hasAttachment, + hasAttachment: !hasAttachment ? null : hasAttachment, subject: subject?.trim().isNotEmpty == true - ? subject + ? subject?.trim() : null, before: sortOrderType.isScrollByPosition() ? null @@ -145,6 +149,17 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin { } } + bool get isApplied => from.isNotEmpty || + to.isNotEmpty || + text?.value.trim().isNotEmpty == true || + subject?.trim().isNotEmpty == true || + hasKeyword.isNotEmpty == true || + notKeyword.isNotEmpty == true || + emailReceiveTimeType != EmailReceiveTimeType.allTime || + sortOrderType != EmailSortOrderType.mostRecent || + (mailbox != null && mailbox?.id != PresentationMailbox.unifiedMailbox.id) || + hasAttachment; + @override List get props => [ from, @@ -160,5 +175,6 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin { startDate, endDate, position, + sortOrderType ]; } \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart index 218c75b47f..3ed62d63c4 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart @@ -12,11 +12,11 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; class AdvancedSearchFilterFormBottomView extends GetWidget { - final InputFieldFocusManager? focusManager; + final InputFieldFocusManager focusManager; const AdvancedSearchFilterFormBottomView({ Key? key, - this.focusManager, + required this.focusManager, }) : super(key: key); @override @@ -30,8 +30,8 @@ class AdvancedSearchFilterFormBottomView extends GetWidget controller.hasAttachment.value = value ?? false, + onChanged: controller.onHasAttachmentCheckboxChanged, ), ), ); diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dart index 212ee0b41e..9a043c921e 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dart @@ -60,14 +60,22 @@ class AdvancedSearchInputForm extends GetWidget context: context, advancedSearchFilterField: AdvancedSearchFilterField.subject, currentFocusNode: controller.focusManager.subjectFieldFocusNode, - nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode + nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode, + onTextChange: (value) => controller.onTextChanged( + AdvancedSearchFilterField.subject, + value + ), ), _buildFilterField( textEditingController: controller.hasKeyWordFilterInputController, context: context, advancedSearchFilterField: AdvancedSearchFilterField.hasKeyword, currentFocusNode: controller.focusManager.hasKeywordFieldFocusNode, - nextFocusNode: controller.focusManager.notKeywordFieldFocusNode + nextFocusNode: controller.focusManager.notKeywordFieldFocusNode, + onTextChange: (value) => controller.onTextChanged( + AdvancedSearchFilterField.hasKeyword, + value + ), ), _buildFilterField( textEditingController: controller.notKeyWordFilterInputController, @@ -75,6 +83,10 @@ class AdvancedSearchInputForm extends GetWidget advancedSearchFilterField: AdvancedSearchFilterField.notKeyword, currentFocusNode: controller.focusManager.notKeywordFieldFocusNode, nextFocusNode: controller.focusManager.mailboxFieldFocusNode, + onTextChange: (value) => controller.onTextChanged( + AdvancedSearchFilterField.notKeyword, + value + ), ), _buildFilterField( textEditingController: controller.mailBoxFilterInputController, @@ -127,7 +139,7 @@ class AdvancedSearchInputForm extends GetWidget receiveTime.getTitle(context), svgIconSelected: controller.imagePaths.icFilterSelected, maxWidth: 320, - isSelected: controller.dateFilterSelectedFormAdvancedSearch.value == receiveTime, + isSelected: controller.receiveTimeType.value == receiveTime, onCallbackAction: () => controller.updateReceiveDateSearchFilter(context, receiveTime), ))) .toList(); @@ -142,6 +154,7 @@ class AdvancedSearchInputForm extends GetWidget MouseCursor? mouseCursor, FocusNode? currentFocusNode, FocusNode? nextFocusNode, + ValueChanged? onTextChange, }) { final child = [ SizedBox( @@ -166,6 +179,7 @@ class AdvancedSearchInputForm extends GetWidget nextFocusNode: nextFocusNode, advancedSearchFilterField: advancedSearchFilterField, textEditingController: textEditingController, + onTextChange: onTextChange, ) else if (controller.responsiveUtils.landscapeTabletSupported(context)) if (advancedSearchFilterField == AdvancedSearchFilterField.date) @@ -173,13 +187,13 @@ class AdvancedSearchInputForm extends GetWidget controller.imagePaths, startDate: controller.startDate.value, endDate: controller.endDate.value, - receiveTimeSelected: controller.dateFilterSelectedFormAdvancedSearch.value, + receiveTimeSelected: controller.receiveTimeType.value, onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime), )) else if (advancedSearchFilterField == AdvancedSearchFilterField.sortBy) Obx(() => SortByDropDownButton( imagePaths: controller.imagePaths, - sortOrderSelected: controller.searchController.sortOrderFiltered.value, + sortOrderSelected: controller.sortOrderType.value, onSortOrderSelected: controller.updateSortOrder, )) else @@ -192,6 +206,7 @@ class AdvancedSearchInputForm extends GetWidget nextFocusNode: nextFocusNode, advancedSearchFilterField: advancedSearchFilterField, textEditingController: textEditingController, + onTextChange: onTextChange, ) else Expanded( @@ -204,6 +219,7 @@ class AdvancedSearchInputForm extends GetWidget nextFocusNode: nextFocusNode, advancedSearchFilterField: advancedSearchFilterField, textEditingController: textEditingController, + onTextChange: onTextChange, ), ) ]; @@ -229,6 +245,7 @@ class AdvancedSearchInputForm extends GetWidget MouseCursor? mouseCursor, FocusNode? currentFocusNode, FocusNode? nextFocusNode, + ValueChanged? onTextChange, }) { switch (advancedSearchFilterField) { case AdvancedSearchFilterField.date: @@ -236,13 +253,13 @@ class AdvancedSearchInputForm extends GetWidget controller.imagePaths, startDate: controller.startDate.value, endDate: controller.endDate.value, - receiveTimeSelected: controller.dateFilterSelectedFormAdvancedSearch.value, + receiveTimeSelected: controller.receiveTimeType.value, onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime), )); case AdvancedSearchFilterField.sortBy: return Obx(() => SortByDropDownButton( imagePaths: controller.imagePaths, - sortOrderSelected: controller.searchController.sortOrderFiltered.value, + sortOrderSelected: controller.sortOrderType.value, onSortOrderSelected: controller.updateSortOrder, )); default: @@ -255,6 +272,7 @@ class AdvancedSearchInputForm extends GetWidget nextFocusNode: nextFocusNode, advancedSearchFilterField: advancedSearchFilterField, textEditingController: textEditingController, + onTextChange: onTextChange, ); } } @@ -268,6 +286,7 @@ class AdvancedSearchInputForm extends GetWidget MouseCursor? mouseCursor, FocusNode? currentFocusNode, FocusNode? nextFocusNode, + ValueChanged? onTextChange, }) { return KeyboardListener( focusNode: currentFocusNode ?? FocusNode(), @@ -293,6 +312,7 @@ class AdvancedSearchInputForm extends GetWidget popBack(); } }, + onTextChange: onTextChange, decoration: InputDecoration( filled: true, fillColor: isSelectFormList ? AppColor.colorItemSelected : Colors.white, diff --git a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/icon_open_advanced_search_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/icon_open_advanced_search_widget.dart index 93c1c48d73..40318b6d18 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/icon_open_advanced_search_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/advanced_search/icon_open_advanced_search_widget.dart @@ -39,7 +39,7 @@ class IconOpenAdvancedSearchWidget extends StatelessWidget { height: 16), onTap: () { log('IconOpenAdvancedSearchWidget::build(): clicked'); - advancedFilterController.initSearchFilterField(); + advancedFilterController.initSearchFilterField(context); searchController.openAdvanceSearch(); }), ), diff --git a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart index 848711df81..90be1e505f 100644 --- a/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart +++ b/lib/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart @@ -137,7 +137,6 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { } if (queryString.isNotEmpty || _searchController.listFilterOnSuggestionForm.isNotEmpty) { - _searchController.clearSortOrder(); _searchController.clearSearchFilter(); _searchController.applyFilterSuggestionToSearchFilter(_dashBoardController.sessionCurrent?.username); _dashBoardController.searchEmailByQueryString(queryString); @@ -158,7 +157,6 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { _searchController.searchInputController.text = recent.value; _searchController.searchFocus.unfocus(); _searchController.enableSearch(); - _searchController.clearSortOrder(); _searchController.clearSearchFilter(); _searchController.applyFilterSuggestionToSearchFilter(_dashBoardController.sessionCurrent?.username); _dashBoardController.searchEmailByQueryString(recent.value); @@ -257,6 +255,6 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin { _searchController.searchInputController.clear(); _searchController.searchFocus.unfocus(); _searchController.enableSearch(); - _dashBoardController.searchEmailByFromFields(emailAddress); + _dashBoardController.quickSearchEmailByFrom(emailAddress); } } \ No newline at end of file diff --git a/lib/features/search/email/presentation/search_email_controller.dart b/lib/features/search/email/presentation/search_email_controller.dart index 1f46f5b367..4cc32b06bc 100644 --- a/lib/features/search/email/presentation/search_email_controller.dart +++ b/lib/features/search/email/presentation/search_email_controller.dart @@ -218,9 +218,9 @@ class SearchEmailController extends BaseController suggestionSearchViewState.value = Right(LoadingState()); currentSearchText.value = value; _updateSimpleSearchFilter( - textOption: value.isNotEmpty ? Some(SearchQuery(value)) : const None(), + textOption: option(value.isNotEmpty, SearchQuery(value)), beforeOption: const None(), - positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() + positionOption: option(searchEmailFilter.value.sortOrderType.isScrollByPosition(), 0) ); if (value.isNotEmpty && session != null && accountId != null) { final tupleListSuggestion = await Future.wait([ @@ -297,15 +297,15 @@ class SearchEmailController extends BaseController : ThreadConstants.defaultLimit; _updateSimpleSearchFilter( beforeOption: const None(), - positionOption: emailSortOrderType.value.isScrollByPosition() ? const Some(0) : const None() + positionOption: option(searchEmailFilter.value.sortOrderType.isScrollByPosition(), 0) ); consumeState(_refreshChangesSearchEmailInteractor.execute( session!, accountId!, limit: limit, position: searchEmailFilter.value.position, - sort: emailSortOrderType.value.getSortOrder().toNullable(), - filter: searchEmailFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), + sort: searchEmailFilter.value.sortOrderType.getSortOrder().toNullable(), + filter: searchEmailFilter.value.mappingToEmailFilterCondition(), properties: EmailUtils.getPropertiesForEmailGetMethod(session!, accountId!), )); } @@ -347,8 +347,8 @@ class SearchEmailController extends BaseController session, accountId, limit: UnsignedInt(5), - sort: emailSortOrderType.value.getSortOrder().toNullable(), - filter: searchEmailFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), + sort: searchEmailFilter.value.sortOrderType.getSortOrder().toNullable(), + filter: searchEmailFilter.value.mappingToEmailFilterCondition(), properties: ThreadConstants.propertiesQuickSearch) .then((result) => result.fold( (failure) => [], @@ -389,9 +389,7 @@ class SearchEmailController extends BaseController } _updateSimpleSearchFilter( - positionOption: emailSortOrderType.value.isScrollByPosition() - ? const Some(0) - : const None(), + positionOption: option(searchEmailFilter.value.sortOrderType.isScrollByPosition(), 0), beforeOption: const None(), ); @@ -400,8 +398,8 @@ class SearchEmailController extends BaseController accountId!, limit: ThreadConstants.defaultLimit, position: searchEmailFilter.value.position, - sort: emailSortOrderType.value.getSortOrder().toNullable(), - filter: searchEmailFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), + sort: searchEmailFilter.value.sortOrderType.getSortOrder().toNullable(), + filter: searchEmailFilter.value.mappingToEmailFilterCondition(), properties: EmailUtils.getPropertiesForEmailGetMethod(session!, accountId!), )); } @@ -440,12 +438,12 @@ class SearchEmailController extends BaseController if (canSearchMore && session != null && accountId != null) { final lastEmail = listResultSearch.last; - if (emailSortOrderType.value.isScrollByPosition()) { + if (searchEmailFilter.value.sortOrderType.isScrollByPosition()) { _updateSimpleSearchFilter( positionOption: Some(listResultSearch.length), beforeOption: const None() ); - } else if (emailSortOrderType.value == EmailSortOrderType.oldest) { + } else if (searchEmailFilter.value.sortOrderType == EmailSortOrderType.oldest) { _updateSimpleSearchFilter(startDateOption: optionOf(lastEmail.receivedAt)); } else { _updateSimpleSearchFilter(beforeOption: optionOf(lastEmail.receivedAt)); @@ -455,9 +453,9 @@ class SearchEmailController extends BaseController session!, accountId!, limit: ThreadConstants.defaultLimit, - sort: emailSortOrderType.value.getSortOrder().toNullable(), + sort: searchEmailFilter.value.sortOrderType.getSortOrder().toNullable(), position: searchEmailFilter.value.position, - filter: searchEmailFilter.value.mappingToEmailFilterCondition(sortOrderType: emailSortOrderType.value), + filter: searchEmailFilter.value.mappingToEmailFilterCondition(), properties: EmailUtils.getPropertiesForEmailGetMethod(session!, accountId!), lastEmailId: lastEmail.id )); @@ -576,9 +574,6 @@ class SearchEmailController extends BaseController onCallbackAction: (newStartDate, newEndDate) { _updateSimpleSearchFilter( emailReceiveTimeTypeOption: Some(emailReceiveTimeType), - textOption: searchQuery == null - ? Some(SearchQuery.initial()) - : optionOf(searchEmailFilter.value.text), startDateOption: optionOf(newStartDate?.toUTCDate()), endDateOption: optionOf(newEndDate?.toUTCDate()), ); @@ -590,9 +585,6 @@ class SearchEmailController extends BaseController } else { _updateSimpleSearchFilter( emailReceiveTimeTypeOption: Some(emailReceiveTimeType), - textOption: searchQuery == null - ? Some(SearchQuery.initial()) - : optionOf(searchEmailFilter.value.text), startDateOption: const None(), endDateOption: const None(), ); @@ -605,6 +597,7 @@ class SearchEmailController extends BaseController void selectSortOrderQuickSearchFilter(BuildContext context, EmailSortOrderType sortOrderType) { popBack(); emailSortOrderType.value = sortOrderType; + _updateSimpleSearchFilter(sortOrderTypeOption: Some(sortOrderType)); _searchEmailAction(context); } @@ -702,6 +695,7 @@ class SearchEmailController extends BaseController Option? endDateOption, Option? positionOption, Option>? hasKeywordOption, + Option? sortOrderTypeOption, }) { searchEmailFilter.value = searchEmailFilter.value.copyWith( fromOption: fromOption, @@ -715,6 +709,7 @@ class SearchEmailController extends BaseController endDateOption: endDateOption, positionOption: positionOption, hasKeywordOption: hasKeywordOption, + sortOrderTypeOption: sortOrderTypeOption, ); searchEmailFilter.refresh(); } @@ -947,9 +942,6 @@ class SearchEmailController extends BaseController void _deleteDateTimeSearchFilter(BuildContext context) { _updateSimpleSearchFilter( emailReceiveTimeTypeOption: const Some(EmailReceiveTimeType.allTime), - textOption: searchQuery == null - ? Some(SearchQuery.initial()) - : optionOf(searchEmailFilter.value.text), startDateOption: const None(), endDateOption: const None(), ); @@ -959,6 +951,7 @@ class SearchEmailController extends BaseController void _deleteSortOrderSearchFilter(BuildContext context) { emailSortOrderType.value = EmailSortOrderType.mostRecent; + _updateSimpleSearchFilter(sortOrderTypeOption: const Some(EmailSortOrderType.mostRecent)); _searchEmailAction(context); } @@ -987,16 +980,6 @@ class SearchEmailController extends BaseController _searchEmailAction(context); } - bool get isSearchFilterHasApplied { - return searchEmailFilter.value.from.isNotEmpty || - searchEmailFilter.value.to.isNotEmpty || - searchEmailFilter.value.emailReceiveTimeType != EmailReceiveTimeType.allTime || - (searchEmailFilter.value.mailbox != PresentationMailbox.unifiedMailbox && searchEmailFilter.value.mailbox != null) || - searchEmailFilter.value.hasAttachment == true || - searchEmailFilter.value.hasKeyword.contains(KeyWordIdentifier.emailFlagged.value) || - emailSortOrderType.value != EmailSortOrderType.mostRecent; - } - void clearAllSearchFilterApplied(BuildContext context) { textInputSearchController.clear(); currentSearchText.value = ''; diff --git a/lib/features/search/email/presentation/search_email_view.dart b/lib/features/search/email/presentation/search_email_view.dart index 6b29888a89..15d72ce66d 100644 --- a/lib/features/search/email/presentation/search_email_view.dart +++ b/lib/features/search/email/presentation/search_email_view.dart @@ -217,7 +217,7 @@ class SearchEmailView extends GetWidget ), ), Obx(() { - if (controller.isSearchFilterHasApplied) { + if (controller.searchEmailFilter.value.isApplied) { return TMailButtonWidget.fromText( text: AppLocalizations.of(context).clearFilter, backgroundColor: Colors.transparent, diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 5eff361d45..995d3c0106 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -273,12 +273,6 @@ class ThreadController extends BaseController with EmailActionController { } }); - ever(searchController.isAdvancedSearchViewOpen, (hasOpen) { - if (hasOpen == true) { - mailboxDashBoardController.filterMessageOption.value = FilterMessageOption.all; - } - }); - ever(mailboxDashBoardController.dashBoardAction, (action) { if (action is SelectionAllEmailAction) { setSelectAllEmailAction(); @@ -302,8 +296,7 @@ class ThreadController extends BaseController with EmailActionController { ); mailboxDashBoardController.clearDashBoardAction(); } else if (action is StartSearchEmailAction - || action is ClearAdvancedSearchFilterEmailAction - || action is StartSearchEmailBySearchFilterAction) { + || action is ClearAdvancedSearchFilterEmailAction) { cancelSelectEmail(); _replaceBrowserHistory(); _searchEmail(); @@ -514,7 +507,7 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, limit: ThreadConstants.defaultLimit, - sort: searchController.sortOrderFiltered.value.getSortOrder().toNullable(), + sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), emailFilter: EmailFilter( filter: _getFilterCondition(mailboxIdSelected: selectedMailboxId), filterOption: mailboxDashBoardController.filterMessageOption.value, @@ -594,7 +587,7 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, newEmailState, - sort: searchController.sortOrderFiltered.value.getSortOrder().toNullable(), + sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), propertiesCreated: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), propertiesUpdated: ThreadConstants.propertiesUpdatedDefault, emailFilter: EmailFilter( @@ -619,8 +612,7 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, limit: ThreadConstants.defaultLimit, - position: _searchEmailFilter.position, - sort: searchController.sortOrderFiltered.value.getSortOrder().toNullable(), + sort: EmailSortOrderType.mostRecent.getSortOrder().toNullable(), filterOption: mailboxDashBoardController.filterMessageOption.value, filter: _getFilterCondition(oldestEmail: oldestEmail, mailboxIdSelected: selectedMailboxId), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), @@ -819,9 +811,7 @@ class ThreadController extends BaseController with EmailActionController { canSearchMore = false; searchController.updateFilterEmail( - positionOption: searchController.sortOrderFiltered.value.isScrollByPosition() - ? const Some(0) - : const None(), + positionOption: option(_searchEmailFilter.sortOrderType.isScrollByPosition(), 0), beforeOption: const None()); searchController.activateSimpleSearch(); @@ -831,9 +821,8 @@ class ThreadController extends BaseController with EmailActionController { _accountId!, limit: limit ?? ThreadConstants.defaultLimit, position: _searchEmailFilter.position, - sort: searchController.sortOrderFiltered.value.getSortOrder().toNullable(), + sort: _searchEmailFilter.sortOrderType.getSortOrder().toNullable(), filter: _searchEmailFilter.mappingToEmailFilterCondition( - sortOrderType: searchController.sortOrderFiltered.value, moreFilterCondition: _getFilterCondition() ), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), @@ -891,14 +880,14 @@ class ThreadController extends BaseController with EmailActionController { ? mailboxDashBoardController.emailsInCurrentMailbox.last : null; - if (searchController.sortOrderFiltered.value.isScrollByPosition()) { + if (_searchEmailFilter.sortOrderType.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) { + } else if (_searchEmailFilter.sortOrderType == EmailSortOrderType.oldest) { searchController.updateFilterEmail(startDateOption: optionOf(lastEmail?.receivedAt)); } else { searchController.updateFilterEmail(beforeOption: optionOf(lastEmail?.receivedAt)); @@ -908,10 +897,9 @@ class ThreadController extends BaseController with EmailActionController { _session!, _accountId!, limit: ThreadConstants.defaultLimit, - sort: searchController.sortOrderFiltered.value.getSortOrder().toNullable(), + sort: _searchEmailFilter.sortOrderType.getSortOrder().toNullable(), position: _searchEmailFilter.position, filter: _searchEmailFilter.mappingToEmailFilterCondition( - sortOrderType: searchController.sortOrderFiltered.value, moreFilterCondition: _getFilterCondition() ), properties: EmailUtils.getPropertiesForEmailGetMethod(_session!, _accountId!), diff --git a/model/lib/extensions/list_email_address_extension.dart b/model/lib/extensions/list_email_address_extension.dart index 41be64533b..84a9465bf3 100644 --- a/model/lib/extensions/list_email_address_extension.dart +++ b/model/lib/extensions/list_email_address_extension.dart @@ -2,7 +2,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/mailbox/expand_mode.dart'; import 'package:model/extensions/email_address_extension.dart'; -extension ListEmailAddressExtension on Set? { +extension SetEmailAddressExtension on Set? { List? getListAddress() => this?.map((emailAddress) => emailAddress.emailAddress).toList(); @@ -34,4 +34,8 @@ extension ListEmailAddressExtension on Set? { ? this!.where((emailAddress) => emailAddress.email != emailAddressNotExist).toList() : List.empty(); } +} + +extension ListEmailAddressExtension on List { + Set asSetAddress() => map((emailAddress) => emailAddress.emailAddress).toSet(); } \ No newline at end of file diff --git a/test/features/mailbox_dashboard/presentation/controller/advanced_filter_controller_test.dart b/test/features/mailbox_dashboard/presentation/controller/advanced_filter_controller_test.dart new file mode 100644 index 0000000000..17c352f960 --- /dev/null +++ b/test/features/mailbox_dashboard/presentation/controller/advanced_filter_controller_test.dart @@ -0,0 +1,330 @@ +import 'package:core/data/network/config/dynamic_url_interceptors.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/app_toast.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/utils/application_manager.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get/get.dart'; +import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; +import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/caching/caching_manager.dart'; +import 'package:tmail_ui_user/features/composer/domain/usecases/get_autocomplete_interactor.dart'; +import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; +import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/quick_search_email_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_recent_search_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; +import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.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/mailbox_dashboard/presentation/model/search/search_email_filter.dart'; +import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; +import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart'; +import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart'; +import 'package:tmail_ui_user/main/utils/toast_manager.dart'; +import 'package:uuid/uuid.dart'; + +import 'advanced_filter_controller_test.mocks.dart'; + +mockControllerCallback() => InternalFinalCallback(callback: () {}); +const fallbackGenerators = { + #onStart: mockControllerCallback, + #onDelete: mockControllerCallback, +}; + +@GenerateNiceMocks([ + // Base controller mock specs + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + MockSpec(), + // Advanced filter controller mock specs + MockSpec(fallbackGenerators: fallbackGenerators), + MockSpec(), + MockSpec(), + // Search controller mock specs + MockSpec(), + MockSpec(), + MockSpec(), +]) +void main() { + // Declaration advanced filter controller + late AdvancedFilterController advancedFilterController; + late MockMailboxDashBoardController mockMailboxDashBoardController; + late MockGetAutoCompleteInteractor mockGetAutoCompleteInteractor; + late MockBuildContext mockBuildContext; + + // Declaration search controller + late SearchController searchController; + late MockQuickSearchEmailInteractor mockQuickSearchEmailInteractor; + late MockSaveRecentSearchInteractor mockSaveRecentSearchInteractor; + late MockGetAllRecentSearchLatestInteractor mockGetAllRecentSearchLatestInteractor; + + // Declaration base controller + late MockCachingManager mockCachingManager; + late MockLanguageCacheManager mockLanguageCacheManager; + late MockAuthorizationInterceptors mockAuthorizationInterceptors; + late MockDynamicUrlInterceptors mockDynamicUrlInterceptors; + late MockDeleteCredentialInteractor mockDeleteCredentialInteractor; + late MockLogoutOidcInteractor mockLogoutOidcInteractor; + late MockDeleteAuthorityOidcInteractor mockDeleteAuthorityOidcInteractor; + late MockAppToast mockAppToast; + late MockImagePaths mockImagePaths; + late MockResponsiveUtils mockResponsiveUtils; + late MockUuid mockUuid; + late MockApplicationManager mockApplicationManager; + late MockToastManager mockToastManager; + + setUpAll(() { + Get.testMode = true; + // Mock base controller + mockCachingManager = MockCachingManager(); + mockLanguageCacheManager = MockLanguageCacheManager(); + mockAuthorizationInterceptors = MockAuthorizationInterceptors(); + mockDynamicUrlInterceptors = MockDynamicUrlInterceptors(); + mockDeleteCredentialInteractor = MockDeleteCredentialInteractor(); + mockLogoutOidcInteractor = MockLogoutOidcInteractor(); + mockDeleteAuthorityOidcInteractor = MockDeleteAuthorityOidcInteractor(); + mockAppToast = MockAppToast(); + mockImagePaths = MockImagePaths(); + mockResponsiveUtils = MockResponsiveUtils(); + mockUuid = MockUuid(); + mockApplicationManager = MockApplicationManager(); + mockToastManager = MockToastManager(); + + Get.put(mockCachingManager); + Get.put(mockLanguageCacheManager); + Get.put(mockAuthorizationInterceptors); + Get.put( + mockAuthorizationInterceptors, + tag: BindingTag.isolateTag, + ); + Get.put(mockDynamicUrlInterceptors); + Get.put(mockDeleteCredentialInteractor); + Get.put(mockLogoutOidcInteractor); + Get.put(mockDeleteAuthorityOidcInteractor); + Get.put(mockAppToast); + Get.put(mockImagePaths); + Get.put(mockResponsiveUtils); + Get.put(mockUuid); + Get.put(mockApplicationManager); + Get.put(mockToastManager); + + // Mock search controller + mockQuickSearchEmailInteractor = MockQuickSearchEmailInteractor(); + mockSaveRecentSearchInteractor = MockSaveRecentSearchInteractor(); + mockGetAllRecentSearchLatestInteractor = MockGetAllRecentSearchLatestInteractor(); + + searchController = SearchController( + mockQuickSearchEmailInteractor, + mockSaveRecentSearchInteractor, + mockGetAllRecentSearchLatestInteractor); + Get.put(searchController); + + // Mock advanced filter controller + mockMailboxDashBoardController = MockMailboxDashBoardController(); + mockGetAutoCompleteInteractor = MockGetAutoCompleteInteractor(); + mockBuildContext = MockBuildContext(); + + Get.put(mockMailboxDashBoardController); + Get.put(mockGetAutoCompleteInteractor); + + advancedFilterController = AdvancedFilterController(); + }); + + group('AdvancedFilterController::test', () { + group('applyAdvancedSearchFilter::test', () { + test('SHOULD make sure memory search filter and search filter should be the same after applying', () async { + // Arrange + advancedFilterController.hasKeyWordFilterInputController.text = 'Hello'; + advancedFilterController.notKeyWordFilterInputController.text = 'dab'; + advancedFilterController.listFromEmailAddress = [EmailAddress(null, 'user1@example.com')]; + advancedFilterController.listToEmailAddress = [EmailAddress(null, 'user2@example.com')]; + advancedFilterController.sortOrderType.value = EmailSortOrderType.oldest; + advancedFilterController.setDestinationMailboxSelected(PresentationMailbox.unifiedMailbox); + advancedFilterController.subjectFilterInputController.text = 'Subject'; + advancedFilterController.receiveTimeType.value = EmailReceiveTimeType.last7Days; + advancedFilterController.hasAttachment.value = true; + + // Act + advancedFilterController.applyAdvancedSearchFilter(); + + await untilCalled(mockMailboxDashBoardController.handleAdvancedSearchEmail()); + + final memorySearchFilter = advancedFilterController.memorySearchFilter; + final searchFilter = searchController.searchEmailFilter.value; + + // Assert + verify(mockMailboxDashBoardController.handleAdvancedSearchEmail()).called(1); + expect(memorySearchFilter, equals(searchFilter)); + }); + }); + + group('initSearchFilterField::test', () { + test( + 'SHOULD make sure the values of the variables in the controller are the same as the values of the MemorySearchFilter\n' + 'WHEN initSearchFilterField is called', + () async { + // Arrange + final memorySearchFilter = SearchEmailFilter( + text: SearchQuery('hello'), + subject: 'subject', + notKeyword: {'hello', 'nice'}, + emailReceiveTimeType: EmailReceiveTimeType.last7Days, + sortOrderType: EmailSortOrderType.oldest, + mailbox: PresentationMailbox( + MailboxId(Id('mailbox1')), + name: MailboxName('mailbox1') + ), + hasAttachment: true, + from: {'user1@example.com'}, + to: {'user2@example.com'}, + ); + advancedFilterController.setMemorySearchFilter(memorySearchFilter); + + // Act + advancedFilterController.initSearchFilterField(mockBuildContext); + + // Assert + expect(advancedFilterController.subjectFilterInputController.text, equals('subject')); + expect(advancedFilterController.hasKeyWordFilterInputController.text, equals('hello')); + expect(advancedFilterController.notKeyWordFilterInputController.text, equals('hello,nice')); + expect(advancedFilterController.receiveTimeType.value, equals(EmailReceiveTimeType.last7Days)); + expect(advancedFilterController.sortOrderType.value, equals(EmailSortOrderType.oldest)); + expect(advancedFilterController.mailBoxFilterInputController.text, equals('mailbox1')); + expect(advancedFilterController.hasAttachment.value, equals(true)); + expect(advancedFilterController.listFromEmailAddress, equals([EmailAddress(null, 'user1@example.com')])); + expect(advancedFilterController.listToEmailAddress, equals([EmailAddress(null, 'user2@example.com')])); + }); + }); + + group('onTextChanged::test', () { + test( + 'SHOULD update memory search filter for subject\n' + 'WHEN onTextChanged called with AdvancedSearchFilterField is Subject', + () { + // Arrange + const filterField = AdvancedSearchFilterField.subject; + const value = 'Subject'; + + // Act + advancedFilterController.onTextChanged(filterField, value); + + // Assert + expect( + advancedFilterController.memorySearchFilter.subject, + 'Subject'); + }); + + test( + 'SHOULD update memory search filter for text\n' + 'WHEN onTextChanged called with AdvancedSearchFilterField is hasKeyword', + () { + // Arrange + const filterField = AdvancedSearchFilterField.hasKeyword; + const value = 'keyword'; + + // Act + advancedFilterController.onTextChanged(filterField, value); + + // Assert + expect( + advancedFilterController.memorySearchFilter.text, + SearchQuery('keyword')); + }); + + test( + 'SHOULD update memory search filter for notKeyword\n' + 'WHEN onTextChanged called with AdvancedSearchFilterField is notKeyword', + () { + // Arrange + const filterField = AdvancedSearchFilterField.notKeyword; + const value = 'keyword1,keyword2'; + + // Act + advancedFilterController.onTextChanged(filterField, value); + + // Assert + expect( + advancedFilterController.memorySearchFilter.notKeyword, + {'keyword1','keyword2'}); + }); + + test( + 'SHOULD update memory search filter for subject is null\n' + 'WHEN onTextChanged called with AdvancedSearchFilterField is subject', + () { + // Arrange + const filterField = AdvancedSearchFilterField.subject; + const value = ' '; + + // Act + advancedFilterController.onTextChanged(filterField, value); + + // Assert + expect( + advancedFilterController.memorySearchFilter.subject, + isNull); + }); + + test( + 'SHOULD update memory search filter for notKeyword is empty values\n' + 'WHEN onTextChanged called with AdvancedSearchFilterField is notKeyword', + () { + // Arrange + const filterField = AdvancedSearchFilterField.notKeyword; + const value = ' '; + + // Act + advancedFilterController.onTextChanged(filterField, value); + + // Assert + expect( + advancedFilterController.memorySearchFilter.notKeyword, + {}); + }); + + test( + 'SHOULD update memory search filter for subject and notKeyword is empty values\n' + 'WHEN onTextChanged called with AdvancedSearchFilterField are subject and notKeyword', + () { + // Arrange + const filterFieldSubject = AdvancedSearchFilterField.subject; + const filterFieldNotKeyword = AdvancedSearchFilterField.notKeyword; + const validSubject = 'Subject'; + const emptyNotKeyword = ' '; + + // Act + advancedFilterController.onTextChanged(filterFieldSubject, validSubject); + advancedFilterController.onTextChanged(filterFieldNotKeyword, emptyNotKeyword); + + // Assert + expect( + advancedFilterController.memorySearchFilter.subject, + 'Subject'); + expect( + advancedFilterController.memorySearchFilter.notKeyword, + {}); + }); + }); + }); +} \ No newline at end of file diff --git a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart index 55cd94908d..cd0e127d55 100644 --- a/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart +++ b/test/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller_test.dart @@ -400,7 +400,7 @@ void main() { // expect sort in search controller update as expected mailboxDashboardController.selectSortOrderQuickSearchFilter( EmailSortOrderType.oldest); - expect(searchController.sortOrderFiltered.value, EmailSortOrderType.oldest); + expect(searchController.sortOrderFiltered, EmailSortOrderType.oldest); // expect filter in search controller update as expected mailboxDashboardController.selectHasAttachmentSearchFilter(); @@ -418,7 +418,7 @@ void main() { emailFilter: anyNamed('emailFilter'), propertiesCreated: anyNamed('propertiesCreated'), propertiesUpdated: anyNamed('propertiesUpdated'))); - expect(searchController.sortOrderFiltered.value, EmailSortOrderType.mostRecent); + expect(searchController.sortOrderFiltered, EmailSortOrderType.mostRecent); expect(searchController.searchEmailFilter.value, SearchEmailFilter.initial()); verify(getEmailsInMailboxInteractor.execute( testSession, testAccountId, @@ -459,6 +459,7 @@ void main() { from: {fromEmailAddress.email!}, to: {toEmailAddress.email!}, subject: emailSubject, + sortOrderType: EmailSortOrderType.relevance, text: SearchQuery(emailContainsWord), notKeyword: {emailNotContainsWord}, emailReceiveTimeType: EmailReceiveTimeType.last30Days, @@ -474,7 +475,7 @@ void main() { emailFilter: anyNamed('emailFilter'), propertiesCreated: anyNamed('propertiesCreated'), propertiesUpdated: anyNamed('propertiesUpdated'))); - expect(searchController.sortOrderFiltered.value, EmailSortOrderType.mostRecent); + expect(searchController.sortOrderFiltered, EmailSortOrderType.mostRecent); expect(searchController.searchEmailFilter.value, SearchEmailFilter.initial()); verify(getEmailsInMailboxInteractor.execute( testSession, testAccountId,