TF-1477 Improve UX for advanced and quick search
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/app_toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_date_range_picker/multiple_view_date_range_picker.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
|
||||
|
||||
mixin DateRangePickerMixin {
|
||||
|
||||
void showMultipleViewDateRangePicker(
|
||||
BuildContext context,
|
||||
DateTime? initStartDate,
|
||||
DateTime? initEndDate,
|
||||
{Function(DateTime? startDate, DateTime? endDate)? onCallbackAction}
|
||||
) {
|
||||
showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: '',
|
||||
barrierColor: Colors.black54,
|
||||
pageBuilder: (context, _, __) {
|
||||
return Dialog(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0)),
|
||||
child: PointerInterceptor(child: MultipleViewDateRangePicker(
|
||||
confirmText: AppLocalizations.of(context).setDate,
|
||||
cancelText: AppLocalizations.of(context).cancel,
|
||||
last7daysTitle: AppLocalizations.of(context).last7Days,
|
||||
last30daysTitle: AppLocalizations.of(context).last30Days,
|
||||
last6monthsTitle: AppLocalizations.of(context).last6Months,
|
||||
lastYearTitle: AppLocalizations.of(context).lastYears,
|
||||
startDate: initStartDate,
|
||||
endDate: initEndDate,
|
||||
setDateActionCallback: ({startDate, endDate}) =>
|
||||
_handleSelectDateRangeResult(
|
||||
context,
|
||||
startDate,
|
||||
endDate,
|
||||
onCallbackAction: onCallbackAction
|
||||
)
|
||||
))
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSelectDateRangeResult(
|
||||
BuildContext context,
|
||||
DateTime? startDate,
|
||||
DateTime? endDate,
|
||||
{Function(DateTime? startDate, DateTime? endDate)? onCallbackAction}
|
||||
) {
|
||||
final _appToast = Get.find<AppToast>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
if (startDate == null) {
|
||||
_appToast.showToastWithIcon(
|
||||
context,
|
||||
textColor: Colors.black,
|
||||
message: AppLocalizations.of(context).toastMessageErrorWhenSelectStartDateIsEmpty,
|
||||
icon: _imagePaths.icNotConnection
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (endDate == null) {
|
||||
_appToast.showToastWithIcon(
|
||||
context,
|
||||
textColor: Colors.black,
|
||||
message: AppLocalizations.of(context).toastMessageErrorWhenSelectEndDateIsEmpty,
|
||||
icon: _imagePaths.icNotConnection
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (endDate.isBefore(startDate)) {
|
||||
_appToast.showToastWithIcon(
|
||||
context,
|
||||
textColor: Colors.black,
|
||||
message: AppLocalizations.of(context).toastMessageErrorWhenSelectDateIsInValid,
|
||||
icon: _imagePaths.icNotConnection
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
popBack();
|
||||
onCallbackAction?.call(startDate, endDate);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class DropDownButtonWidget<T> extends StatelessWidget {
|
||||
final double radiusButton;
|
||||
final double opacity;
|
||||
final Widget? iconArrowDown;
|
||||
final Color? colorButton;
|
||||
final Color colorButton;
|
||||
final String tooltip;
|
||||
final double? dropdownWidth;
|
||||
final double? dropdownMaxHeight;
|
||||
@@ -36,7 +36,7 @@ class DropDownButtonWidget<T> extends StatelessWidget {
|
||||
const DropDownButtonWidget({
|
||||
Key? key,
|
||||
required this.items,
|
||||
required this.itemSelected,
|
||||
this.itemSelected,
|
||||
this.onChanged,
|
||||
this.onMenuStateChange,
|
||||
this.supportHint = false,
|
||||
@@ -112,7 +112,7 @@ class DropDownButtonWidget<T> extends StatelessWidget {
|
||||
color: AppColor.colorInputBorderCreateMailbox,
|
||||
width: 1,
|
||||
),
|
||||
color: colorButton ?? AppColor.colorInputBackgroundCreateMailbox,
|
||||
color: colorButton,
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 12, right: 10),
|
||||
child: Row(children: [
|
||||
@@ -139,7 +139,7 @@ class DropDownButtonWidget<T> extends StatelessWidget {
|
||||
color: AppColor.colorInputBorderCreateMailbox,
|
||||
width: 1,
|
||||
),
|
||||
color: colorButton ?? AppColor.colorInputBackgroundCreateMailbox,
|
||||
color: colorButton,
|
||||
),
|
||||
itemHeight: heightItem,
|
||||
buttonHeight: heightItem,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
|
||||
class PopupItemNoIconWidget extends StatelessWidget {
|
||||
|
||||
final String _nameAction;
|
||||
final String? svgIconSelected;
|
||||
final bool isSelected;
|
||||
final double? maxWidth;
|
||||
final TextStyle? styleName;
|
||||
final EdgeInsets? padding;
|
||||
final VoidCallback? onCallbackAction;
|
||||
|
||||
const PopupItemNoIconWidget(
|
||||
this._nameAction,
|
||||
{
|
||||
Key? key,
|
||||
this.isSelected = false,
|
||||
this.svgIconSelected,
|
||||
this.maxWidth,
|
||||
this.styleName,
|
||||
this.padding,
|
||||
this.onCallbackAction
|
||||
}
|
||||
) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PointerInterceptor(
|
||||
child: InkWell(
|
||||
onTap: onCallbackAction,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: SizedBox(
|
||||
width: maxWidth,
|
||||
child: Row(children: [
|
||||
Expanded(child: Text(
|
||||
_nameAction,
|
||||
style: const TextStyle(
|
||||
fontSize: 17,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.normal
|
||||
)
|
||||
)),
|
||||
if (isSelected && svgIconSelected != null)
|
||||
...[
|
||||
const SizedBox(width: 12),
|
||||
SvgPicture.asset(
|
||||
svgIconSelected!,
|
||||
width: 24,
|
||||
height: 24,
|
||||
fit: BoxFit.fill
|
||||
),
|
||||
]
|
||||
]),
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import 'package:model/email/email_action_type.dart';
|
||||
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/thread/domain/model/filter_message_option.dart';
|
||||
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
|
||||
|
||||
@@ -134,4 +135,25 @@ class OpenMailboxAction extends DashBoardAction {
|
||||
|
||||
@override
|
||||
List<Object?> get props => [context, presentationMailbox];
|
||||
}
|
||||
|
||||
class SelectDateRangeToAdvancedSearch extends DashBoardAction {
|
||||
|
||||
final DateTime? startDate;
|
||||
final DateTime? endDate;
|
||||
|
||||
SelectDateRangeToAdvancedSearch(this.startDate, this.endDate);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [startDate, endDate];
|
||||
}
|
||||
|
||||
class ClearDateRangeToAdvancedSearch extends DashBoardAction {
|
||||
|
||||
final EmailReceiveTimeType receiveTime;
|
||||
|
||||
ClearDateRangeToAdvancedSearch(this.receiveTime);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [receiveTime];
|
||||
}
|
||||
+67
-125
@@ -2,14 +2,12 @@ import 'package:collection/collection.dart';
|
||||
import 'package:core/core.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_date_range_picker/multiple_view_date_range_picker.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/session/session.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/model/contact_suggestion_source.dart';
|
||||
import 'package:tmail_ui_user/features/composer/domain/state/get_autocomplete_state.dart';
|
||||
@@ -37,28 +35,24 @@ class AdvancedFilterController extends BaseController {
|
||||
final hasAttachment = false.obs;
|
||||
final lastTextForm = ''.obs;
|
||||
final lastTextTo = ''.obs;
|
||||
final startDate = Rxn<DateTime>();
|
||||
final endDate = Rxn<DateTime>();
|
||||
|
||||
TextEditingController subjectFilterInputController = TextEditingController();
|
||||
TextEditingController hasKeyWordFilterInputController = TextEditingController();
|
||||
TextEditingController notKeyWordFilterInputController = TextEditingController();
|
||||
TextEditingController dateFilterInputController = TextEditingController();
|
||||
TextEditingController mailBoxFilterInputController = TextEditingController();
|
||||
ContactSuggestionSource _contactSuggestionSource = ContactSuggestionSource.tMailContact;
|
||||
|
||||
final SearchController searchController = Get.find<SearchController>();
|
||||
final MailboxDashBoardController _mailboxDashBoardController = Get.find<MailboxDashBoardController>();
|
||||
final _appToast = Get.find<AppToast>();
|
||||
final _imagePaths = Get.find<ImagePaths>();
|
||||
|
||||
SearchEmailFilter get searchEmailFilter =>
|
||||
searchController.searchEmailFilter.value;
|
||||
|
||||
final focusManager = InputFieldFocusManager.initial();
|
||||
|
||||
DateTime? _startDate, _endDate;
|
||||
|
||||
DateTime? get startDate => _startDate;
|
||||
|
||||
DateTime? get endDate => _endDate;
|
||||
PresentationMailbox? _destinationMailboxSelected;
|
||||
|
||||
late Worker _dashboardActionWorker;
|
||||
|
||||
@@ -83,17 +77,15 @@ class AdvancedFilterController extends BaseController {
|
||||
|
||||
void cleanSearchFilter(BuildContext context) {
|
||||
searchController.clearSearchFilter();
|
||||
dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.allTime;
|
||||
clearDateRangeOfFilter();
|
||||
_updateDateRangeTime(EmailReceiveTimeType.allTime);
|
||||
subjectFilterInputController.text = '';
|
||||
hasKeyWordFilterInputController.text = '';
|
||||
notKeyWordFilterInputController.text = '';
|
||||
dateFilterInputController.text = '';
|
||||
hasAttachment.value = false;
|
||||
_destinationMailboxSelected = null;
|
||||
searchController.deactivateAdvancedSearch();
|
||||
searchController.isAdvancedSearchViewOpen.toggle();
|
||||
_mailboxDashBoardController.searchEmail(
|
||||
context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value));
|
||||
_mailboxDashBoardController.searchEmail(context, StringConvert.writeNullToEmpty(searchEmailFilter.text?.value));
|
||||
}
|
||||
|
||||
void _updateFilterEmailFromAdvancedSearchView() {
|
||||
@@ -127,11 +119,12 @@ class AdvancedFilterController extends BaseController {
|
||||
}
|
||||
|
||||
searchController.updateFilterEmail(
|
||||
mailbox: _destinationMailboxSelected,
|
||||
subjectOption: optionOf(subjectFilterInputController.text),
|
||||
emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value,
|
||||
hasAttachment: hasAttachment.value,
|
||||
endDate: _endDate.toUTCDate(),
|
||||
startDate: _startDate.toUTCDate()
|
||||
startDateOption: optionOf(startDate.value?.toUTCDate()),
|
||||
endDateOption: optionOf(endDate.value?.toUTCDate())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -150,9 +143,9 @@ class AdvancedFilterController extends BaseController {
|
||||
context: context,
|
||||
arguments: arguments,
|
||||
onSelectedMailbox: (destinationMailbox) {
|
||||
searchController.updateFilterEmail(mailbox: destinationMailbox);
|
||||
mailBoxFilterInputController.text =
|
||||
StringConvert.writeNullToEmpty(destinationMailbox.name?.name);
|
||||
_destinationMailboxSelected = destinationMailbox;
|
||||
final mailboxName = destinationMailbox.name?.name;
|
||||
mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(mailboxName);
|
||||
});
|
||||
} else {
|
||||
final destinationMailbox = await push(
|
||||
@@ -160,9 +153,9 @@ class AdvancedFilterController extends BaseController {
|
||||
arguments: arguments);
|
||||
|
||||
if (destinationMailbox is PresentationMailbox) {
|
||||
searchController.updateFilterEmail(mailbox: destinationMailbox);
|
||||
mailBoxFilterInputController.text =
|
||||
StringConvert.writeNullToEmpty(destinationMailbox.name?.name);
|
||||
_destinationMailboxSelected = destinationMailbox;
|
||||
final mailboxName = destinationMailbox.name?.name;
|
||||
mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(mailboxName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,8 +169,7 @@ class AdvancedFilterController extends BaseController {
|
||||
searchController.deactivateAdvancedSearch();
|
||||
}
|
||||
if (!isAdvancedSearchHasApplied) {
|
||||
final newSearchEmailFilter = searchController.searchEmailFilter.value.clearBeforeDate();
|
||||
searchController.searchEmailFilter.value = newSearchEmailFilter;
|
||||
searchController.updateFilterEmail(beforeOption: const None());
|
||||
}
|
||||
searchController.isAdvancedSearchViewOpen.toggle();
|
||||
_mailboxDashBoardController.searchEmail(
|
||||
@@ -259,111 +251,55 @@ class AdvancedFilterController extends BaseController {
|
||||
}
|
||||
|
||||
void initSearchFilterField(BuildContext context) {
|
||||
searchController.updateFilterEmail(
|
||||
mailbox: PresentationMailbox.unifiedMailbox);
|
||||
subjectFilterInputController.text =
|
||||
StringConvert.writeNullToEmpty(searchEmailFilter.subject);
|
||||
hasKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(
|
||||
searchEmailFilter.text?.value);
|
||||
notKeyWordFilterInputController.text = StringConvert.writeNullToEmpty(
|
||||
searchEmailFilter.notKeyword.firstOrNull);
|
||||
dateFilterInputController.text = StringConvert.writeNullToEmpty(
|
||||
searchEmailFilter.emailReceiveTimeType.getTitle(
|
||||
context,
|
||||
startDate: _startDate,
|
||||
endDate: _endDate));
|
||||
mailBoxFilterInputController.text =
|
||||
StringConvert.writeNullToEmpty(searchEmailFilter.mailbox?.name?.name);
|
||||
dateFilterSelectedFormAdvancedSearch.value =
|
||||
searchEmailFilter.emailReceiveTimeType;
|
||||
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 (searchEmailFilter.mailbox == null) {
|
||||
mailBoxFilterInputController.text = AppLocalizations.of(context).allMailboxes;
|
||||
} else {
|
||||
mailBoxFilterInputController.text = StringConvert.writeNullToEmpty(searchEmailFilter.mailbox?.name?.name);
|
||||
}
|
||||
hasAttachment.value = searchEmailFilter.hasAttachment;
|
||||
}
|
||||
|
||||
void selectDateRange(BuildContext context) {
|
||||
showGeneralDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
barrierLabel: '',
|
||||
barrierColor: Colors.black54,
|
||||
pageBuilder: (context, animation, secondaryAnimation) {
|
||||
return Dialog(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(18.0)),
|
||||
child: PointerInterceptor(
|
||||
child: MultipleViewDateRangePicker(
|
||||
confirmText: AppLocalizations.of(context).setDate,
|
||||
cancelText: AppLocalizations.of(context).cancel,
|
||||
last7daysTitle: AppLocalizations.of(context).last7Days,
|
||||
last30daysTitle: AppLocalizations.of(context).last30Days,
|
||||
last6monthsTitle: AppLocalizations.of(context).last6Months,
|
||||
lastYearTitle: AppLocalizations.of(context).lastYears,
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
setDateActionCallback: ({startDate, endDate}) {
|
||||
_handleSelectDateRangeResult(context, startDate, endDate);
|
||||
},
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
searchController.showMultipleViewDateRangePicker(
|
||||
context,
|
||||
startDate.value,
|
||||
endDate.value,
|
||||
onCallbackAction: (startDate, endDate) =>
|
||||
_updateDateRangeTime(
|
||||
EmailReceiveTimeType.customRange,
|
||||
newStartDate: startDate,
|
||||
newEndDate: endDate
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSelectDateRangeResult(
|
||||
BuildContext context,
|
||||
DateTime? startDate,
|
||||
DateTime? endDate
|
||||
) {
|
||||
log('AdvancedFilterController::_handleSelectDateRangeResult(): startDate: $startDate');
|
||||
log('AdvancedFilterController::_handleSelectDateRangeResult(): endDate: $endDate');
|
||||
if (startDate == null) {
|
||||
_appToast.showToastWithIcon(
|
||||
context,
|
||||
textColor: Colors.black,
|
||||
message: AppLocalizations.of(context).toastMessageErrorWhenSelectStartDateIsEmpty,
|
||||
icon: _imagePaths.icNotConnection);
|
||||
return;
|
||||
}
|
||||
if (endDate == null) {
|
||||
_appToast.showToastWithIcon(
|
||||
context,
|
||||
textColor: Colors.black,
|
||||
message: AppLocalizations.of(context).toastMessageErrorWhenSelectEndDateIsEmpty,
|
||||
icon: _imagePaths.icNotConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (endDate.isBefore(startDate)) {
|
||||
_appToast.showToastWithIcon(
|
||||
context,
|
||||
textColor: Colors.black,
|
||||
message: AppLocalizations.of(context).toastMessageErrorWhenSelectDateIsInValid,
|
||||
icon: _imagePaths.icNotConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
_startDate = startDate;
|
||||
_endDate = endDate;
|
||||
dateFilterSelectedFormAdvancedSearch.value = EmailReceiveTimeType.customRange;
|
||||
dateFilterInputController.text = EmailReceiveTimeType.customRange.getTitle(
|
||||
context,
|
||||
startDate: startDate,
|
||||
endDate: endDate);
|
||||
dateFilterSelectedFormAdvancedSearch.refresh();
|
||||
|
||||
popBack();
|
||||
void _updateDateRangeTime(EmailReceiveTimeType receiveTime, {DateTime? newStartDate, DateTime? newEndDate}) {
|
||||
startDate.value = newStartDate;
|
||||
endDate.value = newEndDate;
|
||||
dateFilterSelectedFormAdvancedSearch.value = receiveTime;
|
||||
}
|
||||
|
||||
void clearDateRangeOfFilter() {
|
||||
_startDate = null;
|
||||
_endDate = null;
|
||||
|
||||
searchController.searchEmailFilter.value =
|
||||
searchController.searchEmailFilter.value.withDateRange(
|
||||
startDate: _startDate.toUTCDate(),
|
||||
endDate: _endDate.toUTCDate());
|
||||
void updateReceiveDateSearchFilter(BuildContext context, EmailReceiveTimeType receiveTime) {
|
||||
if (receiveTime == EmailReceiveTimeType.customRange) {
|
||||
searchController.showMultipleViewDateRangePicker(
|
||||
context,
|
||||
startDate.value,
|
||||
endDate.value,
|
||||
onCallbackAction: (startDate, endDate) =>
|
||||
_updateDateRangeTime(
|
||||
EmailReceiveTimeType.customRange,
|
||||
newStartDate: startDate,
|
||||
newEndDate: endDate
|
||||
)
|
||||
);
|
||||
} else {
|
||||
_updateDateRangeTime(receiveTime);
|
||||
}
|
||||
}
|
||||
|
||||
void _resetAllToOriginalValue() {
|
||||
@@ -371,15 +307,14 @@ class AdvancedFilterController extends BaseController {
|
||||
hasAttachment.value = false;
|
||||
lastTextForm.value = '';
|
||||
lastTextTo.value = '';
|
||||
_startDate = null;
|
||||
_endDate = null;
|
||||
startDate.value = null;
|
||||
endDate.value = null;
|
||||
}
|
||||
|
||||
void _clearAllTextFieldInput() {
|
||||
subjectFilterInputController.clear();
|
||||
hasKeyWordFilterInputController.clear();
|
||||
notKeyWordFilterInputController.clear();
|
||||
dateFilterInputController.clear();
|
||||
mailBoxFilterInputController.clear();
|
||||
}
|
||||
|
||||
@@ -389,6 +324,14 @@ class AdvancedFilterController extends BaseController {
|
||||
(action) {
|
||||
if (action is ClearAllFieldOfAdvancedSearchAction) {
|
||||
_handleClearAllFieldOfAdvancedSearch();
|
||||
} else if (action is SelectDateRangeToAdvancedSearch) {
|
||||
_updateDateRangeTime(
|
||||
EmailReceiveTimeType.customRange,
|
||||
newStartDate: action.startDate,
|
||||
newEndDate: action.endDate
|
||||
);
|
||||
} else if (action is ClearDateRangeToAdvancedSearch) {
|
||||
_updateDateRangeTime(action.receiveTime);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -410,7 +353,6 @@ class AdvancedFilterController extends BaseController {
|
||||
hasKeyWordFilterInputController.dispose();
|
||||
notKeyWordFilterInputController.dispose();
|
||||
mailBoxFilterInputController.dispose();
|
||||
dateFilterInputController.dispose();
|
||||
_unregisterWorkerListener();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
+36
-30
@@ -73,6 +73,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/state/update_vacati
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_vacation_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/domain/usecases/update_vacation_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart';
|
||||
import 'package:tmail_ui_user/features/manage_account/presentation/model/manage_account_arguments.dart';
|
||||
@@ -535,9 +536,6 @@ class MailboxDashBoardController extends ReloadableController {
|
||||
if (_searchInsideEmailDetailedViewIsActive(context)) {
|
||||
_closeEmailDetailedView();
|
||||
}
|
||||
if (value.isEmpty){
|
||||
searchController.setEmailReceiveTimeType(null);
|
||||
}
|
||||
_unSelectedMailbox();
|
||||
}
|
||||
|
||||
@@ -1281,23 +1279,13 @@ class MailboxDashBoardController extends ReloadableController {
|
||||
}
|
||||
}
|
||||
|
||||
void selectQuickSearchFilter({
|
||||
required QuickSearchFilter quickSearchFilter,
|
||||
bool fromSuggestionBox = false,
|
||||
}) => searchController.selectQuickSearchFilter(
|
||||
quickSearchFilter: quickSearchFilter,
|
||||
userProfile: userProfile.value!,
|
||||
fromSuggestionBox: fromSuggestionBox,
|
||||
);
|
||||
void selectQuickSearchFilter(QuickSearchFilter filter) {
|
||||
return searchController.selectQuickSearchFilter(filter, userProfile.value!);
|
||||
}
|
||||
|
||||
bool checkQuickSearchFilterSelected({
|
||||
required QuickSearchFilter quickSearchFilter,
|
||||
bool fromSuggestionBox = false,
|
||||
}) => searchController.checkQuickSearchFilterSelected(
|
||||
quickSearchFilter: quickSearchFilter,
|
||||
userProfile: userProfile.value!,
|
||||
fromSuggestionBox: fromSuggestionBox,
|
||||
);
|
||||
void addFilterToSuggestionForm(QuickSearchFilter filter) {
|
||||
searchController.addFilterToSuggestionForm(filter);
|
||||
}
|
||||
|
||||
Future<List<PresentationEmail>> quickSearchEmails() => searchController.quickSearchEmails(accountId: accountId.value!);
|
||||
|
||||
@@ -1353,26 +1341,44 @@ class MailboxDashBoardController extends ReloadableController {
|
||||
|
||||
void selectQuickSearchFilterAction(QuickSearchFilter filter) {
|
||||
log('MailboxDashBoardController::selectQuickSearchFilterAction(): filter: $filter');
|
||||
selectQuickSearchFilter(quickSearchFilter: filter);
|
||||
selectQuickSearchFilter(filter);
|
||||
dispatchAction(StartSearchEmailAction());
|
||||
}
|
||||
|
||||
void selectReceiveTimeQuickSearchFilter(EmailReceiveTimeType? emailReceiveTimeType) {
|
||||
void selectReceiveTimeQuickSearchFilter(BuildContext context, EmailReceiveTimeType receiveTime) {
|
||||
log('MailboxDashBoardController::selectReceiveTimeQuickSearchFilter():receiveTime: $receiveTime');
|
||||
popBack();
|
||||
|
||||
if (emailReceiveTimeType != null) {
|
||||
searchController.updateFilterEmail(emailReceiveTimeType: emailReceiveTimeType);
|
||||
if (receiveTime == EmailReceiveTimeType.customRange) {
|
||||
searchController.showMultipleViewDateRangePicker(
|
||||
context,
|
||||
searchController.startDateFiltered,
|
||||
searchController.endDateFiltered,
|
||||
onCallbackAction: (startDate, endDate) {
|
||||
dispatchAction(SelectDateRangeToAdvancedSearch(startDate, endDate));
|
||||
searchController.updateFilterEmail(
|
||||
emailReceiveTimeType: receiveTime,
|
||||
startDateOption: optionOf(startDate?.toUTCDate()),
|
||||
endDateOption: optionOf(startDate?.toUTCDate()),
|
||||
beforeOption: const None()
|
||||
);
|
||||
dispatchAction(StartSearchEmailAction());
|
||||
}
|
||||
);
|
||||
} else {
|
||||
searchController.updateFilterEmail(emailReceiveTimeType: EmailReceiveTimeType.allTime);
|
||||
dispatchAction(ClearDateRangeToAdvancedSearch(receiveTime));
|
||||
searchController.updateFilterEmail(
|
||||
emailReceiveTimeType: receiveTime,
|
||||
startDateOption: const None(),
|
||||
endDateOption: const None(),
|
||||
beforeOption: const None()
|
||||
);
|
||||
dispatchAction(StartSearchEmailAction());
|
||||
}
|
||||
searchController.setEmailReceiveTimeType(emailReceiveTimeType);
|
||||
searchController.updateFilterEmail();
|
||||
if (searchController.searchQuery == null){
|
||||
searchController.updateFilterEmail(text: SearchQuery.initial());
|
||||
}
|
||||
dispatchAction(StartSearchEmailAction());
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool get isMailboxTrash => selectedMailbox.value?.isTrash == true;
|
||||
|
||||
void emptyTrashAction(BuildContext context) {
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:core/presentation/utils/responsive_utils.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:jmap_dart_client/jmap/account_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/filter/filter.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/sort/comparator.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/unsigned_int.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/utc_date.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_comparator.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_comparator_property.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart';
|
||||
import 'package:model/email/presentation_email.dart';
|
||||
import 'package:model/extensions/email_filter_condition_extension.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
import 'package:model/user/user_profile.dart';
|
||||
import 'package:tmail_ui_user/features/base/base_controller.dart';
|
||||
import 'package:tmail_ui_user/features/base/mixin/date_range_picker_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/get_all_recent_search_latest_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/quick_search_email_state.dart';
|
||||
@@ -27,7 +36,7 @@ import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/model/search_state.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/model/search_status.dart';
|
||||
|
||||
class SearchController extends BaseController {
|
||||
class SearchController extends BaseController with DateRangePickerMixin {
|
||||
final QuickSearchEmailInteractor _quickSearchEmailInteractor;
|
||||
final SaveRecentSearchInteractor _saveRecentSearchInteractor;
|
||||
final GetAllRecentSearchLatestInteractor _getAllRecentSearchLatestInteractor;
|
||||
@@ -38,7 +47,7 @@ class SearchController extends BaseController {
|
||||
final searchEmailFilter = SearchEmailFilter.initial().obs;
|
||||
final searchState = SearchState.initial().obs;
|
||||
final isAdvancedSearchViewOpen = false.obs;
|
||||
final emailReceiveTimeType = Rxn<EmailReceiveTimeType>();
|
||||
final listFilterOnSuggestionForm = RxList<QuickSearchFilter>();
|
||||
final simpleSearchIsActivated = RxBool(false);
|
||||
final advancedSearchIsActivated = RxBool(false);
|
||||
final autoFocus = RxBool(true);
|
||||
@@ -67,53 +76,78 @@ class SearchController extends BaseController {
|
||||
searchEmailFilter.value = SearchEmailFilter.initial();
|
||||
}
|
||||
|
||||
void selectQuickSearchFilter({
|
||||
required QuickSearchFilter quickSearchFilter,
|
||||
required UserProfile userProfile,
|
||||
bool fromSuggestionBox = false,
|
||||
}) {
|
||||
final quickSearchFilterSelected = checkQuickSearchFilterSelected(
|
||||
userProfile: userProfile,
|
||||
quickSearchFilter: quickSearchFilter,
|
||||
fromSuggestionBox: fromSuggestionBox,
|
||||
);
|
||||
void selectQuickSearchFilter(QuickSearchFilter quickSearchFilter, UserProfile userProfile) {
|
||||
final isFilterSelected = quickSearchFilter.isSelected(searchEmailFilter.value, userProfile);
|
||||
|
||||
switch (quickSearchFilter) {
|
||||
case QuickSearchFilter.hasAttachment:
|
||||
updateFilterEmail(hasAttachment: !quickSearchFilterSelected);
|
||||
updateFilterEmail(hasAttachment: !isFilterSelected);
|
||||
return;
|
||||
case QuickSearchFilter.last7Days:
|
||||
if (quickSearchFilterSelected) {
|
||||
setEmailReceiveTimeType(null);
|
||||
updateFilterEmail(emailReceiveTimeType: EmailReceiveTimeType.allTime);
|
||||
} else {
|
||||
setEmailReceiveTimeType(EmailReceiveTimeType.last7Days);
|
||||
updateFilterEmail(emailReceiveTimeType: EmailReceiveTimeType.last7Days);
|
||||
}
|
||||
updateFilterEmail(emailReceiveTimeType: EmailReceiveTimeType.allTime);
|
||||
return;
|
||||
case QuickSearchFilter.fromMe:
|
||||
quickSearchFilterSelected
|
||||
? searchEmailFilter.value.from.removeWhere((e) => e == userProfile.email)
|
||||
: searchEmailFilter.value.from.add(userProfile.email);
|
||||
isFilterSelected
|
||||
? searchEmailFilter.value.from.removeWhere((e) => e == userProfile.email)
|
||||
: searchEmailFilter.value.from.add(userProfile.email);
|
||||
updateFilterEmail(from: searchEmailFilter.value.from);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<PresentationEmail>> quickSearchEmails({required AccountId accountId}) async {
|
||||
return await _quickSearchEmailInteractor
|
||||
.execute(accountId,
|
||||
limit: UnsignedInt(5),
|
||||
sort: <Comparator>{}..add(
|
||||
EmailComparator(EmailComparatorProperty.receivedAt)
|
||||
..setIsAscending(false)),
|
||||
filter: searchEmailFilter.value.mappingToEmailFilterCondition(),
|
||||
properties: ThreadConstants.propertiesQuickSearch)
|
||||
.then((result) => result.fold(
|
||||
(failure) => <PresentationEmail>[],
|
||||
(success) => success is QuickSearchEmailSuccess
|
||||
? success.emailList
|
||||
: <PresentationEmail>[]));
|
||||
void addFilterToSuggestionForm(QuickSearchFilter filter) {
|
||||
if (listFilterOnSuggestionForm.contains(filter)) {
|
||||
listFilterOnSuggestionForm.remove(filter);
|
||||
} else {
|
||||
listFilterOnSuggestionForm.add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<PresentationEmail>> quickSearchEmails({
|
||||
required AccountId accountId,
|
||||
UserProfile? userProfile
|
||||
}) async {
|
||||
return await _quickSearchEmailInteractor.execute(
|
||||
accountId,
|
||||
limit: UnsignedInt(5),
|
||||
sort: <Comparator>{}..add(
|
||||
EmailComparator(EmailComparatorProperty.receivedAt)
|
||||
..setIsAscending(false)),
|
||||
filter: _mappingToFilterOnSuggestionForm(userProfile),
|
||||
properties: ThreadConstants.propertiesQuickSearch
|
||||
).then((result) => result.fold(
|
||||
(failure) => <PresentationEmail>[],
|
||||
(success) => success is QuickSearchEmailSuccess
|
||||
? success.emailList
|
||||
: <PresentationEmail>[]
|
||||
));
|
||||
}
|
||||
|
||||
Filter? _mappingToFilterOnSuggestionForm(UserProfile? userProfile) {
|
||||
final searchText = searchEmailFilter.value.text?.value.trim();
|
||||
|
||||
final filterCondition = EmailFilterCondition(
|
||||
text: searchText?.isNotEmpty == true ? searchText : null,
|
||||
after: listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days)
|
||||
? EmailReceiveTimeType.last7Days.toOldestUTCDate()
|
||||
: null,
|
||||
before: listFilterOnSuggestionForm.contains(QuickSearchFilter.last7Days)
|
||||
? EmailReceiveTimeType.last7Days.toLatestUTCDate()
|
||||
: null,
|
||||
hasAttachment: listFilterOnSuggestionForm.contains(QuickSearchFilter.hasAttachment)
|
||||
? true
|
||||
: null
|
||||
);
|
||||
|
||||
final listEmailCondition = {
|
||||
if (filterCondition.hasCondition) filterCondition,
|
||||
if (listFilterOnSuggestionForm.contains(QuickSearchFilter.fromMe) && userProfile != null)
|
||||
LogicFilterOperator(Operator.AND, {EmailFilterCondition(from: userProfile.email)})
|
||||
};
|
||||
|
||||
return listEmailCondition.isNotEmpty
|
||||
? LogicFilterOperator(Operator.AND, listEmailCondition)
|
||||
: null;
|
||||
}
|
||||
|
||||
void updateFilterEmail({
|
||||
@@ -125,9 +159,9 @@ class SearchController extends BaseController {
|
||||
PresentationMailbox? mailbox,
|
||||
EmailReceiveTimeType? emailReceiveTimeType,
|
||||
bool? hasAttachment,
|
||||
UTCDate? before,
|
||||
UTCDate? startDate,
|
||||
UTCDate? endDate,
|
||||
Option<UTCDate>? beforeOption,
|
||||
Option<UTCDate>? startDateOption,
|
||||
Option<UTCDate>? endDateOption
|
||||
}) {
|
||||
searchEmailFilter.value = searchEmailFilter.value.copyWith(
|
||||
from: from,
|
||||
@@ -138,9 +172,9 @@ class SearchController extends BaseController {
|
||||
mailbox: mailbox,
|
||||
emailReceiveTimeType: emailReceiveTimeType,
|
||||
hasAttachment: hasAttachment,
|
||||
before: before,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
beforeOption: beforeOption,
|
||||
startDateOption: startDateOption,
|
||||
endDateOption: endDateOption,
|
||||
);
|
||||
searchEmailFilter.refresh();
|
||||
}
|
||||
@@ -159,6 +193,12 @@ class SearchController extends BaseController {
|
||||
});
|
||||
}
|
||||
|
||||
EmailReceiveTimeType get receiveTimeFiltered => searchEmailFilter.value.emailReceiveTimeType;
|
||||
|
||||
DateTime? get startDateFiltered => searchEmailFilter.value.startDate?.value.toLocal();
|
||||
|
||||
DateTime? get endDateFiltered => searchEmailFilter.value.endDate?.value.toLocal();
|
||||
|
||||
bool isSearchActive() =>
|
||||
searchState.value.searchStatus == SearchStatus.ACTIVE;
|
||||
|
||||
@@ -188,21 +228,15 @@ class SearchController extends BaseController {
|
||||
searchInputController.text = value;
|
||||
}
|
||||
|
||||
bool checkQuickSearchFilterSelected({
|
||||
required QuickSearchFilter quickSearchFilter,
|
||||
required UserProfile userProfile,
|
||||
bool fromSuggestionBox = false,
|
||||
}) {
|
||||
bool checkQuickSearchFilterSelected(QuickSearchFilter quickSearchFilter, UserProfile userProfile) {
|
||||
switch (quickSearchFilter) {
|
||||
case QuickSearchFilter.hasAttachment:
|
||||
return searchEmailFilter.value.hasAttachment == true;
|
||||
case QuickSearchFilter.last7Days:
|
||||
if (emailReceiveTimeType.value != null) {
|
||||
return true;
|
||||
}
|
||||
return searchEmailFilter.value.emailReceiveTimeType == EmailReceiveTimeType.last7Days;
|
||||
return true;
|
||||
case QuickSearchFilter.fromMe:
|
||||
return searchEmailFilter.value.from.contains( userProfile.email) && searchEmailFilter.value.from.length == 1;
|
||||
return searchEmailFilter.value.from.contains(userProfile.email) &&
|
||||
searchEmailFilter.value.from.length == 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,11 +254,7 @@ class SearchController extends BaseController {
|
||||
: <RecentSearch>[]));
|
||||
}
|
||||
|
||||
void setEmailReceiveTimeType(EmailReceiveTimeType? receiveTimeType) {
|
||||
emailReceiveTimeType.value = receiveTimeType;
|
||||
}
|
||||
|
||||
showAdvancedFilterView(BuildContext context) async {
|
||||
void showAdvancedFilterView(BuildContext context) async {
|
||||
selectOpenAdvanceSearch();
|
||||
if (_responsiveUtils.isMobile(context)) {
|
||||
await showAdvancedSearchFilterBottomSheet(context);
|
||||
@@ -259,7 +289,6 @@ class SearchController extends BaseController {
|
||||
void _clearAllTextInputSimpleSearch() {
|
||||
searchInputController.clear();
|
||||
searchFocus.unfocus();
|
||||
emailReceiveTimeType.value = null;
|
||||
}
|
||||
|
||||
void disableAllSearchEmail() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter_portal/flutter_portal.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
|
||||
@@ -541,8 +542,9 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
||||
QuickSearchFilter filter
|
||||
) {
|
||||
return Obx(() {
|
||||
final quickSearchFilterSelected = controller.checkQuickSearchFilterSelected(
|
||||
quickSearchFilter: filter,
|
||||
final isFilterSelected = filter.isSelected(
|
||||
controller.searchController.searchEmailFilter.value,
|
||||
controller.userProfile.value
|
||||
);
|
||||
|
||||
return Padding(
|
||||
@@ -563,35 +565,40 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
||||
screenSize.width - offset.dx,
|
||||
screenSize.height - offset.dy,
|
||||
);
|
||||
controller.openPopupMenuAction(context, position,
|
||||
popupMenuEmailReceiveTimeType(context,
|
||||
controller.searchController.emailReceiveTimeType.value,
|
||||
(receiveTime) => controller.selectReceiveTimeQuickSearchFilter(receiveTime)));
|
||||
controller.openPopupMenuAction(
|
||||
context,
|
||||
position,
|
||||
popupMenuEmailReceiveTimeType(
|
||||
context,
|
||||
controller.searchController.receiveTimeFiltered,
|
||||
onCallBack: (receiveTime) => controller.selectReceiveTimeQuickSearchFilter(context, receiveTime)
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: filter.getBackgroundColor(quickSearchFilterSelected: quickSearchFilterSelected)),
|
||||
color: filter.getBackgroundColor(isFilterSelected: isFilterSelected)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
SvgPicture.asset(
|
||||
filter.getIcon(
|
||||
imagePaths,
|
||||
quickSearchFilterSelected: quickSearchFilterSelected),
|
||||
filter.getIcon(imagePaths, isFilterSelected: isFilterSelected),
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
filter.getTitle(
|
||||
context,
|
||||
receiveTimeType: controller.searchController.emailReceiveTimeType.value),
|
||||
context,
|
||||
receiveTimeType: controller.searchController.receiveTimeFiltered,
|
||||
startDate: controller.searchController.startDateFiltered,
|
||||
endDate: controller.searchController.endDateFiltered
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: filter.getTextStyle(
|
||||
quickSearchFilterSelected: quickSearchFilterSelected),
|
||||
style: filter.getTextStyle(isFilterSelected: isFilterSelected),
|
||||
),
|
||||
if (filter == QuickSearchFilter.last7Days)
|
||||
... [
|
||||
@@ -609,55 +616,21 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
|
||||
}
|
||||
|
||||
List<PopupMenuEntry> popupMenuEmailReceiveTimeType(
|
||||
BuildContext context,
|
||||
EmailReceiveTimeType? receiveTimeSelected,
|
||||
Function(EmailReceiveTimeType?)? onCallBack
|
||||
BuildContext context,
|
||||
EmailReceiveTimeType? receiveTimeSelected,
|
||||
{Function(EmailReceiveTimeType)? onCallBack}
|
||||
) {
|
||||
return EmailReceiveTimeType.values
|
||||
.map((timeType) => PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: _receiveTimeTileAction(
|
||||
context,
|
||||
receiveTimeSelected,
|
||||
timeType,
|
||||
onCallBack)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Widget _receiveTimeTileAction(
|
||||
BuildContext context,
|
||||
EmailReceiveTimeType? receiveTimeSelected,
|
||||
EmailReceiveTimeType receiveTimeType,
|
||||
Function(EmailReceiveTimeType?)? onCallBack
|
||||
) {
|
||||
return InkWell(
|
||||
onTap: () => onCallBack?.call(receiveTimeType == receiveTimeSelected
|
||||
? null
|
||||
: receiveTimeType),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: SizedBox(
|
||||
width: 320,
|
||||
child: Row(children: [
|
||||
Expanded(child: Text(
|
||||
receiveTimeType.getTitle(context),
|
||||
style: const TextStyle(
|
||||
fontSize: 17,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.normal))),
|
||||
if (receiveTimeType == receiveTimeSelected)
|
||||
...[
|
||||
const SizedBox(width: 12),
|
||||
SvgPicture.asset(
|
||||
imagePaths.icFilterSelected,
|
||||
width: 24,
|
||||
height: 24,
|
||||
fit: BoxFit.fill),
|
||||
]
|
||||
])
|
||||
),
|
||||
)
|
||||
);
|
||||
.map((receiveTime) => PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemNoIconWidget(
|
||||
receiveTime.getTitle(context),
|
||||
svgIconSelected: imagePaths.icFilterSelected,
|
||||
maxWidth: 320,
|
||||
isSelected: receiveTimeSelected == receiveTime,
|
||||
onCallbackAction: () => onCallBack?.call(receiveTime),
|
||||
)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
bool supportEmptyTrash(BuildContext context) {
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ enum AdvancedSearchFilterField {
|
||||
case AdvancedSearchFilterField.notKeyword:
|
||||
return AppLocalizations.of(context).enterSearchTerm;
|
||||
case AdvancedSearchFilterField.mailBox:
|
||||
return AppLocalizations.of(context).allMails;
|
||||
return AppLocalizations.of(context).allMailboxes;
|
||||
case AdvancedSearchFilterField.date:
|
||||
return AppLocalizations.of(context).allTime;
|
||||
case AdvancedSearchFilterField.hasAttachment:
|
||||
|
||||
+43
-4
@@ -37,10 +37,8 @@ enum EmailReceiveTimeType {
|
||||
}
|
||||
}
|
||||
|
||||
UTCDate? toUTCDate() {
|
||||
UTCDate? toOldestUTCDate() {
|
||||
switch(this) {
|
||||
case EmailReceiveTimeType.allTime:
|
||||
return null;
|
||||
case EmailReceiveTimeType.last7Days:
|
||||
final today = DateTime.now();
|
||||
final last7Days = today.subtract(const Duration(days: 7));
|
||||
@@ -57,8 +55,49 @@ enum EmailReceiveTimeType {
|
||||
final today = DateTime.now();
|
||||
final lastYear = DateTime(today.year - 1, today.month, today.day);
|
||||
return lastYear.toUTCDate();
|
||||
case EmailReceiveTimeType.customRange:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
UTCDate? toLatestUTCDate() {
|
||||
switch(this) {
|
||||
case EmailReceiveTimeType.last7Days:
|
||||
case EmailReceiveTimeType.last30Days:
|
||||
case EmailReceiveTimeType.last6Months:
|
||||
case EmailReceiveTimeType.lastYear:
|
||||
return DateTime.now().toUTCDate();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
UTCDate? getAfterDate(UTCDate? startDate) {
|
||||
if (startDate != null) {
|
||||
return startDate;
|
||||
} else {
|
||||
return toOldestUTCDate();
|
||||
}
|
||||
}
|
||||
|
||||
UTCDate? getBeforeDate(UTCDate? endDate, UTCDate? loadMoreDate) {
|
||||
if (endDate != null) {
|
||||
if (loadMoreDate != null && loadMoreDate.value.isBefore(endDate.value)) {
|
||||
return loadMoreDate;
|
||||
} else {
|
||||
return endDate;
|
||||
}
|
||||
} else {
|
||||
final latestDate = toLatestUTCDate();
|
||||
if (latestDate != null) {
|
||||
if (loadMoreDate != null && loadMoreDate.value.isBefore(latestDate.value)) {
|
||||
return loadMoreDate;
|
||||
} else {
|
||||
return latestDate;
|
||||
}
|
||||
} else {
|
||||
return loadMoreDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
|
||||
import 'package:core/core.dart';
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:model/user/user_profile.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/search_email_filter.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
enum QuickSearchFilter {
|
||||
@@ -9,22 +12,36 @@ enum QuickSearchFilter {
|
||||
last7Days,
|
||||
fromMe;
|
||||
|
||||
String getTitle(BuildContext context, {EmailReceiveTimeType? receiveTimeType}) {
|
||||
String getName(BuildContext context) {
|
||||
switch(this) {
|
||||
case QuickSearchFilter.hasAttachment:
|
||||
return AppLocalizations.of(context).hasAttachment;
|
||||
case QuickSearchFilter.last7Days:
|
||||
if (receiveTimeType != null) {
|
||||
return receiveTimeType.getTitle(context);
|
||||
}
|
||||
return AppLocalizations.of(context).last7Days;
|
||||
case QuickSearchFilter.fromMe:
|
||||
return AppLocalizations.of(context).fromMe;
|
||||
}
|
||||
}
|
||||
|
||||
String getIcon(ImagePaths imagePaths, {required bool quickSearchFilterSelected}) {
|
||||
if (quickSearchFilterSelected) {
|
||||
String getTitle(
|
||||
BuildContext context, {
|
||||
EmailReceiveTimeType? receiveTimeType,
|
||||
DateTime? startDate,
|
||||
DateTime? endDate,
|
||||
}) {
|
||||
switch(this) {
|
||||
case QuickSearchFilter.hasAttachment:
|
||||
return AppLocalizations.of(context).hasAttachment;
|
||||
case QuickSearchFilter.last7Days:
|
||||
return receiveTimeType?.getTitle(context, startDate: startDate, endDate: endDate)
|
||||
?? AppLocalizations.of(context).allTime;
|
||||
case QuickSearchFilter.fromMe:
|
||||
return AppLocalizations.of(context).fromMe;
|
||||
}
|
||||
}
|
||||
|
||||
String getIcon(ImagePaths imagePaths, {required bool isFilterSelected}) {
|
||||
if (isFilterSelected) {
|
||||
return imagePaths.icSelectedSB;
|
||||
} else {
|
||||
switch(this) {
|
||||
@@ -38,16 +55,16 @@ enum QuickSearchFilter {
|
||||
}
|
||||
}
|
||||
|
||||
Color getBackgroundColor({required bool quickSearchFilterSelected}) {
|
||||
if (quickSearchFilterSelected) {
|
||||
Color getBackgroundColor({required bool isFilterSelected}) {
|
||||
if (isFilterSelected) {
|
||||
return AppColor.colorItemEmailSelectedDesktop;
|
||||
} else {
|
||||
return AppColor.colorButtonHeaderThread;
|
||||
}
|
||||
}
|
||||
|
||||
TextStyle getTextStyle({required bool quickSearchFilterSelected}) {
|
||||
if (quickSearchFilterSelected) {
|
||||
TextStyle getTextStyle({required bool isFilterSelected}) {
|
||||
if (isFilterSelected) {
|
||||
return const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -59,4 +76,19 @@ enum QuickSearchFilter {
|
||||
color: AppColor.colorTextButtonHeaderThread);
|
||||
}
|
||||
}
|
||||
|
||||
bool isApplied(List<QuickSearchFilter> listFilter) => listFilter.contains(this);
|
||||
|
||||
bool isSelected(SearchEmailFilter filter, UserProfile? userProfile) {
|
||||
switch (this) {
|
||||
case QuickSearchFilter.hasAttachment:
|
||||
return filter.hasAttachment == true;
|
||||
case QuickSearchFilter.last7Days:
|
||||
return true;
|
||||
case QuickSearchFilter.fromMe:
|
||||
return userProfile != null &&
|
||||
filter.from.contains(userProfile.email) &&
|
||||
filter.from.length == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,8 @@ import 'package:jmap_dart_client/jmap/core/filter/filter_operator.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/filter/operator/logic_filter_operator.dart';
|
||||
import 'package:jmap_dart_client/jmap/core/utc_date.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/email/email_filter_condition.dart';
|
||||
import 'package:model/model.dart';
|
||||
import 'package:model/extensions/email_filter_condition_extension.dart';
|
||||
import 'package:model/mailbox/presentation_mailbox.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
||||
import 'package:tmail_ui_user/features/thread/domain/model/search_query.dart';
|
||||
|
||||
@@ -52,9 +53,9 @@ class SearchEmailFilter with EquatableMixin {
|
||||
PresentationMailbox? mailbox,
|
||||
EmailReceiveTimeType? emailReceiveTimeType,
|
||||
bool? hasAttachment,
|
||||
UTCDate? before,
|
||||
UTCDate? startDate,
|
||||
UTCDate? endDate,
|
||||
Option<UTCDate>? beforeOption,
|
||||
Option<UTCDate>? startDateOption,
|
||||
Option<UTCDate>? endDateOption,
|
||||
}) {
|
||||
return SearchEmailFilter(
|
||||
from: from ?? this.from,
|
||||
@@ -65,9 +66,9 @@ class SearchEmailFilter with EquatableMixin {
|
||||
mailbox: mailbox ?? this.mailbox,
|
||||
emailReceiveTimeType: emailReceiveTimeType ?? this.emailReceiveTimeType,
|
||||
hasAttachment: hasAttachment ?? this.hasAttachment,
|
||||
before: before ?? this.before,
|
||||
startDate: startDate ?? this.startDate,
|
||||
endDate: endDate ?? this.endDate,
|
||||
before: _getOptionParam(beforeOption, before),
|
||||
startDate: _getOptionParam(startDateOption, startDate),
|
||||
endDate: _getOptionParam(endDateOption, endDate),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,17 +85,13 @@ class SearchEmailFilter with EquatableMixin {
|
||||
text: text?.value.trim().isNotEmpty == true
|
||||
? text?.value
|
||||
: null,
|
||||
inMailbox: mailbox == PresentationMailbox.unifiedMailbox
|
||||
? null
|
||||
: mailbox?.id,
|
||||
after: emailReceiveTimeType == EmailReceiveTimeType.customRange
|
||||
? startDate
|
||||
: emailReceiveTimeType.toUTCDate(),
|
||||
inMailbox: mailbox?.mailboxId,
|
||||
after: emailReceiveTimeType.getAfterDate(startDate),
|
||||
hasAttachment: hasAttachment == false ? null : hasAttachment,
|
||||
subject: subject,
|
||||
before: emailReceiveTimeType == EmailReceiveTimeType.customRange
|
||||
? endDate
|
||||
: before,
|
||||
subject: subject?.trim().isNotEmpty == true
|
||||
? subject
|
||||
: null,
|
||||
before: emailReceiveTimeType.getBeforeDate(endDate, before)
|
||||
);
|
||||
|
||||
final listEmailCondition = {
|
||||
@@ -135,39 +132,4 @@ class SearchEmailFilter with EquatableMixin {
|
||||
startDate,
|
||||
endDate
|
||||
];
|
||||
}
|
||||
|
||||
extension SearchEmailFilterExtension on SearchEmailFilter {
|
||||
|
||||
SearchEmailFilter clearBeforeDate() {
|
||||
return SearchEmailFilter(
|
||||
from: from,
|
||||
to: to,
|
||||
text: text,
|
||||
subject: subject,
|
||||
notKeyword: notKeyword,
|
||||
mailbox: mailbox,
|
||||
emailReceiveTimeType: emailReceiveTimeType,
|
||||
hasAttachment: hasAttachment,
|
||||
before: null,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
);
|
||||
}
|
||||
|
||||
SearchEmailFilter withDateRange({UTCDate? startDate, UTCDate? endDate}) {
|
||||
return SearchEmailFilter(
|
||||
from: from,
|
||||
to: to,
|
||||
text: text,
|
||||
subject: subject,
|
||||
notKeyword: notKeyword,
|
||||
mailbox: mailbox,
|
||||
emailReceiveTimeType: emailReceiveTimeType,
|
||||
hasAttachment: hasAttachment,
|
||||
before: before,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
);
|
||||
}
|
||||
}
|
||||
+29
-47
@@ -4,11 +4,12 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
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/mailbox_dashboard/presentation/model/search/email_receive_time_type.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/drop_down_button_filter_widget.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/date_drop_down_button.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/advanced_search/text_field_auto_complete_email_adress.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
@@ -73,7 +74,6 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
onTap: () => controller.selectedMailBox(context)),
|
||||
Row(children: [
|
||||
Expanded(child: _buildFilterField(
|
||||
textEditingController: controller.dateFilterInputController,
|
||||
context: context,
|
||||
advancedSearchFilterField: AdvancedSearchFilterField.date,
|
||||
isSelectFormList: true,
|
||||
@@ -102,52 +102,22 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
|
||||
List<Widget> _buildEmailReceiveTimeTypeActionTiles(BuildContext context) {
|
||||
return EmailReceiveTimeType.values
|
||||
.map(
|
||||
(e) => Material(
|
||||
child: PopupMenuItem(
|
||||
child: Row(children: [
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
e.getTitle(
|
||||
context,
|
||||
startDate: controller.startDate,
|
||||
endDate: controller.endDate),
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500))),
|
||||
if (e == controller.dateFilterSelectedFormAdvancedSearch.value)
|
||||
...[
|
||||
const SizedBox(width: 12),
|
||||
SvgPicture.asset(
|
||||
_imagePaths.icFilterSelected,
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
]
|
||||
]),
|
||||
onTap: () {
|
||||
if (e != EmailReceiveTimeType.customRange) {
|
||||
controller.clearDateRangeOfFilter();
|
||||
}
|
||||
controller.dateFilterSelectedFormAdvancedSearch.value = e;
|
||||
controller.dateFilterInputController.text = e.getTitle(
|
||||
context,
|
||||
startDate: controller.startDate,
|
||||
endDate: controller.endDate);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
.map((receiveTime) => PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemNoIconWidget(
|
||||
receiveTime.getTitle(context),
|
||||
svgIconSelected: _imagePaths.icFilterSelected,
|
||||
maxWidth: 320,
|
||||
isSelected: controller.dateFilterSelectedFormAdvancedSearch.value == receiveTime,
|
||||
onCallbackAction: () => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
||||
)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Widget _buildFilterField({
|
||||
required BuildContext context,
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required TextEditingController textEditingController,
|
||||
TextEditingController? textEditingController,
|
||||
VoidCallback? onTap,
|
||||
bool isSelectFormList = false,
|
||||
MouseCursor? mouseCursor,
|
||||
@@ -180,7 +150,13 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
)
|
||||
else if (_responsiveUtils.landscapeTabletSupported(context))
|
||||
if (advancedSearchFilterField == AdvancedSearchFilterField.date)
|
||||
const DateDropDownButton()
|
||||
Obx(() => DateDropDownButton(
|
||||
_imagePaths,
|
||||
startDate: controller.startDate.value,
|
||||
endDate: controller.endDate.value,
|
||||
receiveTimeSelected: controller.dateFilterSelectedFormAdvancedSearch.value,
|
||||
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
||||
))
|
||||
else
|
||||
_buildTextField(
|
||||
isSelectFormList: isSelectFormList,
|
||||
@@ -222,7 +198,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
Widget _buildTextFieldFilterForWeb({
|
||||
required BuildContext context,
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required TextEditingController textEditingController,
|
||||
TextEditingController? textEditingController,
|
||||
VoidCallback? onTap,
|
||||
bool isSelectFormList = false,
|
||||
MouseCursor? mouseCursor,
|
||||
@@ -231,7 +207,13 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
}) {
|
||||
switch (advancedSearchFilterField) {
|
||||
case AdvancedSearchFilterField.date:
|
||||
return const DateDropDownButton();
|
||||
return Obx(() => DateDropDownButton(
|
||||
_imagePaths,
|
||||
startDate: controller.startDate.value,
|
||||
endDate: controller.endDate.value,
|
||||
receiveTimeSelected: controller.dateFilterSelectedFormAdvancedSearch.value,
|
||||
onReceiveTimeSelected: (receiveTime) => controller.updateReceiveDateSearchFilter(context, receiveTime),
|
||||
));
|
||||
default:
|
||||
return _buildTextField(
|
||||
isSelectFormList: isSelectFormList,
|
||||
@@ -357,7 +339,7 @@ class AdvancedSearchInputForm extends GetWidget<AdvancedFilterController>
|
||||
Widget _buildTextField({
|
||||
required BuildContext context,
|
||||
required AdvancedSearchFilterField advancedSearchFilterField,
|
||||
required TextEditingController textEditingController,
|
||||
TextEditingController? textEditingController,
|
||||
VoidCallback? onTap,
|
||||
bool isSelectFormList = false,
|
||||
MouseCursor? mouseCursor,
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/utils/style_utils.dart';
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:pointer_interceptor/pointer_interceptor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
||||
|
||||
class DateDropDownButton extends StatelessWidget {
|
||||
|
||||
final ImagePaths imagePaths;
|
||||
final DateTime? startDate;
|
||||
final DateTime? endDate;
|
||||
final EmailReceiveTimeType? receiveTimeSelected;
|
||||
final Function(EmailReceiveTimeType)? onReceiveTimeSelected;
|
||||
|
||||
const DateDropDownButton(
|
||||
this.imagePaths, {
|
||||
Key? key,
|
||||
this.startDate,
|
||||
this.endDate,
|
||||
this.receiveTimeSelected,
|
||||
this.onReceiveTimeSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownButtonHideUnderline(
|
||||
child: PointerInterceptor(
|
||||
child: DropdownButton2<EmailReceiveTimeType>(
|
||||
isExpanded: true,
|
||||
items: EmailReceiveTimeType.values
|
||||
.map((item) => _buildItemMenu(context, item))
|
||||
.toList(),
|
||||
value: receiveTimeSelected,
|
||||
customButton: Container(
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: AppColor.colorInputBorderCreateMailbox,
|
||||
width: 1,
|
||||
),
|
||||
color: AppColor.colorInputBackgroundCreateMailbox
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 12, right: 10),
|
||||
child: Row(children: [
|
||||
Expanded(child: Text(
|
||||
receiveTimeSelected?.getTitle(context, startDate: startDate, endDate: endDate) ?? '',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Colors.black
|
||||
),
|
||||
maxLines: 1,
|
||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
)),
|
||||
SvgPicture.asset(imagePaths.icDropDown)
|
||||
]),
|
||||
),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onReceiveTimeSelected?.call(value);
|
||||
}
|
||||
},
|
||||
icon: SvgPicture.asset(imagePaths.icDropDown),
|
||||
buttonPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
buttonDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: AppColor.colorInputBorderCreateMailbox,
|
||||
width: 1,
|
||||
),
|
||||
color: AppColor.colorInputBackgroundCreateMailbox,
|
||||
),
|
||||
itemHeight: 44,
|
||||
buttonHeight: 44,
|
||||
selectedItemHighlightColor: Colors.white,
|
||||
itemPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
dropdownMaxHeight: 200,
|
||||
dropdownDecoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Colors.white,
|
||||
),
|
||||
offset: const Offset(0.0, -8.0),
|
||||
dropdownElevation: 4,
|
||||
scrollbarRadius: const Radius.circular(40),
|
||||
scrollbarThickness: 6
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
DropdownMenuItem<EmailReceiveTimeType> _buildItemMenu(
|
||||
BuildContext context,
|
||||
EmailReceiveTimeType receiveTime
|
||||
) {
|
||||
return DropdownMenuItem<EmailReceiveTimeType>(
|
||||
value: receiveTime,
|
||||
child: PointerInterceptor(
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
height: 44,
|
||||
child: Row(children: [
|
||||
Expanded(child: Text(
|
||||
receiveTime.getTitle(context),
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Colors.black
|
||||
),
|
||||
maxLines: 1,
|
||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
)),
|
||||
if (receiveTime == receiveTimeSelected)
|
||||
SvgPicture.asset(
|
||||
imagePaths.icChecked,
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.fill
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,7 @@
|
||||
import 'package:core/presentation/extensions/color_extension.dart';
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
import 'package:core/presentation/views/button/icon_button_web.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -34,9 +35,8 @@ class IconOpenAdvancedSearchWidget extends StatelessWidget {
|
||||
width: 16,
|
||||
height: 16),
|
||||
onTap: () {
|
||||
if(searchController.isAdvancedSearchViewOpen.isFalse && searchController.advancedSearchIsActivated.isFalse){
|
||||
advancedFilterController.initSearchFilterField(context);
|
||||
}
|
||||
log('IconOpenAdvancedSearchWidget::build(): clicked');
|
||||
advancedFilterController.initSearchFilterField(context);
|
||||
searchController.showAdvancedFilterView(_parentContext);
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -128,10 +128,7 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin {
|
||||
},
|
||||
buttonActionCallback: (filterAction) {
|
||||
if (filterAction is QuickSearchFilter) {
|
||||
dashBoardController.selectQuickSearchFilter(
|
||||
quickSearchFilter: filterAction,
|
||||
fromSuggestionBox: true,
|
||||
);
|
||||
dashBoardController.addFilterToSuggestionForm(filterAction);
|
||||
}
|
||||
},
|
||||
listActionPadding: const EdgeInsets.only(
|
||||
@@ -210,43 +207,31 @@ class SearchInputFormWidget extends StatelessWidget with AppLoaderMixin {
|
||||
}
|
||||
|
||||
Widget buildListButtonForQuickSearchForm(BuildContext context, QuickSearchFilter filter) {
|
||||
final controller = dashBoardController.searchController;
|
||||
|
||||
return Obx(() {
|
||||
final isFilterSelected = dashBoardController.checkQuickSearchFilterSelected(
|
||||
quickSearchFilter: filter);
|
||||
final isFilterSelected = filter.isApplied(dashBoardController.searchController.listFilterOnSuggestionForm);
|
||||
|
||||
return Chip(
|
||||
labelPadding: const EdgeInsets.only(
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
right: 10),
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
right: 10),
|
||||
label: Text(
|
||||
filter.getTitle(
|
||||
context,
|
||||
receiveTimeType: controller.emailReceiveTimeType.value),
|
||||
filter.getName(context),
|
||||
maxLines: 1,
|
||||
overflow: CommonTextStyle.defaultTextOverFlow,
|
||||
softWrap: CommonTextStyle.defaultSoftWrap,
|
||||
style: filter.getTextStyle(
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
style: filter.getTextStyle(isFilterSelected: isFilterSelected),
|
||||
),
|
||||
avatar: SvgPicture.asset(
|
||||
filter.getIcon(
|
||||
imagePaths,
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill),
|
||||
labelStyle: filter.getTextStyle(
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
backgroundColor: filter.getBackgroundColor(
|
||||
quickSearchFilterSelected: isFilterSelected),
|
||||
filter.getIcon(imagePaths, isFilterSelected: isFilterSelected),
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.fill),
|
||||
labelStyle: filter.getTextStyle(isFilterSelected: isFilterSelected),
|
||||
backgroundColor: filter.getBackgroundColor(isFilterSelected: isFilterSelected),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
side: BorderSide(
|
||||
color: filter.getBackgroundColor(
|
||||
quickSearchFilterSelected: isFilterSelected)),
|
||||
side: BorderSide(color: filter.getBackgroundColor(isFilterSelected: isFilterSelected)),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -151,6 +151,7 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
newState.fold(
|
||||
(failure) {
|
||||
if (failure is SearchEmailFailure) {
|
||||
canSearchMore = false;
|
||||
mailboxDashBoardController.emailsInCurrentMailbox.clear();
|
||||
} else if (failure is SearchMoreEmailFailure || failure is LoadMoreEmailsFailure) {
|
||||
_isLoadingMore = false;
|
||||
@@ -197,7 +198,7 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
if (_currentMailboxId != mailbox.id) {
|
||||
_currentMailboxId = mailbox.id;
|
||||
_resetToOriginalValue();
|
||||
_getAllEmail();
|
||||
_getAllEmailAction();
|
||||
}
|
||||
} else if (mailbox == null) { // disable current mailbox when search active
|
||||
_currentMailboxId = null;
|
||||
@@ -262,6 +263,12 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
_navigationRouter = action.navigationRouter;
|
||||
_activateSearchFromRouter();
|
||||
mailboxDashBoardController.clearDashBoardAction();
|
||||
} else if (action is SelectDateRangeToAdvancedSearch || action is ClearDateRangeToAdvancedSearch) {
|
||||
if (listEmailController.hasClients) {
|
||||
listEmailController.jumpTo(0);
|
||||
}
|
||||
canSearchMore = true;
|
||||
mailboxDashBoardController.emailsInCurrentMailbox.clear();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -335,18 +342,12 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
logError('ThreadController::_handleErrorGetAllOrRefreshChangesEmail():Error: $error');
|
||||
if (error is CannotCalculateChangesMethodResponseException) {
|
||||
await _cachingManager.clearEmailCache();
|
||||
_getAllEmail();
|
||||
_getAllEmailAction();
|
||||
} else {
|
||||
super.onError(error);
|
||||
}
|
||||
}
|
||||
|
||||
void _getAllEmail() {
|
||||
if (_accountId != null) {
|
||||
_getAllEmailAction(_accountId!, mailboxId: _currentMailboxId);
|
||||
}
|
||||
}
|
||||
|
||||
void _resetToOriginalValue() {
|
||||
dispatchState(Right(LoadingState()));
|
||||
mailboxDashBoardController.emailsInCurrentMailbox.clear();
|
||||
@@ -389,48 +390,47 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
}
|
||||
}
|
||||
|
||||
void _getAllEmailAction(AccountId accountId, {MailboxId? mailboxId}) {
|
||||
consumeState(_getEmailsInMailboxInteractor.execute(
|
||||
accountId,
|
||||
limit: ThreadConstants.defaultLimit,
|
||||
sort: _sortOrder,
|
||||
emailFilter: EmailFilter(
|
||||
filter: _getFilterCondition(),
|
||||
filterOption: mailboxDashBoardController.filterMessageOption.value,
|
||||
mailboxId: mailboxId ?? _currentMailboxId),
|
||||
propertiesCreated: ThreadConstants.propertiesDefault,
|
||||
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
|
||||
));
|
||||
void _getAllEmailAction() {
|
||||
if (_accountId != null) {
|
||||
consumeState(_getEmailsInMailboxInteractor.execute(
|
||||
_accountId!,
|
||||
limit: ThreadConstants.defaultLimit,
|
||||
sort: _sortOrder,
|
||||
emailFilter: EmailFilter(
|
||||
filter: _getFilterCondition(mailboxIdSelected: _currentMailboxId),
|
||||
filterOption: mailboxDashBoardController.filterMessageOption.value,
|
||||
mailboxId: _currentMailboxId
|
||||
),
|
||||
propertiesCreated: ThreadConstants.propertiesDefault,
|
||||
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
EmailFilterCondition _getFilterCondition({bool isLoadMore = false}) {
|
||||
final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
|
||||
? mailboxDashBoardController.emailsInCurrentMailbox.last
|
||||
: null;
|
||||
final mailboxIdSelected = mailboxDashBoardController.selectedMailbox.value?.id;
|
||||
EmailFilterCondition _getFilterCondition({PresentationEmail? oldestEmail, MailboxId? mailboxIdSelected}) {
|
||||
switch(mailboxDashBoardController.filterMessageOption.value) {
|
||||
case FilterMessageOption.all:
|
||||
return EmailFilterCondition(
|
||||
inMailbox: mailboxIdSelected,
|
||||
before: isLoadMore ? lastEmail?.receivedAt : null
|
||||
before: oldestEmail?.receivedAt
|
||||
);
|
||||
case FilterMessageOption.unread:
|
||||
return EmailFilterCondition(
|
||||
inMailbox: mailboxIdSelected,
|
||||
notKeyword: KeyWordIdentifier.emailSeen.value,
|
||||
before: isLoadMore ? lastEmail?.receivedAt : null
|
||||
before: oldestEmail?.receivedAt
|
||||
);
|
||||
case FilterMessageOption.attachments:
|
||||
return EmailFilterCondition(
|
||||
inMailbox: mailboxIdSelected,
|
||||
hasAttachment: true,
|
||||
before: isLoadMore ? lastEmail?.receivedAt : null
|
||||
before: oldestEmail?.receivedAt
|
||||
);
|
||||
case FilterMessageOption.starred:
|
||||
return EmailFilterCondition(
|
||||
inMailbox: mailboxIdSelected,
|
||||
hasKeyword: KeyWordIdentifier.emailFlagged.value,
|
||||
before: isLoadMore ? lastEmail?.receivedAt : null
|
||||
before: oldestEmail?.receivedAt
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -441,10 +441,9 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
cancelSelectEmail();
|
||||
|
||||
if (searchController.isSearchEmailRunning) {
|
||||
searchController.searchEmailFilter.value = _searchEmailFilter.clearBeforeDate();
|
||||
_searchEmail(limit: limitEmailFetched);
|
||||
} else {
|
||||
_getAllEmail();
|
||||
_getAllEmailAction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,22 +458,22 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
void _refreshEmailChanges({jmap.State? currentEmailState}) {
|
||||
log('ThreadController::_refreshEmailChanges(): currentEmailState: $currentEmailState');
|
||||
if (searchController.isSearchEmailRunning) {
|
||||
searchController.searchEmailFilter.value = _searchEmailFilter.clearBeforeDate();
|
||||
_searchEmail(limit: limitEmailFetched);
|
||||
} else {
|
||||
final newEmailState = currentEmailState ?? _currentEmailState;
|
||||
log('ThreadController::_refreshEmailChanges(): newEmailState: $newEmailState');
|
||||
if (_accountId != null && newEmailState != null) {
|
||||
consumeState(_refreshChangesEmailsInMailboxInteractor.execute(
|
||||
_accountId!,
|
||||
newEmailState,
|
||||
sort: _sortOrder,
|
||||
propertiesCreated: ThreadConstants.propertiesDefault,
|
||||
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
|
||||
emailFilter: EmailFilter(
|
||||
filter: _getFilterCondition(),
|
||||
filterOption: mailboxDashBoardController.filterMessageOption.value,
|
||||
mailboxId: _currentMailboxId),
|
||||
_accountId!,
|
||||
newEmailState,
|
||||
sort: _sortOrder,
|
||||
propertiesCreated: ThreadConstants.propertiesDefault,
|
||||
propertiesUpdated: ThreadConstants.propertiesUpdatedDefault,
|
||||
emailFilter: EmailFilter(
|
||||
filter: _getFilterCondition(mailboxIdSelected: _currentMailboxId),
|
||||
filterOption: mailboxDashBoardController.filterMessageOption.value,
|
||||
mailboxId: _currentMailboxId
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -483,15 +482,19 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
void loadMoreEmails() {
|
||||
log('ThreadController::loadMoreEmails()');
|
||||
if (canLoadMore && _accountId != null) {
|
||||
final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
|
||||
? mailboxDashBoardController.emailsInCurrentMailbox.last
|
||||
: null;
|
||||
consumeState(_loadMoreEmailsInMailboxInteractor.execute(
|
||||
GetEmailRequest(
|
||||
_accountId!,
|
||||
limit: ThreadConstants.defaultLimit,
|
||||
sort: _sortOrder,
|
||||
filterOption: mailboxDashBoardController.filterMessageOption.value,
|
||||
filter: _getFilterCondition(isLoadMore: true),
|
||||
properties: ThreadConstants.propertiesDefault,
|
||||
lastEmailId: mailboxDashBoardController.emailsInCurrentMailbox.last.id)
|
||||
_accountId!,
|
||||
limit: ThreadConstants.defaultLimit,
|
||||
sort: _sortOrder,
|
||||
filterOption: mailboxDashBoardController.filterMessageOption.value,
|
||||
filter: _getFilterCondition(oldestEmail: oldestEmail),
|
||||
properties: ThreadConstants.propertiesDefault,
|
||||
lastEmailId: oldestEmail?.id
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -649,7 +652,7 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
icon: newFilterOption.getIconToast(_imagePaths));
|
||||
|
||||
if (searchController.isSearchEmailRunning) {
|
||||
_searchEmail(filterCondition: _getFilterCondition());
|
||||
_searchEmail();
|
||||
} else {
|
||||
refreshAllEmail();
|
||||
}
|
||||
@@ -664,21 +667,22 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
searchController.clearTextSearch();
|
||||
}
|
||||
|
||||
void _searchEmail({UnsignedInt? limit, EmailFilterCondition? filterCondition}) {
|
||||
void _searchEmail({UnsignedInt? limit}) {
|
||||
if (_accountId != null) {
|
||||
searchController.activateSimpleSearch();
|
||||
if (listEmailController.hasClients) {
|
||||
listEmailController.jumpTo(0);
|
||||
}
|
||||
mailboxDashBoardController.emailsInCurrentMailbox.clear();
|
||||
canSearchMore = true;
|
||||
searchController.updateFilterEmail(beforeOption: const None());
|
||||
|
||||
filterCondition = EmailFilterCondition(
|
||||
notKeyword: filterCondition?.notKeyword,
|
||||
hasKeyword: filterCondition?.hasKeyword,
|
||||
hasAttachment: filterCondition?.hasAttachment,
|
||||
);
|
||||
searchController.activateSimpleSearch();
|
||||
|
||||
consumeState(_searchEmailInteractor.execute(
|
||||
_accountId!,
|
||||
limit: limit ?? ThreadConstants.defaultLimit,
|
||||
sort: _sortOrder,
|
||||
filter: _searchEmailFilter.mappingToEmailFilterCondition(moreFilterCondition: filterCondition),
|
||||
filter: _searchEmailFilter.mappingToEmailFilterCondition(moreFilterCondition: _getFilterCondition()),
|
||||
properties: ThreadConstants.propertiesDefault,
|
||||
));
|
||||
}
|
||||
@@ -697,6 +701,7 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
}
|
||||
|
||||
void _searchEmailsSuccess(SearchEmailSuccess success) {
|
||||
canSearchMore = true;
|
||||
final resultEmailSearchList = success.emailList
|
||||
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
|
||||
.toList();
|
||||
@@ -716,21 +721,24 @@ class ThreadController extends BaseController with EmailActionController {
|
||||
|
||||
void searchMoreEmails() {
|
||||
if (canSearchMore && _accountId != null) {
|
||||
final lastEmail = mailboxDashBoardController.emailsInCurrentMailbox.last;
|
||||
searchController.updateFilterEmail(before: lastEmail.receivedAt);
|
||||
final oldestEmail = mailboxDashBoardController.emailsInCurrentMailbox.isNotEmpty
|
||||
? mailboxDashBoardController.emailsInCurrentMailbox.last
|
||||
: null;
|
||||
searchController.updateFilterEmail(beforeOption: optionOf(oldestEmail?.receivedAt));
|
||||
consumeState(_searchMoreEmailInteractor.execute(
|
||||
_accountId!,
|
||||
limit: ThreadConstants.defaultLimit,
|
||||
sort: _sortOrder,
|
||||
filter: searchController.searchEmailFilter.value.mappingToEmailFilterCondition(),
|
||||
filter: searchController.searchEmailFilter.value.mappingToEmailFilterCondition(moreFilterCondition: _getFilterCondition()),
|
||||
properties: ThreadConstants.propertiesDefault,
|
||||
lastEmailId: lastEmail.id
|
||||
lastEmailId: oldestEmail?.id
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _searchMoreEmailsSuccess(SearchMoreEmailSuccess success) {
|
||||
if (success.emailList.isNotEmpty) {
|
||||
canSearchMore = true;
|
||||
final resultEmailSearchList = success.emailList
|
||||
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailboxById))
|
||||
.where((email) => !mailboxDashBoardController.emailsInCurrentMailbox.contains(email))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"@@last_modified": "2023-02-24T11:57:26.810965",
|
||||
"@@last_modified": "2023-03-02T21:08:14.879842",
|
||||
"initializing_data": "Initializing data...",
|
||||
"@initializing_data": {
|
||||
"type": "text",
|
||||
@@ -1488,12 +1488,6 @@
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"allMails": "All mails",
|
||||
"@allMails": {
|
||||
"type": "text",
|
||||
"placeholders_order": [],
|
||||
"placeholders": {}
|
||||
},
|
||||
"allTime": "All time",
|
||||
"@allTime": {
|
||||
"type": "text",
|
||||
|
||||
@@ -1515,13 +1515,6 @@ class AppLocalizations {
|
||||
);
|
||||
}
|
||||
|
||||
String get allMails {
|
||||
return Intl.message(
|
||||
'All mails',
|
||||
name: 'allMails',
|
||||
);
|
||||
}
|
||||
|
||||
String get allTime {
|
||||
return Intl.message(
|
||||
'All time',
|
||||
|
||||
@@ -107,6 +107,14 @@ class PresentationMailbox with EquatableMixin {
|
||||
|
||||
bool get allowedToDisplay => isSubscribedMailbox || isDefault;
|
||||
|
||||
MailboxId? get mailboxId {
|
||||
if (id == unifiedMailbox.id) {
|
||||
return null;
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
|
||||
Reference in New Issue
Block a user