TF-4229 Implement search by label filter in mobile

This commit is contained in:
dab246
2026-01-05 11:25:29 +07:00
committed by Dat H. Pham
parent 96f03eaa40
commit a35b263dca
11 changed files with 362 additions and 71 deletions
@@ -45,6 +45,8 @@ mixin OptionalPopupSelectedIcon<T> {
Color get selectedIconColor => AppColor.primaryMain; Color get selectedIconColor => AppColor.primaryMain;
double get selectedIconSize => 16.0; double get selectedIconSize => 16.0;
bool get isArrangeRTL => true;
} }
mixin OptionalPopupHoverIcon { mixin OptionalPopupHoverIcon {
@@ -19,6 +19,7 @@ class ContextMenuDialogItem extends StatelessWidget {
Widget? iconWidget; Widget? iconWidget;
Widget? selectedIconWidget; Widget? selectedIconWidget;
bool isSelected = false; bool isSelected = false;
bool isArrangeRTL = true;
if (menuAction is ContextMenuItemActionRequiredIcon) { if (menuAction is ContextMenuItemActionRequiredIcon) {
final specificMenuAction = final specificMenuAction =
@@ -47,6 +48,7 @@ class ContextMenuDialogItem extends StatelessWidget {
), ),
); );
isSelected = specificMenuAction.selectedAction == menuAction.action; isSelected = specificMenuAction.selectedAction == menuAction.action;
isArrangeRTL = specificMenuAction.isArrangeRTL;
} else if (menuAction is ContextMenuItemActionRequiredFull) { } else if (menuAction is ContextMenuItemActionRequiredFull) {
final specificMenuAction = final specificMenuAction =
menuAction as ContextMenuItemActionRequiredFull; menuAction as ContextMenuItemActionRequiredFull;
@@ -71,8 +73,12 @@ class ContextMenuDialogItem extends StatelessWidget {
), ),
); );
isSelected = specificMenuAction.selectedAction == menuAction.action; isSelected = specificMenuAction.selectedAction == menuAction.action;
isArrangeRTL = specificMenuAction.isArrangeRTL;
} }
final leadingWidget =
iconWidget ?? (isArrangeRTL ? const SizedBox(width: 24) : null);
return Material( return Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: InkWell( child: InkWell(
@@ -81,7 +87,9 @@ class ContextMenuDialogItem extends StatelessWidget {
height: 48, height: 48,
child: Row( child: Row(
children: [ children: [
if (iconWidget != null) iconWidget else const SizedBox(width: 24), if (leadingWidget != null) leadingWidget,
if (!isArrangeRTL && selectedIconWidget != null)
selectedIconWidget,
Expanded( Expanded(
child: Text( child: Text(
menuAction.actionName, menuAction.actionName,
@@ -95,7 +103,7 @@ class ContextMenuDialogItem extends StatelessWidget {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
if (isSelected && selectedIconWidget != null) if (isArrangeRTL && isSelected && selectedIconWidget != null)
selectedIconWidget selectedIconWidget
else else
const SizedBox(width: 24), const SizedBox(width: 24),
@@ -31,6 +31,8 @@ mixin OptionalSelectedIcon<T> {
String get selectedIcon; String get selectedIcon;
Color get selectedIconColor => AppColor.primaryMain; Color get selectedIconColor => AppColor.primaryMain;
bool get isArrangeRTL => true;
} }
abstract class ContextMenuItemActionRequiredIcon<T> abstract class ContextMenuItemActionRequiredIcon<T>
@@ -5,6 +5,8 @@ import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:labels/extensions/label_extension.dart';
import 'package:labels/model/label.dart';
import 'package:model/mailbox/presentation_mailbox.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/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_receive_time_type.dart';
@@ -22,7 +24,8 @@ enum QuickSearchFilter {
dateTime, dateTime,
from, from,
to, to,
folder; folder,
labels;
String getTitle( String getTitle(
BuildContext context, { BuildContext context, {
@@ -33,7 +36,8 @@ enum QuickSearchFilter {
Set<String>? listAddressOfFrom, Set<String>? listAddressOfFrom,
UserName? userName, UserName? userName,
Set<String>? listAddressOfTo, Set<String>? listAddressOfTo,
PresentationMailbox? mailbox PresentationMailbox? mailbox,
Label? label,
}) { }) {
switch(this) { switch(this) {
case QuickSearchFilter.hasAttachment: case QuickSearchFilter.hasAttachment:
@@ -61,6 +65,8 @@ enum QuickSearchFilter {
return AppLocalizations.of(context).starred; return AppLocalizations.of(context).starred;
case QuickSearchFilter.unread: case QuickSearchFilter.unread:
return AppLocalizations.of(context).unread; return AppLocalizations.of(context).unread;
case QuickSearchFilter.labels:
return label?.safeDisplayName ?? AppLocalizations.of(context).allLabels;
} }
} }
@@ -86,6 +92,8 @@ enum QuickSearchFilter {
return isSelected ? imagePaths.icSelectedSB : imagePaths.icUnStar; return isSelected ? imagePaths.icSelectedSB : imagePaths.icUnStar;
case QuickSearchFilter.unread: case QuickSearchFilter.unread:
return isSelected ? imagePaths.icSelectedSB : imagePaths.icUnread; return isSelected ? imagePaths.icSelectedSB : imagePaths.icUnread;
case QuickSearchFilter.labels:
return imagePaths.icTag;
} }
} }
@@ -152,6 +160,8 @@ enum QuickSearchFilter {
return searchFilter.hasKeyword.contains(KeyWordIdentifier.emailFlagged.value) == true; return searchFilter.hasKeyword.contains(KeyWordIdentifier.emailFlagged.value) == true;
case QuickSearchFilter.unread: case QuickSearchFilter.unread:
return searchFilter.unread; return searchFilter.unread;
case QuickSearchFilter.labels:
return searchFilter.label != null;
} }
} }
@@ -171,5 +181,6 @@ enum QuickSearchFilter {
this == QuickSearchFilter.from || this == QuickSearchFilter.from ||
this == QuickSearchFilter.to || this == QuickSearchFilter.to ||
this == QuickSearchFilter.folder || this == QuickSearchFilter.folder ||
this == QuickSearchFilter.sortBy; this == QuickSearchFilter.sortBy ||
this == QuickSearchFilter.labels;
} }
@@ -4,6 +4,7 @@ import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:labels/model/label.dart';
import 'package:model/mailbox/presentation_mailbox.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_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/email_sort_order_type.dart';
@@ -29,6 +30,7 @@ class SearchFilterButton extends StatefulWidget {
final Set<String>? listAddressOfFrom; final Set<String>? listAddressOfFrom;
final Set<String>? listAddressOfTo; final Set<String>? listAddressOfTo;
final PresentationMailbox? mailbox; final PresentationMailbox? mailbox;
final Label? label;
final Color? backgroundColor; final Color? backgroundColor;
final EdgeInsetsGeometry? buttonPadding; final EdgeInsetsGeometry? buttonPadding;
final bool isContextMenuAlignEndButton; final bool isContextMenuAlignEndButton;
@@ -49,6 +51,7 @@ class SearchFilterButton extends StatefulWidget {
this.listAddressOfFrom, this.listAddressOfFrom,
this.listAddressOfTo, this.listAddressOfTo,
this.mailbox, this.mailbox,
this.label,
this.backgroundColor, this.backgroundColor,
this.buttonPadding, this.buttonPadding,
this.onSelectSearchFilterAction, this.onSelectSearchFilterAction,
@@ -73,6 +76,7 @@ class _SearchFilterButtonState extends State<SearchFilterButton> {
sortOrderType: widget.sortOrderType, sortOrderType: widget.sortOrderType,
listAddressOfFrom: widget.listAddressOfFrom, listAddressOfFrom: widget.listAddressOfFrom,
mailbox: widget.mailbox, mailbox: widget.mailbox,
label: widget.label,
listAddressOfTo: widget.listAddressOfTo, listAddressOfTo: widget.listAddressOfTo,
); );
@@ -0,0 +1,54 @@
import 'package:dartz/dartz.dart';
import 'package:labels/model/label.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/mailbox_dashboard/presentation/model/search/search_email_filter.dart';
import 'package:tmail_ui_user/features/search/email/presentation/search_email_controller.dart';
extension UpdateSearchFilterExtension on SearchEmailController {
void deleteQuickSearchFilter({required QuickSearchFilter filter}) {
switch (filter) {
case QuickSearchFilter.hasAttachment:
updateSimpleSearchFilter(hasAttachmentOption: const None());
break;
case QuickSearchFilter.starred:
updateSimpleSearchFilter(hasKeywordOption: const None());
break;
case QuickSearchFilter.unread:
updateSimpleSearchFilter(unreadOption: const None());
break;
case QuickSearchFilter.sortBy:
updateSimpleSearchFilter(
sortOrderTypeOption: const Some(SearchEmailFilter.defaultSortOrder),
);
break;
case QuickSearchFilter.dateTime:
updateSimpleSearchFilter(
emailReceiveTimeTypeOption: const Some(EmailReceiveTimeType.allTime),
startDateOption: const None(),
endDateOption: const None(),
);
break;
case QuickSearchFilter.from:
updateSimpleSearchFilter(fromOption: const None());
break;
case QuickSearchFilter.to:
updateSimpleSearchFilter(toOption: const None());
break;
case QuickSearchFilter.folder:
updateSimpleSearchFilter(mailboxOption: const None());
break;
case QuickSearchFilter.labels:
updateSimpleSearchFilter(labelOption: const None());
break;
default:
break;
}
searchEmailAction();
}
void onSelectLabelFilter(Label? newLabel) {
updateSimpleSearchFilter(labelOption: optionOf(newLabel));
searchEmailAction();
}
}
@@ -0,0 +1,92 @@
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/material.dart';
import 'package:labels/model/label.dart';
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_label_type_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/popup_menu_item_label_type_action.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
mixin SearchLabelFilterModalMixin on PopupContextMenuActionMixin {
void openLabelsFilterModal({
required BuildContext context,
required List<Label> labels,
required Label? selectedLabel,
required ImagePaths imagePaths,
required OnSelectLabelsActions onSelectLabelsActions,
RelativeRect? position,
}) {
if (position != null) {
openPopupMenuLabelsFilter(
context: context,
position: position,
labels: labels,
selectedLabel: selectedLabel,
imagePaths: imagePaths,
onSelectLabelsActions: onSelectLabelsActions,
);
} else {
openContextMenuLabelsFilter(
context: context,
labels: labels,
selectedLabel: selectedLabel,
imagePaths: imagePaths,
onSelectLabelsActions: onSelectLabelsActions,
);
}
}
void openPopupMenuLabelsFilter({
required BuildContext context,
required RelativeRect position,
required List<Label> labels,
required Label? selectedLabel,
required ImagePaths imagePaths,
required OnSelectLabelsActions onSelectLabelsActions,
}) {
final popupMenuItems = labels.map((label) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
menuAction: PopupMenuItemLabelTypeAction(
label,
selectedLabel,
imagePaths,
),
menuActionClick: (menuAction) {
popBack();
onSelectLabelsActions(menuAction.action);
},
),
);
}).toList();
openPopupMenuAction(context, position, popupMenuItems);
}
void openContextMenuLabelsFilter({
required BuildContext context,
required List<Label> labels,
required Label? selectedLabel,
required ImagePaths imagePaths,
required OnSelectLabelsActions onSelectLabelsActions,
}) {
final contextMenuActions = labels.map((label) {
return ContextItemLabelTypeAction(
label,
selectedLabel,
imagePaths,
);
}).toList();
openBottomSheetContextMenuAction(
context: context,
itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) {
popBack();
onSelectLabelsActions(menuAction.action);
},
);
}
}
@@ -0,0 +1,34 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/animation.dart';
import 'package:labels/labels.dart';
import 'package:tmail_ui_user/features/base/widget/context_menu/context_menu_item_action.dart';
class ContextItemLabelTypeAction
extends ContextMenuItemActionRequiredSelectedIcon<Label> {
final ImagePaths imagePaths;
ContextItemLabelTypeAction(
super.action,
super.selectedAction,
this.imagePaths,
);
bool get isSelected => action.id == selectedAction?.id;
@override
String get actionName => action.safeDisplayName;
@override
String get selectedIcon => isSelected
? imagePaths.icCheckboxSelected
: imagePaths.icCheckboxUnselected;
@override
Color get selectedIconColor => isSelected
? AppColor.primaryMain
: AppColor.gray424244.withValues(alpha: 0.72);
@override
bool get isArrangeRTL => false;
}
@@ -0,0 +1,35 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/animation.dart';
import 'package:labels/extensions/label_extension.dart';
import 'package:labels/model/label.dart';
import 'package:tmail_ui_user/features/base/model/popup_menu_item_action.dart';
class PopupMenuItemLabelTypeAction
extends PopupMenuItemActionRequiredSelectedIcon<Label> {
final ImagePaths imagePaths;
PopupMenuItemLabelTypeAction(
super.action,
super.selectedAction,
this.imagePaths,
);
bool get isSelected => action.id == selectedAction?.id;
@override
String get actionName => action.safeDisplayName;
@override
String get selectedIcon => isSelected
? imagePaths.icCheckboxSelected
: imagePaths.icCheckboxUnselected;
@override
Color get selectedIconColor => isSelected
? AppColor.primaryMain
: AppColor.gray424244.withValues(alpha: 0.72);
@override
bool get isArrangeRTL => false;
}
@@ -17,6 +17,7 @@ import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart'; import 'package:jmap_dart_client/jmap/core/utc_date.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart';
import 'package:labels/model/label.dart';
import 'package:model/email/email_action_type.dart'; import 'package:model/email/email_action_type.dart';
import 'package:model/email/mark_star_action.dart'; import 'package:model/email/mark_star_action.dart';
import 'package:model/email/prefix_email_address.dart'; import 'package:model/email/prefix_email_address.dart';
@@ -61,6 +62,8 @@ import 'package:tmail_ui_user/features/push_notification/presentation/websocket/
import 'package:tmail_ui_user/features/search/email/domain/state/refresh_changes_search_email_state.dart'; import 'package:tmail_ui_user/features/search/email/domain/state/refresh_changes_search_email_state.dart';
import 'package:tmail_ui_user/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart'; import 'package:tmail_ui_user/features/search/email/domain/usecases/refresh_changes_search_email_interactor.dart';
import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_keyboard_shortcut_actions_extension.dart'; import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_keyboard_shortcut_actions_extension.dart';
import 'package:tmail_ui_user/features/search/email/presentation/extension/update_search_filter_extension.dart';
import 'package:tmail_ui_user/features/search/email/presentation/mixin/search_label_filter_modal_mixin.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/search_more_state.dart'; import 'package:tmail_ui_user/features/search/email/presentation/model/search_more_state.dart';
import 'package:tmail_ui_user/features/search/email/presentation/search_email_bindings.dart'; import 'package:tmail_ui_user/features/search/email/presentation/search_email_bindings.dart';
import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart';
@@ -83,7 +86,8 @@ import 'package:tmail_ui_user/main/routes/route_utils.dart';
class SearchEmailController extends BaseController class SearchEmailController extends BaseController
with EmailActionController, with EmailActionController,
DateRangePickerMixin { DateRangePickerMixin,
SearchLabelFilterModalMixin {
final networkConnectionController = Get.find<NetworkConnectionController>(); final networkConnectionController = Get.find<NetworkConnectionController>();
@@ -141,6 +145,8 @@ class SearchEmailController extends BaseController
PresentationMailbox? get mailboxFiltered => searchEmailFilter.value.mailbox; PresentationMailbox? get mailboxFiltered => searchEmailFilter.value.mailbox;
Label? get labelFiltered => searchEmailFilter.value.label;
Set<String> get listAddressOfToFiltered => searchEmailFilter.value.to; Set<String> get listAddressOfToFiltered => searchEmailFilter.value.to;
Set<String> get listAddressOfFromFiltered => searchEmailFilter.value.from; Set<String> get listAddressOfFromFiltered => searchEmailFilter.value.from;
@@ -452,7 +458,9 @@ class SearchEmailController extends BaseController
)); ));
} }
void _searchEmailAction(BuildContext context) { void searchEmailAction() => _searchEmailAction();
void _searchEmailAction() {
textInputSearchFocus.unfocus(); textInputSearchFocus.unfocus();
if (session == null || accountId == null) { if (session == null || accountId == null) {
@@ -592,16 +600,13 @@ class SearchEmailController extends BaseController
queryString: recentSearch.value); queryString: recentSearch.value);
} }
void searchEmailByEmailAddressAction( void searchEmailByEmailAddressAction(EmailAddress emailAddress) {
BuildContext context,
EmailAddress emailAddress
) {
textInputSearchController.clear(); textInputSearchController.clear();
currentSearchText.value = ''; currentSearchText.value = '';
_updateSimpleSearchFilter( _updateSimpleSearchFilter(
textOption: const None(), textOption: const None(),
fromOption: Some({emailAddress.emailAddress})); fromOption: Some({emailAddress.emailAddress}));
_searchEmailAction(context); _searchEmailAction();
} }
void _searchEmailByQueryString({ void _searchEmailByQueryString({
@@ -618,30 +623,30 @@ class SearchEmailController extends BaseController
searchIsRunning.value = false; searchIsRunning.value = false;
final isMailAddress = EmailUtils.isEmailAddressValid(queryString); final isMailAddress = EmailUtils.isEmailAddressValid(queryString);
if (isMailAddress) { if (isMailAddress) {
searchEmailByEmailAddressAction(context, EmailAddress(null, queryString)); searchEmailByEmailAddressAction(EmailAddress(null, queryString));
} else { } else {
_updateSimpleSearchFilter(textOption: Some(SearchQuery(queryString))); _updateSimpleSearchFilter(textOption: Some(SearchQuery(queryString)));
_searchEmailAction(context); _searchEmailAction();
} }
} }
void selectHasAttachmentSearchFilter(BuildContext context) { void selectHasAttachmentSearchFilter() {
_updateSimpleSearchFilter(hasAttachmentOption: const Some(true)); _updateSimpleSearchFilter(hasAttachmentOption: const Some(true));
_searchEmailAction(context); _searchEmailAction();
} }
void selectStarredSearchFilter(BuildContext context) { void selectStarredSearchFilter() {
final listKeyword = listHasKeywordFiltered; final listKeyword = listHasKeywordFiltered;
if (!listKeyword.contains(KeyWordIdentifier.emailFlagged.value)) { if (!listKeyword.contains(KeyWordIdentifier.emailFlagged.value)) {
listKeyword.add(KeyWordIdentifier.emailFlagged.value); listKeyword.add(KeyWordIdentifier.emailFlagged.value);
} }
_updateSimpleSearchFilter(hasKeywordOption: Some(listKeyword)); _updateSimpleSearchFilter(hasKeywordOption: Some(listKeyword));
_searchEmailAction(context); _searchEmailAction();
} }
void selectUnreadSearchFilter(BuildContext context) { void selectUnreadSearchFilter() {
_updateSimpleSearchFilter(unreadOption: const Some(true)); _updateSimpleSearchFilter(unreadOption: const Some(true));
_searchEmailAction(context); _searchEmailAction();
} }
bool checkQuickSearchFilterSelected(QuickSearchFilter filter) { bool checkQuickSearchFilterSelected(QuickSearchFilter filter) {
@@ -675,7 +680,7 @@ class SearchEmailController extends BaseController
); );
_setEmailReceiveTimeType(emailReceiveTimeType); _setEmailReceiveTimeType(emailReceiveTimeType);
_searchEmailAction(context); _searchEmailAction();
} }
); );
} else { } else {
@@ -686,18 +691,18 @@ class SearchEmailController extends BaseController
); );
_setEmailReceiveTimeType(emailReceiveTimeType); _setEmailReceiveTimeType(emailReceiveTimeType);
_searchEmailAction(context); _searchEmailAction();
} }
} }
void selectSortOrderQuickSearchFilter(BuildContext context, EmailSortOrderType sortOrderType) { void selectSortOrderQuickSearchFilter(EmailSortOrderType sortOrderType) {
emailSortOrderType.value = sortOrderType; emailSortOrderType.value = sortOrderType;
_updateSimpleSearchFilter(sortOrderTypeOption: Some(sortOrderType)); _updateSimpleSearchFilter(sortOrderTypeOption: Some(sortOrderType));
mailboxDashBoardController.storeEmailSortOrder(sortOrderType); mailboxDashBoardController.storeEmailSortOrder(sortOrderType);
_searchEmailAction(context); _searchEmailAction();
} }
void selectMailboxForSearchFilter(BuildContext context, PresentationMailbox? mailbox) async { void selectMailboxForSearchFilter(PresentationMailbox? mailbox) async {
final arguments = DestinationPickerArguments( final arguments = DestinationPickerArguments(
mailboxDashBoardController.accountId.value!, mailboxDashBoardController.accountId.value!,
MailboxActions.select, MailboxActions.select,
@@ -716,9 +721,7 @@ class SearchEmailController extends BaseController
: Some(destinationMailbox) : Some(destinationMailbox)
); );
if (context.mounted) { _searchEmailAction();
_searchEmailAction(context);
}
} }
Future<void> selectContactForSearchFilter( Future<void> selectContactForSearchFilter(
@@ -776,9 +779,41 @@ class SearchEmailController extends BaseController
break; break;
} }
_searchEmailAction(context); _searchEmailAction();
} }
void updateSimpleSearchFilter({
Option<Set<String>>? fromOption,
Option<Set<String>>? toOption,
Option<SearchQuery>? textOption,
Option<PresentationMailbox>? mailboxOption,
Option<EmailReceiveTimeType>? emailReceiveTimeTypeOption,
Option<bool>? hasAttachmentOption,
Option<bool>? unreadOption,
Option<UTCDate>? beforeOption,
Option<UTCDate>? startDateOption,
Option<UTCDate>? endDateOption,
Option<int>? positionOption,
Option<Set<String>>? hasKeywordOption,
Option<EmailSortOrderType>? sortOrderTypeOption,
Option<Label>? labelOption,
}) => _updateSimpleSearchFilter(
fromOption: fromOption,
toOption: toOption,
textOption: textOption,
mailboxOption: mailboxOption,
emailReceiveTimeTypeOption: emailReceiveTimeTypeOption,
hasAttachmentOption: hasAttachmentOption,
unreadOption: unreadOption,
beforeOption: beforeOption,
startDateOption: startDateOption,
endDateOption: endDateOption,
positionOption: positionOption,
hasKeywordOption: hasKeywordOption,
sortOrderTypeOption: sortOrderTypeOption,
labelOption: labelOption,
);
void _updateSimpleSearchFilter({ void _updateSimpleSearchFilter({
Option<Set<String>>? fromOption, Option<Set<String>>? fromOption,
Option<Set<String>>? toOption, Option<Set<String>>? toOption,
@@ -793,6 +828,7 @@ class SearchEmailController extends BaseController
Option<int>? positionOption, Option<int>? positionOption,
Option<Set<String>>? hasKeywordOption, Option<Set<String>>? hasKeywordOption,
Option<EmailSortOrderType>? sortOrderTypeOption, Option<EmailSortOrderType>? sortOrderTypeOption,
Option<Label>? labelOption,
}) { }) {
searchEmailFilter.value = searchEmailFilter.value.copyWith( searchEmailFilter.value = searchEmailFilter.value.copyWith(
fromOption: fromOption, fromOption: fromOption,
@@ -808,6 +844,7 @@ class SearchEmailController extends BaseController
positionOption: positionOption, positionOption: positionOption,
hasKeywordOption: hasKeywordOption, hasKeywordOption: hasKeywordOption,
sortOrderTypeOption: sortOrderTypeOption, sortOrderTypeOption: sortOrderTypeOption,
labelOption: labelOption,
); );
searchEmailFilter.refresh(); searchEmailFilter.refresh();
} }
@@ -1017,45 +1054,48 @@ class SearchEmailController extends BaseController
) { ) {
switch(searchFilter) { switch(searchFilter) {
case QuickSearchFilter.dateTime: case QuickSearchFilter.dateTime:
_deleteDateTimeSearchFilter(context); _deleteDateTimeSearchFilter();
break; break;
case QuickSearchFilter.sortBy: case QuickSearchFilter.sortBy:
_deleteSortOrderSearchFilter(context); _deleteSortOrderSearchFilter();
break; break;
case QuickSearchFilter.from: case QuickSearchFilter.from:
_deleteFromSearchFilter(context); _deleteFromSearchFilter();
break; break;
case QuickSearchFilter.hasAttachment: case QuickSearchFilter.hasAttachment:
_deleteHasAttachmentSearchFilter(context); _deleteHasAttachmentSearchFilter();
break; break;
case QuickSearchFilter.to: case QuickSearchFilter.to:
_deleteToSearchFilter(context); _deleteToSearchFilter();
break; break;
case QuickSearchFilter.folder: case QuickSearchFilter.folder:
_deleteFolderSearchFilter(context); _deleteFolderSearchFilter();
break; break;
case QuickSearchFilter.starred: case QuickSearchFilter.starred:
_deleteStarredSearchFilter(context); _deleteStarredSearchFilter();
break; break;
case QuickSearchFilter.unread: case QuickSearchFilter.unread:
_deleteUnreadSearchFilter(context); _deleteUnreadSearchFilter();
break;
case QuickSearchFilter.labels:
deleteQuickSearchFilter(filter: QuickSearchFilter.labels);
break; break;
default: default:
break; break;
} }
} }
void _deleteDateTimeSearchFilter(BuildContext context) { void _deleteDateTimeSearchFilter() {
_updateSimpleSearchFilter( _updateSimpleSearchFilter(
emailReceiveTimeTypeOption: const Some(EmailReceiveTimeType.allTime), emailReceiveTimeTypeOption: const Some(EmailReceiveTimeType.allTime),
startDateOption: const None(), startDateOption: const None(),
endDateOption: const None(), endDateOption: const None(),
); );
_setEmailReceiveTimeType(EmailReceiveTimeType.allTime); _setEmailReceiveTimeType(EmailReceiveTimeType.allTime);
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteSortOrderSearchFilter(BuildContext context) { void _deleteSortOrderSearchFilter() {
emailSortOrderType.value = SearchEmailFilter.defaultSortOrder; emailSortOrderType.value = SearchEmailFilter.defaultSortOrder;
_updateSimpleSearchFilter( _updateSimpleSearchFilter(
sortOrderTypeOption: const Some(SearchEmailFilter.defaultSortOrder), sortOrderTypeOption: const Some(SearchEmailFilter.defaultSortOrder),
@@ -1063,40 +1103,40 @@ class SearchEmailController extends BaseController
mailboxDashBoardController.storeEmailSortOrder( mailboxDashBoardController.storeEmailSortOrder(
SearchEmailFilter.defaultSortOrder, SearchEmailFilter.defaultSortOrder,
); );
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteFromSearchFilter(BuildContext context) { void _deleteFromSearchFilter() {
_updateSimpleSearchFilter(fromOption: const None()); _updateSimpleSearchFilter(fromOption: const None());
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteToSearchFilter(BuildContext context) { void _deleteToSearchFilter() {
_updateSimpleSearchFilter(toOption: const None()); _updateSimpleSearchFilter(toOption: const None());
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteHasAttachmentSearchFilter(BuildContext context) { void _deleteHasAttachmentSearchFilter() {
_updateSimpleSearchFilter(hasAttachmentOption: const None()); _updateSimpleSearchFilter(hasAttachmentOption: const None());
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteFolderSearchFilter(BuildContext context) { void _deleteFolderSearchFilter() {
_updateSimpleSearchFilter(mailboxOption: const None()); _updateSimpleSearchFilter(mailboxOption: const None());
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteStarredSearchFilter(BuildContext context) { void _deleteStarredSearchFilter() {
_updateSimpleSearchFilter(hasKeywordOption: const None()); _updateSimpleSearchFilter(hasKeywordOption: const None());
_searchEmailAction(context); _searchEmailAction();
} }
void _deleteUnreadSearchFilter(BuildContext context) { void _deleteUnreadSearchFilter() {
_updateSimpleSearchFilter(unreadOption: const None()); _updateSimpleSearchFilter(unreadOption: const None());
_searchEmailAction(context); _searchEmailAction();
} }
void clearAllSearchFilterApplied(BuildContext context) { void clearAllSearchFilterApplied() {
textInputSearchController.clear(); textInputSearchController.clear();
currentSearchText.value = ''; currentSearchText.value = '';
listRecentSearch.clear(); listRecentSearch.clear();
@@ -1109,7 +1149,7 @@ class SearchEmailController extends BaseController
searchEmailFilter.value = SearchEmailFilter.withSortOrder( searchEmailFilter.value = SearchEmailFilter.withSortOrder(
emailSortOrderType.value, emailSortOrderType.value,
); );
_searchEmailAction(context); _searchEmailAction();
} }
@override @override
@@ -32,6 +32,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/se
import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_email_more_action_extension.dart'; import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_email_more_action_extension.dart';
import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_keyboard_shortcut_actions_extension.dart'; import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_keyboard_shortcut_actions_extension.dart';
import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_press_email_selection_action.dart'; import 'package:tmail_ui_user/features/search/email/presentation/extension/handle_press_email_selection_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/extension/update_search_filter_extension.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_receive_time_type_action.dart'; import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_receive_time_type_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_sort_order_type_action.dart'; import 'package:tmail_ui_user/features/search/email/presentation/model/context_item_sort_order_type_action.dart';
import 'package:tmail_ui_user/features/search/email/presentation/model/popup_menu_item_date_filter_action.dart'; import 'package:tmail_ui_user/features/search/email/presentation/model/popup_menu_item_date_filter_action.dart';
@@ -278,6 +279,8 @@ class SearchEmailView extends GetWidget<SearchEmailController>
children: [ children: [
_buildSearchFilterButton(context, QuickSearchFilter.folder), _buildSearchFilterButton(context, QuickSearchFilter.folder),
SearchEmailViewStyle.searchFilterSizeBoxMargin, SearchEmailViewStyle.searchFilterSizeBoxMargin,
_buildSearchFilterButton(context, QuickSearchFilter.labels),
SearchEmailViewStyle.searchFilterSizeBoxMargin,
_buildSearchFilterButton(context, QuickSearchFilter.from), _buildSearchFilterButton(context, QuickSearchFilter.from),
SearchEmailViewStyle.searchFilterSizeBoxMargin, SearchEmailViewStyle.searchFilterSizeBoxMargin,
_buildSearchFilterButton(context, QuickSearchFilter.to), _buildSearchFilterButton(context, QuickSearchFilter.to),
@@ -308,7 +311,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w500 fontWeight: FontWeight.w500
), ),
onTapActionCallback: () => controller.clearAllSearchFilterApplied(context) onTapActionCallback: controller.clearAllSearchFilterApplied
); );
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -331,6 +334,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
final endDate = controller.endDateFiltered; final endDate = controller.endDateFiltered;
final receiveTimeType = controller.receiveTimeFiltered; final receiveTimeType = controller.receiveTimeFiltered;
final mailbox = controller.mailboxFiltered; final mailbox = controller.mailboxFiltered;
final label = controller.labelFiltered;
final listAddressOfTo = controller.listAddressOfToFiltered; final listAddressOfTo = controller.listAddressOfToFiltered;
final isSelected = searchFilter.isSelected( final isSelected = searchFilter.isSelected(
@@ -352,6 +356,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
listAddressOfFrom: listAddressOfFrom, listAddressOfFrom: listAddressOfFrom,
listAddressOfTo: listAddressOfTo, listAddressOfTo: listAddressOfTo,
mailbox: mailbox, mailbox: mailbox,
label: label,
backgroundColor: searchFilter.getMobileBackgroundColor(isSelected: isSelected), backgroundColor: searchFilter.getMobileBackgroundColor(isSelected: isSelected),
onSelectSearchFilterAction: _onSelectSearchFilterAction, onSelectSearchFilterAction: _onSelectSearchFilterAction,
onDeleteSearchFilterAction: (searchFilter) => onDeleteSearchFilterAction: (searchFilter) =>
@@ -386,7 +391,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
PrefixEmailAddress.from); PrefixEmailAddress.from);
break; break;
case QuickSearchFilter.hasAttachment: case QuickSearchFilter.hasAttachment:
controller.selectHasAttachmentSearchFilter(context); controller.selectHasAttachmentSearchFilter();
break; break;
case QuickSearchFilter.to: case QuickSearchFilter.to:
controller.selectContactForSearchFilter( controller.selectContactForSearchFilter(
@@ -394,15 +399,26 @@ class SearchEmailView extends GetWidget<SearchEmailController>
PrefixEmailAddress.to); PrefixEmailAddress.to);
break; break;
case QuickSearchFilter.folder: case QuickSearchFilter.folder:
controller.selectMailboxForSearchFilter( controller.selectMailboxForSearchFilter(controller.mailboxFiltered);
context,
controller.mailboxFiltered);
break; break;
case QuickSearchFilter.starred: case QuickSearchFilter.starred:
controller.selectStarredSearchFilter(context); controller.selectStarredSearchFilter();
break; break;
case QuickSearchFilter.unread: case QuickSearchFilter.unread:
controller.selectUnreadSearchFilter(context); controller.selectUnreadSearchFilter();
break;
case QuickSearchFilter.labels:
final listLabels = controller.mailboxDashBoardController.labelController.labels;
final selectedLabel = controller.labelFiltered;
controller.openLabelsFilterModal(
context: context,
position: buttonPosition,
labels: listLabels,
selectedLabel: selectedLabel,
imagePaths: controller.imagePaths,
onSelectLabelsActions: controller.onSelectLabelFilter,
);
break; break;
default: default:
break; break;
@@ -471,10 +487,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
), ),
menuActionClick: (menuAction) { menuActionClick: (menuAction) {
popBack(); popBack();
controller.selectSortOrderQuickSearchFilter( controller.selectSortOrderQuickSearchFilter(menuAction.action);
context,
menuAction.action,
);
}, },
), ),
); );
@@ -499,10 +512,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
itemActions: contextMenuActions, itemActions: contextMenuActions,
onContextMenuActionClick: (menuAction) { onContextMenuActionClick: (menuAction) {
popBack(); popBack();
controller.selectSortOrderQuickSearchFilter( controller.selectSortOrderQuickSearchFilter(menuAction.action);
context,
menuAction.action,
);
}, },
); );
} }
@@ -648,7 +658,6 @@ class SearchEmailView extends GetWidget<SearchEmailController>
child: InkWell( child: InkWell(
child: ContactQuickSearchItem(emailAddress: emailAddress), child: ContactQuickSearchItem(emailAddress: emailAddress),
onTap: () => controller.searchEmailByEmailAddressAction( onTap: () => controller.searchEmailByEmailAddressAction(
context,
emailAddress emailAddress
), ),
), ),