Use common FilterField & EmailReceiveTimeType objects for the entire app

Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
dab246
2025-07-11 01:31:07 +07:00
committed by Dat H. Pham
parent 84e3c526f7
commit da29ff01e3
17 changed files with 253 additions and 378 deletions
+104
View File
@@ -0,0 +1,104 @@
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum FilterField {
from,
to,
cc,
bcc,
replyTo,
subject,
hasKeyword,
notKeyword,
mailBox,
date,
sortBy,
hasAttachment,
deletionDate,
receptionDate,
recoverSubject,
recipients,
sender;
String getTitle(AppLocalizations appLocalizations) {
switch (this) {
case FilterField.from:
return appLocalizations.from_email_address_prefix;
case FilterField.to:
return appLocalizations.to_email_address_prefix;
case FilterField.subject:
case FilterField.recoverSubject:
return appLocalizations.subject;
case FilterField.hasKeyword:
return appLocalizations.hasTheWords;
case FilterField.notKeyword:
return appLocalizations.doesNotHave;
case FilterField.mailBox:
return appLocalizations.folder;
case FilterField.date:
return appLocalizations.date;
case FilterField.sortBy:
return appLocalizations.sortBy;
case FilterField.hasAttachment:
return appLocalizations.hasAttachment;
case FilterField.deletionDate:
return appLocalizations.deletionDate;
case FilterField.receptionDate:
return appLocalizations.receptionDate;
case FilterField.recipients:
return appLocalizations.headerRecipients;
case FilterField.sender:
return appLocalizations.sender;
default:
return '';
}
}
String getHintText(AppLocalizations appLocalizations) {
switch (this) {
case FilterField.from:
case FilterField.to:
return appLocalizations.nameOrEmailAddress;
case FilterField.subject:
return appLocalizations.enterASubject;
case FilterField.hasKeyword:
case FilterField.notKeyword:
return appLocalizations.enterSomeSuggestions;
case FilterField.mailBox:
return appLocalizations.allFolders;
case FilterField.date:
return appLocalizations.allTime;
case FilterField.sortBy:
return appLocalizations.mostRecent;
case FilterField.hasAttachment:
return appLocalizations.hasAttachment;
case FilterField.recoverSubject:
return appLocalizations.enterSubjectKeywords;
case FilterField.recipients:
case FilterField.sender:
return appLocalizations.addAnEmailAddress;
default:
return '';
}
}
List<EmailReceiveTimeType> getSupportedTimeTypes(
DateTime restorationHorizon,
) {
switch (this) {
case FilterField.deletionDate:
final supportedTypes = EmailReceiveTimeType
.valuesForRecoverDeletionDateField
.where((type) => restorationHorizon
.subtract(const Duration(seconds: 2)) // to allow "15 days" if restorationHorizon is exactly 15
.isBefore(type.toOldestUTCDate()!.value))
.toList();
return [...supportedTypes, EmailReceiveTimeType.customRange];
case FilterField.receptionDate:
return EmailReceiveTimeType.valuesForRecoverReceptionDateDateField;
default:
return [];
}
}
}
@@ -2,6 +2,7 @@
import 'package:flutter/cupertino.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
extension PrefixEmailAddressExtension on PrefixEmailAddress {
@@ -35,4 +36,19 @@ extension PrefixEmailAddressExtension on PrefixEmailAddress {
return email.from?.toList() ?? List.empty();
}
}
FilterField get filterField {
switch(this) {
case PrefixEmailAddress.from:
return FilterField.from;
case PrefixEmailAddress.to:
return FilterField.to;
case PrefixEmailAddress.cc:
return FilterField.cc;
case PrefixEmailAddress.bcc:
return FilterField.bcc;
case PrefixEmailAddress.replyTo:
return FilterField.replyTo;
}
}
}
@@ -1,6 +1,6 @@
import 'package:model/email/prefix_email_address.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
@@ -30,20 +30,20 @@ extension RemoveDraggableEmailAddressBetweenRecipientFieldsExtension on Composer
required ComposerController controller,
required DraggableEmailAddress draggableEmailAddress,
}) {
switch(draggableEmailAddress.prefix) {
case PrefixEmailAddress.to:
switch(draggableEmailAddress.filterField) {
case FilterField.to:
controller.listToEmailAddress.remove(draggableEmailAddress.emailAddress);
controller.toAddressExpandMode.value = ExpandMode.EXPAND;
break;
case PrefixEmailAddress.cc:
case FilterField.cc:
controller.listCcEmailAddress.remove(draggableEmailAddress.emailAddress);
controller.ccAddressExpandMode.value = ExpandMode.EXPAND;
break;
case PrefixEmailAddress.bcc:
case FilterField.bcc:
controller.listBccEmailAddress.remove(draggableEmailAddress.emailAddress);
controller.bccAddressExpandMode.value = ExpandMode.EXPAND;
break;
case PrefixEmailAddress.replyTo:
case FilterField.replyTo:
controller.listReplyToEmailAddress.remove(draggableEmailAddress.emailAddress);
controller.replyToAddressExpandMode.value = ExpandMode.EXPAND;
break;
@@ -1,18 +1,18 @@
import 'package:equatable/equatable.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
class DraggableEmailAddress with EquatableMixin {
final EmailAddress emailAddress;
final PrefixEmailAddress prefix;
final FilterField filterField;
final String? composerId;
DraggableEmailAddress({
required this.emailAddress,
required this.prefix,
required this.filterField,
this.composerId,
});
@override
List<Object?> get props => [emailAddress, prefix, composerId];
List<Object?> get props => [emailAddress, filterField, composerId];
}
@@ -594,7 +594,7 @@ class _RecipientComposerWidgetState extends State<RecipientComposerWidget> {
) {
log('_RecipientComposerWidgetState::_handleAcceptDraggableEmailAddressAction: $draggableEmailAddress');
if (draggableEmailAddress.composerId == widget.composerId) {
if (draggableEmailAddress.prefix != widget.prefix) {
if (draggableEmailAddress.filterField != widget.prefix.filterField) {
if (!_currentListEmailAddress.contains(draggableEmailAddress.emailAddress)) {
stateSetter(() {
_currentListEmailAddress.add(draggableEmailAddress.emailAddress);
@@ -11,6 +11,7 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:tmail_ui_user/features/base/widget/card_with_smart_interaction_overlay_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/prefix_email_address_extension.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/email_address_action_type.dart';
import 'package:tmail_ui_user/features/composer/presentation/styles/recipient_tag_item_widget_style.dart';
@@ -137,7 +138,7 @@ class RecipientTagItemWidget extends StatelessWidget {
tagWidget = Draggable<DraggableEmailAddress>(
data: DraggableEmailAddress(
emailAddress: currentEmailAddress,
prefix: prefix,
filterField: prefix.filterField,
composerId: composerId,
),
feedback: DraggableRecipientTagWidget(emailAddress: currentEmailAddress),
@@ -1,99 +0,0 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/theme_utils.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/email_recovery/presentation/model/email_recovery_time_type.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum EmailRecoveryField {
deletionDate,
receptionDate,
subject,
recipients,
sender;
String getTitle(BuildContext context) {
switch (this) {
case EmailRecoveryField.deletionDate:
return AppLocalizations.of(context).deletionDate;
case EmailRecoveryField.receptionDate:
return AppLocalizations.of(context).receptionDate;
case EmailRecoveryField.subject:
return AppLocalizations.of(context).subject;
case EmailRecoveryField.recipients:
return AppLocalizations.of(context).headerRecipients;
case EmailRecoveryField.sender:
return AppLocalizations.of(context).sender;
}
}
String getHintText(BuildContext context) {
switch (this) {
case EmailRecoveryField.deletionDate:
return AppLocalizations.of(context).last7Days;
case EmailRecoveryField.receptionDate:
return AppLocalizations.of(context).allTime;
case EmailRecoveryField.subject:
return AppLocalizations.of(context).enterSomeSuggestions;
case EmailRecoveryField.recipients:
return AppLocalizations.of(context).addRecipientButton;
case EmailRecoveryField.sender:
return AppLocalizations.of(context).addSender;
}
}
List<EmailRecoveryTimeType> getSupportedTimeTypes(DateTime restorationHorizon) {
switch (this) {
case EmailRecoveryField.deletionDate:
final supportedTypes = [
EmailRecoveryTimeType.last7Days,
EmailRecoveryTimeType.last15Days,
EmailRecoveryTimeType.last30Days,
EmailRecoveryTimeType.last6Months,
EmailRecoveryTimeType.last1Year,
].where((type) => restorationHorizon
.subtract(const Duration(seconds: 2)) // to allow "15 days" if restorationHorizon is exactly 15
.isBefore(type.toOldestUTCDate()!.value)).toList();
return [...supportedTypes, EmailRecoveryTimeType.customRange];
case EmailRecoveryField.receptionDate:
return [
EmailRecoveryTimeType.allTime,
EmailRecoveryTimeType.last7Days,
EmailRecoveryTimeType.last30Days,
EmailRecoveryTimeType.last6Months,
EmailRecoveryTimeType.lastYear,
EmailRecoveryTimeType.customRange,
];
default:
return [];
}
}
TextStyle getTitleTextStyle() {
return ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColor.colorContentEmail,
);
}
TextStyle getHintTextStyle() {
final Color color;
switch (this) {
case EmailRecoveryField.deletionDate:
case EmailRecoveryField.receptionDate:
color = Colors.black;
break;
case EmailRecoveryField.subject:
case EmailRecoveryField.recipients:
case EmailRecoveryField.sender:
color = AppColor.colorHintSearchBar;
break;
}
return ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 16,
fontWeight: FontWeight.w400,
color: color,
);
}
}
@@ -1,105 +0,0 @@
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:jmap_dart_client/jmap/core/utc_date.dart';
enum EmailRecoveryTimeType {
allTime,
last7Days,
last15Days,
last30Days,
last6Months,
last1Year,
lastYear,
customRange;
String getTitle(BuildContext context, {DateTime? startDate, DateTime? endDate}) {
switch(this) {
case EmailRecoveryTimeType.allTime:
return AppLocalizations.of(context).allTime;
case EmailRecoveryTimeType.last7Days:
return AppLocalizations.of(context).last7Days;
case EmailRecoveryTimeType.last15Days:
return AppLocalizations.of(context).last15Days;
case EmailRecoveryTimeType.last30Days:
return AppLocalizations.of(context).last30Days;
case EmailRecoveryTimeType.last6Months:
return AppLocalizations.of(context).last6Months;
case EmailRecoveryTimeType.last1Year:
return AppLocalizations.of(context).last1Year;
case EmailRecoveryTimeType.lastYear:
return AppLocalizations.of(context).lastYears;
case EmailRecoveryTimeType.customRange:
if (startDate != null && endDate != null) {
final startDateString = startDate.formatDate(pattern: 'yyyy-dd-MM');
final endDateString = endDate.formatDate(pattern: 'yyyy-dd-MM');
return AppLocalizations.of(context).dateRangeAdvancedSearchFilter(
startDateString,
endDateString
);
} else {
return AppLocalizations.of(context).customRange;
}
}
}
UTCDate? toOldestUTCDate() {
switch(this) {
case EmailRecoveryTimeType.last7Days:
final today = DateTime.now();
final last7Days = today.subtract(const Duration(days: 7));
return last7Days.toUTCDate();
case EmailRecoveryTimeType.last15Days:
final today = DateTime.now();
final last15Days = today.subtract(const Duration(days: 15));
return last15Days.toUTCDate();
case EmailRecoveryTimeType.last30Days:
final today = DateTime.now();
final last30Days = today.subtract(const Duration(days: 30));
return last30Days.toUTCDate();
case EmailRecoveryTimeType.last6Months:
final today = DateTime.now();
final last6months = DateTime(today.year, today.month - 6, today.day);
return last6months.toUTCDate();
case EmailRecoveryTimeType.last1Year:
case EmailRecoveryTimeType.lastYear:
final today = DateTime.now();
final lastYear = DateTime(today.year - 1, today.month, today.day);
return lastYear.toUTCDate();
default:
return null;
}
}
UTCDate? toLatestUTCDate() {
switch(this) {
case EmailRecoveryTimeType.last7Days:
case EmailRecoveryTimeType.last15Days:
case EmailRecoveryTimeType.last30Days:
case EmailRecoveryTimeType.last6Months:
case EmailRecoveryTimeType.last1Year:
case EmailRecoveryTimeType.lastYear:
final today = DateTime.now();
return today.toUTCDate();
default:
return null;
}
}
UTCDate? getAfterDate(UTCDate? startDate) {
if (startDate != null) {
return startDate;
} else {
return toOldestUTCDate();
}
}
UTCDate? getBeforeDate(UTCDate? endDate) {
if (endDate != null) {
return endDate;
} else {
return toLatestUTCDate();
}
}
}
@@ -18,7 +18,7 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/das
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/input_field_focus_manager.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' as search;
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.dart';
import 'package:tmail_ui_user/features/base/model/filter_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';
@@ -359,14 +359,14 @@ class AdvancedFilterController extends BaseController {
}
}
void showFullEmailAddress(AdvancedSearchFilterField field) {
void showFullEmailAddress(FilterField field) {
FocusManager.instance.primaryFocus?.unfocus();
switch(field) {
case AdvancedSearchFilterField.from:
case FilterField.from:
fromAddressExpandMode.value = ExpandMode.EXPAND;
break;
case AdvancedSearchFilterField.to:
case FilterField.to:
toAddressExpandMode.value = ExpandMode.EXPAND;
break;
default:
@@ -375,18 +375,18 @@ class AdvancedFilterController extends BaseController {
}
void updateListEmailAddress(
AdvancedSearchFilterField field,
FilterField field,
List<EmailAddress> listEmailAddress,
) {
switch(field) {
case AdvancedSearchFilterField.from:
case FilterField.from:
listFromEmailAddress = List.from(listEmailAddress);
_updateMemorySearchFilter(
fromOption: option(
listFromEmailAddress.isNotEmpty,
listFromEmailAddress.asSetAddress()));
break;
case AdvancedSearchFilterField.to:
case FilterField.to:
listToEmailAddress = List.from(listEmailAddress);
_updateMemorySearchFilter(
toOption: option(
@@ -526,19 +526,19 @@ class AdvancedFilterController extends BaseController {
_updateMemorySearchFilter(hasAttachmentOption: Some(hasAttachment.value));
}
void onTextChanged(AdvancedSearchFilterField filterField, String value) {
void onTextChanged(FilterField filterField, String value) {
switch (filterField) {
case AdvancedSearchFilterField.subject:
case FilterField.subject:
final subjectOption = option(value.trim().isNotEmpty, value.trim());
_updateMemorySearchFilter(subjectOption: subjectOption);
break;
case AdvancedSearchFilterField.hasKeyword:
case FilterField.hasKeyword:
final textOption = option(
value.trim().isNotEmpty,
SearchQuery(value.trim()));
_updateMemorySearchFilter(textOption: textOption);
break;
case AdvancedSearchFilterField.notKeyword:
case FilterField.notKeyword:
final notKeywordsOption = option(
value.trim().isNotEmpty,
value.trim().split(',').map((value) => value.trim()).toSet());
@@ -551,8 +551,8 @@ class AdvancedFilterController extends BaseController {
void removeDraggableEmailAddress(DraggableEmailAddress draggableEmailAddress) {
log('AdvancedFilterController::removeDraggableEmailAddress:removeDraggableEmailAddress: $draggableEmailAddress');
switch(draggableEmailAddress.prefix) {
case PrefixEmailAddress.to:
switch(draggableEmailAddress.filterField) {
case FilterField.to:
listToEmailAddress.remove(draggableEmailAddress.emailAddress);
_updateMemorySearchFilter(
toOption: option(
@@ -563,7 +563,7 @@ class AdvancedFilterController extends BaseController {
toAddressExpandMode.value = ExpandMode.EXPAND;
toAddressExpandMode.refresh();
break;
case PrefixEmailAddress.from:
case FilterField.from:
listFromEmailAddress.remove(draggableEmailAddress.emailAddress);
_updateMemorySearchFilter(
fromOption: option(
@@ -818,7 +818,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
}
void _openPopupMenuDateFilter(BuildContext context, RelativeRect position) {
final popupMenuItems = EmailReceiveTimeType.values.map((timeType) {
final popupMenuItems = EmailReceiveTimeType.valuesForSearch.map((timeType) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
@@ -1,85 +0,0 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum AdvancedSearchFilterField {
from,
to,
subject,
hasKeyword,
notKeyword,
mailBox,
date,
sortBy,
hasAttachment;
String getTitle(BuildContext context) {
switch (this) {
case AdvancedSearchFilterField.from:
return AppLocalizations.of(context).from_email_address_prefix;
case AdvancedSearchFilterField.to:
return AppLocalizations.of(context).to_email_address_prefix;
case AdvancedSearchFilterField.subject:
return AppLocalizations.of(context).subject;
case AdvancedSearchFilterField.hasKeyword:
return AppLocalizations.of(context).hasTheWords;
case AdvancedSearchFilterField.notKeyword:
return AppLocalizations.of(context).doesNotHave;
case AdvancedSearchFilterField.mailBox:
return AppLocalizations.of(context).folder;
case AdvancedSearchFilterField.date:
return AppLocalizations.of(context).date;
case AdvancedSearchFilterField.sortBy:
return AppLocalizations.of(context).sortBy;
case AdvancedSearchFilterField.hasAttachment:
return AppLocalizations.of(context).hasAttachment;
}
}
String getHintText(BuildContext context) {
switch (this) {
case AdvancedSearchFilterField.from:
case AdvancedSearchFilterField.to:
return AppLocalizations.of(context).nameOrEmailAddress;
case AdvancedSearchFilterField.subject:
return AppLocalizations.of(context).enterASubject;
case AdvancedSearchFilterField.hasKeyword:
case AdvancedSearchFilterField.notKeyword:
return AppLocalizations.of(context).enterSomeSuggestions;
case AdvancedSearchFilterField.mailBox:
return AppLocalizations.of(context).allFolders;
case AdvancedSearchFilterField.date:
return AppLocalizations.of(context).allTime;
case AdvancedSearchFilterField.sortBy:
return AppLocalizations.of(context).mostRecent;
case AdvancedSearchFilterField.hasAttachment:
return AppLocalizations.of(context).hasAttachment;
}
}
TextStyle getTitleTextStyle() {
return ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400,
color: AppColor.colorContentEmail);
}
PrefixEmailAddress getPrefixEmailAddress() {
switch (this) {
case AdvancedSearchFilterField.from:
return PrefixEmailAddress.from;
case AdvancedSearchFilterField.to:
return PrefixEmailAddress.to;
default:
return PrefixEmailAddress.cc;
}
}
TextStyle getHintTextStyle() {
return ThemeUtils.defaultTextStyleInterFont.copyWith(
fontSize: 16,
fontWeight: FontWeight.w400,
color: AppColor.colorHintSearchBar);
}
}
@@ -7,11 +7,39 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum EmailReceiveTimeType {
allTime,
last7Days,
last15Days,
last30Days,
last6Months,
last1Year,
lastYear,
customRange;
static List<EmailReceiveTimeType> get valuesForSearch => [
allTime,
last7Days,
last30Days,
last6Months,
lastYear,
customRange,
];
static List<EmailReceiveTimeType> get valuesForRecoverDeletionDateField => [
last7Days,
last15Days,
last30Days,
last6Months,
last1Year,
];
static List<EmailReceiveTimeType> get valuesForRecoverReceptionDateDateField => [
allTime,
last7Days,
last30Days,
last6Months,
lastYear,
customRange,
];
String getTitle(BuildContext context, {DateTime? startDate, DateTime? endDate}) {
return getTitleByAppLocalizations(
AppLocalizations.of(context),
@@ -32,10 +60,14 @@ enum EmailReceiveTimeType {
return appLocalizations.allTime;
case EmailReceiveTimeType.last7Days:
return appLocalizations.last7Days;
case EmailReceiveTimeType.last15Days:
return appLocalizations.last15Days;
case EmailReceiveTimeType.last30Days:
return appLocalizations.last30Days;
case EmailReceiveTimeType.last6Months:
return appLocalizations.last6Months;
case EmailReceiveTimeType.last1Year:
return appLocalizations.last1Year;
case EmailReceiveTimeType.lastYear:
return appLocalizations.lastYears;
case EmailReceiveTimeType.customRange:
@@ -58,6 +90,10 @@ enum EmailReceiveTimeType {
final today = DateTime.now();
final last7Days = today.subtract(const Duration(days: 7));
return last7Days.toUTCDate();
case EmailReceiveTimeType.last15Days:
final today = DateTime.now();
final last15Days = today.subtract(const Duration(days: 15));
return last15Days.toUTCDate();
case EmailReceiveTimeType.last30Days:
final today = DateTime.now();
final last30Days = today.subtract(const Duration(days: 30));
@@ -66,6 +102,7 @@ enum EmailReceiveTimeType {
final today = DateTime.now();
final last6months = DateTime(today.year, today.month - 6, today.day);
return last6months.toUTCDate();
case EmailReceiveTimeType.last1Year:
case EmailReceiveTimeType.lastYear:
final today = DateTime.now();
final lastYear = DateTime(today.year - 1, today.month, today.day);
@@ -78,8 +115,10 @@ enum EmailReceiveTimeType {
UTCDate? toLatestUTCDate() {
switch(this) {
case EmailReceiveTimeType.last7Days:
case EmailReceiveTimeType.last15Days:
case EmailReceiveTimeType.last30Days:
case EmailReceiveTimeType.last6Months:
case EmailReceiveTimeType.last1Year:
case EmailReceiveTimeType.lastYear:
return DateTime.now().toUTCDate();
default:
@@ -6,11 +6,11 @@ import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/advanced_search_filter.dart';
import 'package:tmail_ui_user/features/base/model/filter_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/styles/advanced_search_input_form_style.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/date_drop_down_button.dart';
import 'package:tmail_ui_user/features/base/widget/default_field/date_drop_down_button.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/label_advanced_search_field_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/sort_by_drop_down_button.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_autocomplete_email_address_web.dart';
@@ -29,7 +29,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
child: Column(
children: [
Obx(() => TextFieldAutocompleteEmailAddressWeb(
field: AdvancedSearchFilterField.from,
field: FilterField.from,
listEmailAddress: controller.listFromEmailAddress,
expandMode: controller.fromAddressExpandMode.value,
minInputLengthAutocomplete: controller
@@ -47,7 +47,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
)),
const SizedBox(height: 12),
Obx(() => TextFieldAutocompleteEmailAddressWeb(
field: AdvancedSearchFilterField.to,
field: FilterField.to,
listEmailAddress: controller.listToEmailAddress,
expandMode: controller.toAddressExpandMode.value,
minInputLengthAutocomplete: controller
@@ -67,11 +67,11 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
_buildFilterField(
textEditingController: controller.subjectFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.subject,
filterField: FilterField.subject,
currentFocusNode: controller.focusManager.subjectFieldFocusNode,
nextFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
onTextChange: (value) => controller.onTextChanged(
AdvancedSearchFilterField.subject,
FilterField.subject,
value
),
),
@@ -79,11 +79,11 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
_buildFilterField(
textEditingController: controller.hasKeyWordFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.hasKeyword,
filterField: FilterField.hasKeyword,
currentFocusNode: controller.focusManager.hasKeywordFieldFocusNode,
nextFocusNode: controller.focusManager.notKeywordFieldFocusNode,
onTextChange: (value) => controller.onTextChanged(
AdvancedSearchFilterField.hasKeyword,
FilterField.hasKeyword,
value
),
),
@@ -91,11 +91,11 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
_buildFilterField(
textEditingController: controller.notKeyWordFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.notKeyword,
filterField: FilterField.notKeyword,
currentFocusNode: controller.focusManager.notKeywordFieldFocusNode,
nextFocusNode: controller.focusManager.mailboxFieldFocusNode,
onTextChange: (value) => controller.onTextChanged(
AdvancedSearchFilterField.notKeyword,
FilterField.notKeyword,
value
),
),
@@ -103,7 +103,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
_buildFilterField(
textEditingController: controller.mailBoxFilterInputController,
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.mailBox,
filterField: FilterField.mailBox,
isSelectFormList: true,
currentFocusNode: controller.focusManager.mailboxFieldFocusNode,
nextFocusNode: controller.focusManager.attachmentCheckboxFocusNode,
@@ -114,7 +114,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Row(children: [
Expanded(child: _buildFilterField(
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.date,
filterField: FilterField.date,
isSelectFormList: true,
onTap: () {
openContextMenuAction(
@@ -151,7 +151,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
const SizedBox(height: 12),
_buildFilterField(
context: context,
advancedSearchFilterField: AdvancedSearchFilterField.sortBy
filterField: FilterField.sortBy
),
const SizedBox(height: 24),
AdvancedSearchFilterFormBottomView(focusManager: controller.focusManager)
@@ -161,7 +161,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
}
List<Widget> _buildEmailReceiveTimeTypeActionTiles(BuildContext context) {
return EmailReceiveTimeType.values
return EmailReceiveTimeType.valuesForSearch
.map((receiveTime) => PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupItemNoIconWidget(
@@ -176,7 +176,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Widget _buildFilterField({
required BuildContext context,
required AdvancedSearchFilterField advancedSearchFilterField,
required FilterField filterField,
TextEditingController? textEditingController,
VoidCallback? onTap,
bool isSelectFormList = false,
@@ -189,7 +189,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
SizedBox(
width: _isVerticalArrange(context) ? null : 112,
child: LabelAdvancedSearchFieldWidget(
name: advancedSearchFilterField.getTitle(context),
name: filterField.getTitle(AppLocalizations.of(context)),
),
),
if (_isVerticalArrange(context))
@@ -204,20 +204,21 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
mouseCursor: mouseCursor,
currentFocusNode: currentFocusNode,
nextFocusNode: nextFocusNode,
advancedSearchFilterField: advancedSearchFilterField,
filterField: filterField,
textEditingController: textEditingController,
onTextChange: onTextChange,
)
else if (controller.responsiveUtils.landscapeTabletSupported(context))
if (advancedSearchFilterField == AdvancedSearchFilterField.date)
if (filterField == FilterField.date)
Obx(() => DateDropDownButton(
controller.imagePaths,
imagePaths: controller.imagePaths,
receiveTimeTypes: EmailReceiveTimeType.valuesForSearch,
startDate: controller.startDate.value,
endDate: controller.endDate.value,
receiveTimeSelected: controller.receiveTimeType.value,
receiveTimeTypeSelected: controller.receiveTimeType.value,
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
))
else if (advancedSearchFilterField == AdvancedSearchFilterField.sortBy)
else if (filterField == FilterField.sortBy)
Obx(() => SortByDropDownButton(
imagePaths: controller.imagePaths,
sortOrderSelected: controller.sortOrderType.value,
@@ -231,7 +232,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
mouseCursor: mouseCursor,
currentFocusNode: currentFocusNode,
nextFocusNode: nextFocusNode,
advancedSearchFilterField: advancedSearchFilterField,
filterField: filterField,
textEditingController: textEditingController,
onTextChange: onTextChange,
)
@@ -244,7 +245,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
mouseCursor: mouseCursor,
currentFocusNode: currentFocusNode,
nextFocusNode: nextFocusNode,
advancedSearchFilterField: advancedSearchFilterField,
filterField: filterField,
textEditingController: textEditingController,
onTextChange: onTextChange,
),
@@ -269,7 +270,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Widget _buildTextFieldFilterForWeb({
required BuildContext context,
required AdvancedSearchFilterField advancedSearchFilterField,
required FilterField filterField,
TextEditingController? textEditingController,
VoidCallback? onTap,
bool isSelectFormList = false,
@@ -278,16 +279,17 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
FocusNode? nextFocusNode,
ValueChanged<String>? onTextChange,
}) {
switch (advancedSearchFilterField) {
case AdvancedSearchFilterField.date:
switch (filterField) {
case FilterField.date:
return Obx(() => DateDropDownButton(
controller.imagePaths,
imagePaths: controller.imagePaths,
receiveTimeTypes: EmailReceiveTimeType.valuesForSearch,
startDate: controller.startDate.value,
endDate: controller.endDate.value,
receiveTimeSelected: controller.receiveTimeType.value,
receiveTimeTypeSelected: controller.receiveTimeType.value,
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
));
case AdvancedSearchFilterField.sortBy:
case FilterField.sortBy:
return Obx(() => SortByDropDownButton(
imagePaths: controller.imagePaths,
sortOrderSelected: controller.sortOrderType.value,
@@ -301,7 +303,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
mouseCursor: mouseCursor,
currentFocusNode: currentFocusNode,
nextFocusNode: nextFocusNode,
advancedSearchFilterField: advancedSearchFilterField,
filterField: filterField,
textEditingController: textEditingController,
onTextChange: onTextChange,
);
@@ -310,7 +312,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
Widget _buildTextField({
required BuildContext context,
required AdvancedSearchFilterField advancedSearchFilterField,
required FilterField filterField,
TextEditingController? textEditingController,
VoidCallback? onTap,
bool isSelectFormList = false,
@@ -378,9 +380,9 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
color: AppColor.primaryColor,
),
),
hintText: advancedSearchFilterField.getHintText(context),
hintText: filterField.getHintText(AppLocalizations.of(context)),
hintStyle: ThemeUtils.textStyleBodyBody3(
color: advancedSearchFilterField == AdvancedSearchFilterField.mailBox
color: filterField == FilterField.mailBox
? Colors.black
: AppColor.m3Tertiary,
),
@@ -13,26 +13,27 @@ import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/extensions/email_address_extension.dart';
import 'package:model/mailbox/expand_mode.dart';
import 'package:super_tag_editor/tag_editor.dart';
import 'package:tmail_ui_user/features/base/model/filter_filter.dart';
import 'package:tmail_ui_user/features/base/widget/default_field/default_autocomplete_tag_item_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/draggable_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/model/suggestion_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_suggestion_item_widget.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/styles/advanced_search_input_form_style.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/text_field_autocomplete_email_address_web_style.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/autocomplete_tag_item_widget_web.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/label_advanced_search_field_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/utils/app_config.dart';
typedef OnSuggestionEmailAddress = Future<List<EmailAddress>> Function(String word, {int? limit});
typedef OnUpdateListEmailAddressAction = void Function(AdvancedSearchFilterField field, List<EmailAddress> newData);
typedef OnDeleteEmailAddressTypeAction = void Function(AdvancedSearchFilterField field);
typedef OnShowFullListEmailAddressAction = void Function(AdvancedSearchFilterField field);
typedef OnUpdateListEmailAddressAction = void Function(FilterField field, List<EmailAddress> newData);
typedef OnDeleteEmailAddressTypeAction = void Function(FilterField field);
typedef OnShowFullListEmailAddressAction = void Function(FilterField field);
typedef OnDeleteTagAction = void Function(EmailAddress emailAddress);
class TextFieldAutocompleteEmailAddressWeb extends StatefulWidget {
final AdvancedSearchFilterField field;
final FilterField field;
final List<EmailAddress> listEmailAddress;
final ExpandMode expandMode;
final FocusNode? focusNode;
@@ -106,7 +107,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
SizedBox(
width: TextFieldAutoCompleteEmailAddressWebStyles.fieldTitleWidth,
child: LabelAdvancedSearchFieldWidget(
name: widget.field.getTitle(context),
name: widget.field.getTitle(AppLocalizations.of(context)),
),
),
const SizedBox(width: TextFieldAutoCompleteEmailAddressWebStyles.space),
@@ -147,7 +148,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
),
fillColor: TextFieldAutoCompleteEmailAddressWebStyles.textInputFillColor,
border: TextFieldAutoCompleteEmailAddressWebStyles.textInputBorder,
hintText: widget.field.getHintText(context),
hintText: widget.field.getHintText(AppLocalizations.of(context)),
hintStyle: TextFieldAutoCompleteEmailAddressWebStyles.textInputHintStyle,
isDense: true,
contentPadding: _currentListEmailAddress.isNotEmpty
@@ -181,7 +182,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
tagBuilder: (context, index) {
final currentEmailAddress = _currentListEmailAddress.elementAt(index);
final isLatestEmail = currentEmailAddress == _currentListEmailAddress.last;
return AutoCompleteTagItemWidgetWeb(
return DefaultAutocompleteTagItemWidget(
field: widget.field,
currentEmailAddress: currentEmailAddress,
currentListEmailAddress: _currentListEmailAddress,
@@ -189,6 +190,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
isLatestEmail: isLatestEmail,
isCollapsed: _isCollapse,
isLatestTagFocused: _lastTagFocused,
iconClose: _imagePaths.icClose,
onDeleteTagAction: (emailAddress) => _handleDeleteTagAction.call(emailAddress, setState),
onShowFullAction: widget.onShowFullListEmailAddressAction,
);
@@ -389,7 +391,7 @@ class _TextFieldAutocompleteEmailAddressWebState extends State<TextFieldAutocomp
StateSetter stateSetter
) {
log('_TextFieldAutocompleteEmailAddressWebState::_handleAcceptDraggableEmailAddressAction:draggableEmailAddress = $draggableEmailAddress');
if (draggableEmailAddress.prefix != widget.field.getPrefixEmailAddress()) {
if (draggableEmailAddress.filterField != widget.field) {
if (!_currentListEmailAddress.contains(draggableEmailAddress.emailAddress)) {
stateSetter(() {
_currentListEmailAddress.add(draggableEmailAddress.emailAddress);
@@ -346,7 +346,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
}
void _openPopupMenuDateFilter(BuildContext context, RelativeRect position) {
final popupMenuItems = EmailReceiveTimeType.values.map((timeType) {
final popupMenuItems = EmailReceiveTimeType.valuesForSearch.map((timeType) {
return PopupMenuItem(
padding: EdgeInsets.zero,
child: PopupMenuItemActionWidget(
@@ -371,7 +371,7 @@ class SearchEmailView extends GetWidget<SearchEmailController>
}
void _openContextMenuDateFilter(BuildContext context) {
final contextMenuActions = EmailReceiveTimeType.values.map((timeType) {
final contextMenuActions = EmailReceiveTimeType.valuesForSearch.map((timeType) {
return ContextItemReceiveTimeTypeAction(
timeType,
controller.emailReceiveTimeType.value,