TF-3002 [WEB] Add To/Folder search filters

This commit is contained in:
dab246
2024-09-12 19:31:38 +07:00
committed by Dat H. Pham
parent 34c9c0cd0e
commit 8290025c14
24 changed files with 461 additions and 228 deletions
@@ -251,19 +251,18 @@ class EmailView extends GetWidget<SingleEmailController> {
); );
} }
EdgeInsetsGeometry _getMarginEmailView(BuildContext context) { EdgeInsetsGeometry? _getMarginEmailView(BuildContext context) {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
if (controller.responsiveUtils.isDesktop(context)) { if (controller.responsiveUtils.isDesktop(context)) {
return const EdgeInsetsDirectional.only( return const EdgeInsetsDirectional.only(
end: 16, end: 16,
top: 8,
bottom: 16 bottom: 16
); );
} else { } else {
return const EdgeInsets.symmetric(vertical: 16); return const EdgeInsets.symmetric(vertical: 16);
} }
} else { } else {
return EdgeInsets.zero; return null;
} }
} }
@@ -118,7 +118,7 @@ class AdvancedFilterController extends BaseController {
searchController.updateFilterEmail(sortOrderOption: searchController.sortOrderFiltered.value.getSortOrder()); searchController.updateFilterEmail(sortOrderOption: searchController.sortOrderFiltered.value.getSortOrder());
searchController.updateFilterEmail( searchController.updateFilterEmail(
mailbox: _destinationMailboxSelected, mailboxOption: optionOf(_destinationMailboxSelected),
subjectOption: optionOf(subjectFilterInputController.text), subjectOption: optionOf(subjectFilterInputController.text),
emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value, emailReceiveTimeType: dateFilterSelectedFormAdvancedSearch.value,
hasAttachment: hasAttachment.value, hasAttachment: hasAttachment.value,
@@ -397,8 +397,17 @@ class AdvancedFilterController extends BaseController {
); );
} else if (action is ClearDateRangeToAdvancedSearch) { } else if (action is ClearDateRangeToAdvancedSearch) {
_updateDateRangeTime(action.receiveTime); _updateDateRangeTime(action.receiveTime);
} else if (action is StartSearchEmailAction && action.filter == QuickSearchFilter.from) { } else if (action is StartSearchEmailAction) {
_updateFromField(); switch(action.filter) {
case QuickSearchFilter.from:
_updateFromField();
break;
case QuickSearchFilter.to:
_updateToField();
break;
default:
break;
}
} else if (action is SearchEmailByFromFieldsAction) { } else if (action is SearchEmailByFromFieldsAction) {
searchController.clearSearchFilter(); searchController.clearSearchFilter();
_resetAllToOriginalValue(); _resetAllToOriginalValue();
@@ -437,8 +446,13 @@ class AdvancedFilterController extends BaseController {
} }
void _updateFromField() { void _updateFromField() {
final listEmailAddress = searchEmailFilter.from.map((address) => EmailAddress(null, address)).toList(); listFromEmailAddress = List.from(
listFromEmailAddress = List.from(listEmailAddress); searchEmailFilter.from.map((address) => EmailAddress(null, address)));
}
void _updateToField() {
listToEmailAddress= List.from(
searchEmailFilter.to.map((address) => EmailAddress(null, address)));
} }
void onSearchAction(BuildContext context) { void onSearchAction(BuildContext context) {
@@ -240,6 +240,7 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo
PresentationMailbox? outboxMailbox; PresentationMailbox? outboxMailbox;
ComposerArguments? composerArguments; ComposerArguments? composerArguments;
List<Identity>? _identities; List<Identity>? _identities;
ScrollController? listSearchFilterScrollController;
late StreamSubscription _emailAddressStreamSubscription; late StreamSubscription _emailAddressStreamSubscription;
late StreamSubscription _emailContentStreamSubscription; late StreamSubscription _emailContentStreamSubscription;
@@ -297,6 +298,9 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo
@override @override
void onReady() { void onReady() {
if (PlatformInfo.isWeb) {
listSearchFilterScrollController = ScrollController();
}
_registerPendingEmailAddress(); _registerPendingEmailAddress();
_registerPendingEmailContents(); _registerPendingEmailContents();
_registerPendingFileInfo(); _registerPendingFileInfo();
@@ -1679,6 +1683,60 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo
} }
} }
Future<void> selectToSearchFilter() async {
if (accountId.value == null || sessionCurrent == null) return;
final contactArgument = ContactArguments(
accountId.value!,
sessionCurrent!,
searchController.searchEmailFilter.value.to);
final newContact = await DialogRouter.pushGeneralDialog(
routeName: AppRoutes.contact,
arguments: contactArgument);
if (newContact is EmailAddress) {
searchController.updateFilterEmail(toOption: Some({newContact.emailAddress}));
dispatchAction(StartSearchEmailAction(filter: QuickSearchFilter.to));
}
}
Future<void> selectFolderSearchFilter() async {
if (accountId.value == null || sessionCurrent == null) return;
final mailboxIdSelected = searchController.mailboxFiltered?.id;
final destinationArgument = DestinationPickerArguments(
accountId.value!,
MailboxActions.select,
sessionCurrent!,
mailboxIdSelected: mailboxIdSelected);
final destinationMailbox = PlatformInfo.isWeb
? await DialogRouter.pushGeneralDialog(
routeName: AppRoutes.destinationPicker,
arguments: destinationArgument)
: await push(
AppRoutes.destinationPicker,
arguments: destinationArgument);
if (destinationMailbox is! PresentationMailbox) return;
if (destinationMailbox != PresentationMailbox.unifiedMailbox &&
mailboxIdSelected != destinationMailbox.id) {
searchController.updateFilterEmail(
mailboxOption: Some(destinationMailbox),
beforeOption: const None(),
positionOption: searchController.sortOrderFiltered.value.isScrollByPosition()
? const Some(0)
: const None()
);
dispatchAction(StartSearchEmailAction(filter: QuickSearchFilter.folder));
}
}
void selectReceiveTimeQuickSearchFilter(BuildContext context, EmailReceiveTimeType receiveTime) { void selectReceiveTimeQuickSearchFilter(BuildContext context, EmailReceiveTimeType receiveTime) {
log('MailboxDashBoardController::selectReceiveTimeQuickSearchFilter():receiveTime: $receiveTime'); log('MailboxDashBoardController::selectReceiveTimeQuickSearchFilter():receiveTime: $receiveTime');
popBack(); popBack();
@@ -2694,6 +2752,9 @@ class MailboxDashBoardController extends ReloadableController with UserSettingPo
@override @override
void onClose() { void onClose() {
if (PlatformInfo.isWeb) {
listSearchFilterScrollController?.dispose();
}
_emailReceiveManager.closeEmailReceiveManagerStream(); _emailReceiveManager.closeEmailReceiveManagerStream();
if (PlatformInfo.isIOS) { if (PlatformInfo.isIOS) {
_iosNotificationManager?.dispose(); _iosNotificationManager?.dispose();
@@ -158,7 +158,7 @@ class SearchController extends BaseController with DateRangePickerMixin {
SearchQuery? text, SearchQuery? text,
Option<String>? subjectOption, Option<String>? subjectOption,
Set<String>? notKeyword, Set<String>? notKeyword,
PresentationMailbox? mailbox, Option<PresentationMailbox>? mailboxOption,
EmailReceiveTimeType? emailReceiveTimeType, EmailReceiveTimeType? emailReceiveTimeType,
bool? hasAttachment, bool? hasAttachment,
Option<UTCDate>? beforeOption, Option<UTCDate>? beforeOption,
@@ -173,7 +173,7 @@ class SearchController extends BaseController with DateRangePickerMixin {
text: text, text: text,
subjectOption: subjectOption, subjectOption: subjectOption,
notKeyword: notKeyword, notKeyword: notKeyword,
mailbox: mailbox, mailboxOption: mailboxOption,
emailReceiveTimeType: emailReceiveTimeType, emailReceiveTimeType: emailReceiveTimeType,
hasAttachment: hasAttachment, hasAttachment: hasAttachment,
beforeOption: beforeOption, beforeOption: beforeOption,
@@ -191,6 +191,8 @@ class SearchController extends BaseController with DateRangePickerMixin {
DateTime? get endDateFiltered => searchEmailFilter.value.endDate?.value.toLocal(); DateTime? get endDateFiltered => searchEmailFilter.value.endDate?.value.toLocal();
PresentationMailbox? get mailboxFiltered => searchEmailFilter.value.mailbox;
bool isSearchActive() => bool isSearchActive() =>
searchState.value.searchStatus == SearchStatus.ACTIVE; searchState.value.searchStatus == SearchStatus.ACTIVE;
@@ -1,4 +1,5 @@
import 'package:core/core.dart'; import 'package:core/core.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_portal/flutter_portal.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
@@ -6,10 +7,10 @@ import 'package:get/get.dart';
import 'package:model/extensions/presentation_mailbox_extension.dart'; import 'package:model/extensions/presentation_mailbox_extension.dart';
import 'package:model/extensions/username_extension.dart'; import 'package:model/extensions/username_extension.dart';
import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart'; import 'package:tmail_ui_user/features/base/widget/popup_item_no_icon_widget.dart';
import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.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/email_view.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/base_mailbox_dashboard_view.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/base_mailbox_dashboard_view.dart';
@@ -19,19 +20,19 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/sear
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/download/download_task_item_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/download/download_task_item_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/mark_mailbox_as_read_loading_banner.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/navigation_bar/navigation_bar_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/navigation_bar/navigation_bar_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/search_input_form_widget.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/top_bar_thread_selection.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_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/vacation/styles/vacation_notification_message_widget_style.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart';
import 'package:tmail_ui_user/features/quotas/presentation/widget/quotas_banner_widget.dart'; import 'package:tmail_ui_user/features/quotas/presentation/widget/quotas_banner_widget.dart';
import 'package:tmail_ui_user/features/search/email/presentation/search_email_view.dart'; import 'package:tmail_ui_user/features/search/email/presentation/search_email_view.dart';
import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_view.dart'; import 'package:tmail_ui_user/features/search/mailbox/presentation/search_mailbox_view.dart';
import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart'; import 'package:tmail_ui_user/features/thread/domain/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/banner_delete_all_spam_emails_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/banner_empty_trash_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/banner_delete_all_spam_emails_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/banner_delete_all_spam_emails_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/banner_empty_trash_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/banner_empty_trash_widget.dart';
@@ -88,22 +89,23 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
)) ))
]), ]),
Expanded(child: Column(children: [ Expanded(child: Column(children: [
const SizedBox(height: 16),
Obx(() => RecoverDeletedMessageLoadingBannerWidget(
isLoading: controller.isRecoveringDeletedMessage.value,
horizontalLoadingWidget: horizontalLoadingWidget,
responsiveUtils: controller.responsiveUtils,
)),
Obx(() => MarkMailboxAsReadLoadingBanner(
viewState: controller.viewStateMarkAsReadMailbox.value,
)),
const SpamReportBannerWebWidget(), const SpamReportBannerWebWidget(),
QuotasBannerWidget( QuotasBannerWidget(),
margin: const EdgeInsetsDirectional.only(end: 16, top: 8),
),
_buildVacationNotificationMessage(context), _buildVacationNotificationMessage(context),
Obx(() { Obx(() {
final presentationMailbox = controller.selectedMailbox.value; final presentationMailbox = controller.selectedMailbox.value;
if (controller.isEmptyTrashBannerEnabledOnWeb(context, presentationMailbox)) { if (controller.isEmptyTrashBannerEnabledOnWeb(context, presentationMailbox)) {
return Padding( return BannerEmptyTrashWidget(
padding: const EdgeInsetsDirectional.only( onTapAction: () => controller.emptyTrashAction(context)
top: BannerEmptyTrashStyles.webTopMargin,
end: BannerEmptyTrashStyles.webEndMargin
),
child: BannerEmptyTrashWidget(
onTapAction: () => controller.emptyTrashAction(context)
),
); );
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -112,26 +114,14 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
Obx(() { Obx(() {
final presentationMailbox = controller.selectedMailbox.value; final presentationMailbox = controller.selectedMailbox.value;
if (controller.isEmptySpamBannerEnabledOnWeb(context, presentationMailbox)) { if (controller.isEmptySpamBannerEnabledOnWeb(context, presentationMailbox)) {
return Padding( return BannerDeleteAllSpamEmailsWidget(
padding: const EdgeInsetsDirectional.only( onTapAction: () => controller.openDialogEmptySpamFolder(context)
top: BannerDeleteAllSpamEmailsStyles.webTopMargin,
end: BannerDeleteAllSpamEmailsStyles.webEndMargin
),
child: BannerDeleteAllSpamEmailsWidget(
onTapAction: () => controller.openDialogEmptySpamFolder(context)
),
); );
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
}), }),
Obx(() => RecoverDeletedMessageLoadingBannerWidget(
isLoading: controller.isRecoveringDeletedMessage.value,
horizontalLoadingWidget: horizontalLoadingWidget,
responsiveUtils: controller.responsiveUtils,
)),
_buildListButtonQuickSearchFilter(context), _buildListButtonQuickSearchFilter(context),
_buildMarkAsMailboxReadLoading(context),
Expanded(child: Obx(() { Expanded(child: Obx(() {
switch(controller.dashboardRoute.value) { switch(controller.dashboardRoute.value) {
case DashboardRoutes.thread: case DashboardRoutes.thread:
@@ -223,7 +213,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
Widget _buildThreadViewForWebDesktop(BuildContext context) { Widget _buildThreadViewForWebDesktop(BuildContext context) {
return Container( return Container(
margin: const EdgeInsetsDirectional.only(end: 16, top: 8, bottom: 16), margin: const EdgeInsetsDirectional.only(end: 16, bottom: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
border: Border.all(color: AppColor.colorBorderBodyThread, width: 1), border: Border.all(color: AppColor.colorBorderBodyThread, width: 1),
@@ -380,37 +370,18 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
}),
const Spacer(),
Obx(() {
if (controller.searchController.isSearchEmailRunning &&
controller.dashboardRoute.value == DashboardRoutes.thread) {
return _buildQuickSearchFilterButton(context, QuickSearchFilter.sortBy);
} else {
return const SizedBox.shrink();
}
}) })
]);
}
Widget _buildMarkAsMailboxReadLoading(BuildContext context) { ]);
return Obx(() {
final viewState = controller.viewStateMarkAsReadMailbox.value;
return viewState.fold(
(failure) => const SizedBox.shrink(),
(success) {
if (success is MarkAsMailboxReadLoading) {
return Padding(
padding: EdgeInsets.only(
top: controller.responsiveUtils.isDesktop(context) ? 16 : 0,
left: 16,
right: 16,
bottom: controller.responsiveUtils.isDesktop(context) ? 0 : 16),
child: horizontalLoadingWidget);
} else if (success is UpdatingMarkAsMailboxReadState) {
final percent = success.countRead / success.totalUnread;
return Padding(
padding: EdgeInsets.only(
top: controller.responsiveUtils.isDesktop(context) ? 16 : 0,
left: 16,
right: 16,
bottom: controller.responsiveUtils.isDesktop(context) ? 0 : 16),
child: horizontalPercentLoadingWidget(percent));
}
return const SizedBox.shrink();
});
});
} }
Widget _buildDownloadTaskStateWidget() { Widget _buildDownloadTaskStateWidget() {
@@ -450,7 +421,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
return Obx(() { return Obx(() {
if (controller.vacationResponse.value?.vacationResponderIsValid == true) { if (controller.vacationResponse.value?.vacationResponderIsValid == true) {
return VacationNotificationMessageWidget( return VacationNotificationMessageWidget(
margin: const EdgeInsetsDirectional.only(top: 8, end: 16), margin: VacationNotificationMessageWidgetStyle.bannerMargin,
vacationResponse: controller.vacationResponse.value!, vacationResponse: controller.vacationResponse.value!,
actionGotoVacationSetting: controller.goToVacationSetting, actionGotoVacationSetting: controller.goToVacationSetting,
actionEndNow: controller.disableVacationResponder); actionEndNow: controller.disableVacationResponder);
@@ -465,17 +436,44 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
if (controller.searchController.isSearchEmailRunning && if (controller.searchController.isSearchEmailRunning &&
controller.dashboardRoute.value == DashboardRoutes.thread) { controller.dashboardRoute.value == DashboardRoutes.thread) {
return Padding( return Padding(
padding: const EdgeInsetsDirectional.only(end: 16, top: 8), padding: const EdgeInsetsDirectional.only(end: 16),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildQuickSearchFilterButton(context, QuickSearchFilter.from), Expanded(
const SizedBox(width: 8), child: SizedBox(
_buildQuickSearchFilterButton(context, QuickSearchFilter.dateTime), height: 45,
const SizedBox(width: 8), child: ScrollbarListView(
_buildQuickSearchFilterButton(context, QuickSearchFilter.hasAttachment), scrollBehavior: ScrollConfiguration.of(context).copyWith(
const Spacer(), dragDevices: {
_buildQuickSearchFilterButton(context, QuickSearchFilter.sortBy), PointerDeviceKind.touch,
const SizedBox(width: 8), PointerDeviceKind.mouse,
PointerDeviceKind.trackpad
},
scrollbars: false
),
scrollController: controller.listSearchFilterScrollController!,
child: ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
padding: const EdgeInsetsDirectional.only(bottom: 10),
controller: controller.listSearchFilterScrollController!,
children: [
_buildQuickSearchFilterButton(context, QuickSearchFilter.folder),
const SizedBox(width: 8),
_buildQuickSearchFilterButton(context, QuickSearchFilter.from),
const SizedBox(width: 8),
_buildQuickSearchFilterButton(context, QuickSearchFilter.to),
const SizedBox(width: 8),
_buildQuickSearchFilterButton(context, QuickSearchFilter.dateTime),
const SizedBox(width: 8),
_buildQuickSearchFilterButton(context, QuickSearchFilter.hasAttachment),
const SizedBox(width: 8),
],
),
),
)
),
] ]
), ),
); );
@@ -497,6 +495,8 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
final startDate = controller.searchController.startDateFiltered; final startDate = controller.searchController.startDateFiltered;
final endDate = controller.searchController.endDateFiltered; final endDate = controller.searchController.endDateFiltered;
final receiveTimeType = controller.searchController.receiveTimeFiltered; final receiveTimeType = controller.searchController.receiveTimeFiltered;
final mailbox = controller.searchController.mailboxFiltered;
final listAddressOfTo = controller.searchController.searchEmailFilter.value.to;
final isSelected = searchFilter.isSelected( final isSelected = searchFilter.isSelected(
context, context,
@@ -504,6 +504,7 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
sortOrderType); sortOrderType);
return SearchFilterButton( return SearchFilterButton(
key: Key('${searchFilter.name}_search_filter_button'),
searchFilter: searchFilter, searchFilter: searchFilter,
imagePaths: controller.imagePaths, imagePaths: controller.imagePaths,
isSelected: isSelected, isSelected: isSelected,
@@ -512,7 +513,9 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
endDate: endDate, endDate: endDate,
sortOrderType: sortOrderType, sortOrderType: sortOrderType,
listAddressOfFrom: listAddressOfFrom, listAddressOfFrom: listAddressOfFrom,
listAddressOfTo: listAddressOfTo,
userName: userName, userName: userName,
mailbox: mailbox,
onSelectSearchFilterAction: _onSelectSearchFilterAction, onSelectSearchFilterAction: _onSelectSearchFilterAction,
); );
}); });
@@ -540,6 +543,12 @@ class MailboxDashBoardView extends BaseMailboxDashBoardView {
case QuickSearchFilter.hasAttachment: case QuickSearchFilter.hasAttachment:
controller.selectHasAttachmentSearchFilter(); controller.selectHasAttachmentSearchFilter();
break; break;
case QuickSearchFilter.to:
controller.selectToSearchFilter();
break;
case QuickSearchFilter.folder:
controller.selectFolderSearchFilter();
break;
default: default:
break; break;
} }
@@ -3,6 +3,8 @@ import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/resources/image_paths.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart';
@@ -14,26 +16,9 @@ enum QuickSearchFilter {
fromMe, fromMe,
sortBy, sortBy,
dateTime, dateTime,
from; from,
to,
String getName(BuildContext context) { folder;
switch(this) {
case QuickSearchFilter.hasAttachment:
return AppLocalizations.of(context).hasAttachment;
case QuickSearchFilter.last7Days:
return AppLocalizations.of(context).last7Days;
case QuickSearchFilter.fromMe:
return AppLocalizations.of(context).fromMe;
case QuickSearchFilter.sortBy:
return AppLocalizations.of(context).sortBy;
case QuickSearchFilter.dateTime:
return AppLocalizations.of(context).allTime;
case QuickSearchFilter.from:
return AppLocalizations.of(context).from_email_address_prefix;
default:
return '';
}
}
String getTitle( String getTitle(
BuildContext context, { BuildContext context, {
@@ -42,7 +27,9 @@ enum QuickSearchFilter {
DateTime? startDate, DateTime? startDate,
DateTime? endDate, DateTime? endDate,
Set<String>? listAddressOfFrom, Set<String>? listAddressOfFrom,
UserName? userName UserName? userName,
Set<String>? listAddressOfTo,
PresentationMailbox? mailbox
}) { }) {
switch(this) { switch(this) {
case QuickSearchFilter.hasAttachment: case QuickSearchFilter.hasAttachment:
@@ -61,17 +48,11 @@ enum QuickSearchFilter {
endDate: endDate endDate: endDate
) ?? AppLocalizations.of(context).allTime; ) ?? AppLocalizations.of(context).allTime;
case QuickSearchFilter.from: case QuickSearchFilter.from:
if (listAddressOfFrom?.length != 1) { return AppLocalizations.of(context).from_email_address_prefix;
return AppLocalizations.of(context).from_email_address_prefix; case QuickSearchFilter.folder:
} return mailbox?.getDisplayName(context) ?? AppLocalizations.of(context).all;
case QuickSearchFilter.to:
if (userName?.value.isNotEmpty == true && listAddressOfFrom?.first == userName?.value) { return AppLocalizations.of(context).to_email_address_prefix;
return AppLocalizations.of(context).fromMe;
} else {
return '${AppLocalizations.of(context).from_email_address_prefix} ${listAddressOfFrom?.first}';
}
default:
return '';
} }
} }
@@ -89,6 +70,10 @@ enum QuickSearchFilter {
return imagePaths.icCalendarSB; return imagePaths.icCalendarSB;
case QuickSearchFilter.from: case QuickSearchFilter.from:
return imagePaths.icUserSB; return imagePaths.icUserSB;
case QuickSearchFilter.to:
return imagePaths.icUserSB;
case QuickSearchFilter.folder:
return imagePaths.icFolderMailbox;
} }
} }
@@ -136,6 +121,10 @@ enum QuickSearchFilter {
return searchFilter.emailReceiveTimeType != EmailReceiveTimeType.allTime; return searchFilter.emailReceiveTimeType != EmailReceiveTimeType.allTime;
case QuickSearchFilter.from: case QuickSearchFilter.from:
return searchFilter.from.isNotEmpty; return searchFilter.from.isNotEmpty;
case QuickSearchFilter.to:
return searchFilter.to.isNotEmpty;
case QuickSearchFilter.folder:
return searchFilter.mailbox != null;
} }
} }
@@ -145,5 +134,7 @@ enum QuickSearchFilter {
bool isArrowDownIconSupported() => bool isArrowDownIconSupported() =>
this == QuickSearchFilter.dateTime || this == QuickSearchFilter.dateTime ||
this == QuickSearchFilter.from || this == QuickSearchFilter.from ||
this == QuickSearchFilter.to ||
this == QuickSearchFilter.folder ||
this == QuickSearchFilter.sortBy; this == QuickSearchFilter.sortBy;
} }
@@ -60,7 +60,7 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin {
SearchQuery? text, SearchQuery? text,
Option<String>? subjectOption, Option<String>? subjectOption,
Set<String>? notKeyword, Set<String>? notKeyword,
PresentationMailbox? mailbox, Option<PresentationMailbox>? mailboxOption,
EmailReceiveTimeType? emailReceiveTimeType, EmailReceiveTimeType? emailReceiveTimeType,
bool? hasAttachment, bool? hasAttachment,
Option<UTCDate>? beforeOption, Option<UTCDate>? beforeOption,
@@ -75,7 +75,7 @@ class SearchEmailFilter with EquatableMixin, OptionParamMixin {
text: text ?? this.text, text: text ?? this.text,
subject: getOptionParam(subjectOption, subject), subject: getOptionParam(subjectOption, subject),
notKeyword: notKeyword ?? this.notKeyword, notKeyword: notKeyword ?? this.notKeyword,
mailbox: mailbox ?? this.mailbox, mailbox: getOptionParam(mailboxOption, mailbox),
emailReceiveTimeType: emailReceiveTimeType ?? this.emailReceiveTimeType, emailReceiveTimeType: emailReceiveTimeType ?? this.emailReceiveTimeType,
hasAttachment: hasAttachment ?? this.hasAttachment, hasAttachment: hasAttachment ?? this.hasAttachment,
before: getOptionParam(beforeOption, before), before: getOptionParam(beforeOption, before),
@@ -0,0 +1,5 @@
import 'package:flutter/material.dart';
class MarkMailboxAsReadLoadingBannerStyle {
static const EdgeInsetsGeometry bannerMargin = EdgeInsetsDirectional.only(end: 16, bottom: 8);
}
@@ -0,0 +1,26 @@
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
class RecoverDeletedMessageLoadingBannerStyle {
static EdgeInsetsGeometry getBannerMargin(
BuildContext context,
ResponsiveUtils responsiveUtils
) {
if (PlatformInfo.isWeb) {
if (responsiveUtils.isDesktop(context)) {
return const EdgeInsetsDirectional.only(end: 16, bottom: 8);
} else if (responsiveUtils.isTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 24, end: 24);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 12, end: 12);
}
} else {
if (responsiveUtils.isPortraitTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 32, end: 32);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 16, end: 16);
}
}
}
}
@@ -5,6 +5,7 @@ class SearchFilterButtonStyle {
static const double iconSize = 16; static const double iconSize = 16;
static const double deleteIconSize = 10; static const double deleteIconSize = 10;
static const double spaceSize = 4; static const double spaceSize = 4;
static const double buttonSize = 35;
static const EdgeInsetsGeometry buttonPadding = EdgeInsets.symmetric(horizontal: 12, vertical: 8); static const EdgeInsetsGeometry buttonPadding = EdgeInsets.symmetric(horizontal: 12, vertical: 8);
static const EdgeInsetsGeometry elementPadding = EdgeInsetsDirectional.only(start: 8); static const EdgeInsetsGeometry elementPadding = EdgeInsetsDirectional.only(start: 8);
@@ -0,0 +1,37 @@
import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/mark_mailbox_as_read_loading_banner_style.dart';
class MarkMailboxAsReadLoadingBanner extends StatelessWidget with AppLoaderMixin {
final Either<Failure, Success> viewState;
const MarkMailboxAsReadLoadingBanner({
super.key,
required this.viewState,
});
@override
Widget build(BuildContext context) {
return viewState.fold(
(failure) => const SizedBox.shrink(),
(success) {
if (success is MarkAsMailboxReadLoading) {
return Padding(
padding: MarkMailboxAsReadLoadingBannerStyle.bannerMargin,
child: horizontalLoadingWidget);
} else if (success is UpdatingMarkAsMailboxReadState) {
final percent = success.countRead / success.totalUnread;
return Padding(
padding: MarkMailboxAsReadLoadingBannerStyle.bannerMargin,
child: horizontalPercentLoadingWidget(percent));
} else {
return const SizedBox.shrink();
}
}
);
}
}
@@ -1,6 +1,7 @@
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/styles/recover_deleted_message_loading_banner_style.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class RecoverDeletedMessageLoadingBannerWidget extends StatelessWidget { class RecoverDeletedMessageLoadingBannerWidget extends StatelessWidget {
@@ -18,42 +19,38 @@ class RecoverDeletedMessageLoadingBannerWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (isLoading) { if (isLoading) {
return Padding( return Container(
padding: EdgeInsetsDirectional.only( margin: RecoverDeletedMessageLoadingBannerStyle.getBannerMargin(
top: responsiveUtils.isDesktop(context) ? 16 : 0, context,
end: 16, responsiveUtils),
bottom: responsiveUtils.isDesktop(context) ? 0 : 16, padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
), ),
child: Container( decoration: const ShapeDecoration(
padding: const EdgeInsets.symmetric( color: Colors.white,
horizontal: 16, shape: RoundedRectangleBorder(
vertical: 12, side: BorderSide(
), width: 1,
decoration: const ShapeDecoration( color: AppColor.colorBorderBodyThread,
color: Colors.white, ),
shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(14)),
side: BorderSide( )
width: 1, ),
color: AppColor.colorBorderBodyThread, child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context).bannerProgressingRecoveryMessage,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
color: AppColor.primaryColor,
), ),
borderRadius: BorderRadius.all(Radius.circular(14)), ),
) const SizedBox(height: 12),
), horizontalLoadingWidget
child: Column( ],
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context).bannerProgressingRecoveryMessage,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
color: AppColor.primaryColor,
),
),
const SizedBox(height: 12),
horizontalLoadingWidget
],
),
), ),
); );
} else { } else {
@@ -5,6 +5,7 @@ import 'package:core/presentation/views/button/tmail_button_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:jmap_dart_client/jmap/core/user_name.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart';
import 'package:model/mailbox/presentation_mailbox.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart';
@@ -17,6 +18,8 @@ typedef OnSelectSearchFilterAction = Function(
class SearchFilterButton extends StatelessWidget { class SearchFilterButton extends StatelessWidget {
static const int _titleCharactersMaximum = 20;
final QuickSearchFilter searchFilter; final QuickSearchFilter searchFilter;
final bool isSelected; final bool isSelected;
final ImagePaths imagePaths; final ImagePaths imagePaths;
@@ -25,7 +28,9 @@ class SearchFilterButton extends StatelessWidget {
final DateTime? startDate; final DateTime? startDate;
final DateTime? endDate; final DateTime? endDate;
final Set<String>? listAddressOfFrom; final Set<String>? listAddressOfFrom;
final Set<String>? listAddressOfTo;
final UserName? userName; final UserName? userName;
final PresentationMailbox? mailbox;
final Color? backgroundColor; final Color? backgroundColor;
final OnSelectSearchFilterAction? onSelectSearchFilterAction; final OnSelectSearchFilterAction? onSelectSearchFilterAction;
@@ -39,18 +44,33 @@ class SearchFilterButton extends StatelessWidget {
this.startDate, this.startDate,
this.endDate, this.endDate,
this.listAddressOfFrom, this.listAddressOfFrom,
this.listAddressOfTo,
this.userName, this.userName,
this.mailbox,
this.backgroundColor, this.backgroundColor,
this.onSelectSearchFilterAction, this.onSelectSearchFilterAction,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final filterTitle = searchFilter.getTitle(
context,
receiveTimeType: receiveTimeType,
startDate: startDate,
endDate: startDate,
sortOrderType: sortOrderType,
listAddressOfFrom: listAddressOfFrom,
userName: userName,
mailbox: mailbox,
listAddressOfTo: listAddressOfTo,
);
final childItem = Container( final childItem = Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: SearchFilterButtonStyle.borderRadius, borderRadius: SearchFilterButtonStyle.borderRadius,
color: backgroundColor ?? searchFilter.getBackgroundColor(isFilterSelected: isSelected)), color: backgroundColor ?? searchFilter.getBackgroundColor(isFilterSelected: isSelected)),
padding: SearchFilterButtonStyle.buttonPadding, padding: SearchFilterButtonStyle.buttonPadding,
height: SearchFilterButtonStyle.buttonSize,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -62,14 +82,9 @@ class SearchFilterButton extends StatelessWidget {
fit: BoxFit.fill), fit: BoxFit.fill),
const SizedBox(width: SearchFilterButtonStyle.spaceSize), const SizedBox(width: SearchFilterButtonStyle.spaceSize),
Text( Text(
searchFilter.getTitle( filterTitle.length > _titleCharactersMaximum
context, ? '${filterTitle.substring(0, _titleCharactersMaximum)}...'
receiveTimeType: receiveTimeType, : filterTitle,
startDate: startDate,
endDate: startDate,
sortOrderType: sortOrderType,
listAddressOfFrom: listAddressOfFrom,
userName: userName),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: SearchFilterButtonStyle.titleStyle, style: SearchFilterButtonStyle.titleStyle,
@@ -0,0 +1,8 @@
import 'package:flutter/material.dart';
class VacationNotificationMessageWidgetStyle {
static const EdgeInsetsGeometry bannerMargin = EdgeInsetsDirectional.only(
end: 16,
bottom: 8);
}
@@ -1,10 +1,10 @@
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class QuotasBannerStyles { class QuotasBannerStyles {
static const double verticalPadding = 8;
static const double horizontalPadding = 16;
static const double iconPadding = 16; static const double iconPadding = 16;
static const double iconSize = 32; static const double iconSize = 32;
static const double titleTextSize = 17; static const double titleTextSize = 17;
@@ -16,4 +16,29 @@ class QuotasBannerStyles {
static const FontWeight titleFontWeight = FontWeight.w700; static const FontWeight titleFontWeight = FontWeight.w700;
static const FontWeight messageFontWeight = FontWeight.w400; static const FontWeight messageFontWeight = FontWeight.w400;
static const EdgeInsetsGeometry bannerPadding = EdgeInsetsDirectional.symmetric(
horizontal: 16,
vertical: 8,
);
static EdgeInsetsGeometry getBannerMargin(
BuildContext context,
ResponsiveUtils responsiveUtils
) {
if (PlatformInfo.isWeb) {
if (responsiveUtils.isDesktop(context)) {
return const EdgeInsetsDirectional.only(end: 16, bottom: 8);
} else if (responsiveUtils.isTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 24, end: 24);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 12, end: 12);
}
} else {
if (responsiveUtils.isPortraitTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 32, end: 32);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 16, end: 16);
}
}
}
} }
@@ -8,28 +8,23 @@ import 'package:tmail_ui_user/features/quotas/presentation/styles/quotas_banner_
class QuotasBannerWidget extends StatelessWidget { class QuotasBannerWidget extends StatelessWidget {
final QuotasController _quotasController = Get.find<QuotasController>(); final QuotasController _quotasController = Get.find<QuotasController>();
final EdgeInsetsGeometry? margin;
QuotasBannerWidget({ QuotasBannerWidget({Key? key}) : super(key: key);
Key? key,
this.margin,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Obx(() { return Obx(() {
if (_quotasController.octetsQuota.value != null && _quotasController.octetsQuota.value!.allowedDisplayToQuotaBanner) { final octetQuota = _quotasController.octetsQuota.value;
final octetQuota = _quotasController.octetsQuota.value!; if (octetQuota != null && octetQuota.allowedDisplayToQuotaBanner) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: octetQuota.getQuotaBannerBackgroundColor(), color: octetQuota.getQuotaBannerBackgroundColor(),
borderRadius: const BorderRadius.all(Radius.circular(QuotasBannerStyles.borderRadius)), borderRadius: const BorderRadius.all(Radius.circular(QuotasBannerStyles.borderRadius)),
), ),
margin: margin, margin: QuotasBannerStyles.getBannerMargin(
padding: const EdgeInsetsDirectional.symmetric( context,
horizontal: QuotasBannerStyles.horizontalPadding, _quotasController.responsiveUtils),
vertical: QuotasBannerStyles.verticalPadding, padding: QuotasBannerStyles.bannerPadding,
),
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
@@ -1,5 +1,7 @@
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class BannerDeleteAllSpamEmailsStyles { class BannerDeleteAllSpamEmailsStyles {
@@ -7,9 +9,6 @@ class BannerDeleteAllSpamEmailsStyles {
static const double buttonBorderRadius = 20; static const double buttonBorderRadius = 20;
static const double horizontalPadding = 16; static const double horizontalPadding = 16;
static const double verticalPadding = 10; static const double verticalPadding = 10;
static const double webEndMargin = 16;
static const double webTopMargin = 8;
static const double mobileMargin = 16;
static const double labelTextSize = 13; static const double labelTextSize = 13;
static const double buttonTextSize = 17; static const double buttonTextSize = 17;
static const double iconSize = 20; static const double iconSize = 20;
@@ -18,4 +17,25 @@ class BannerDeleteAllSpamEmailsStyles {
static const Color borderStrokeColor = AppColor.colorBorderBodyThread; static const Color borderStrokeColor = AppColor.colorBorderBodyThread;
static const Color labelTextColor = AppColor.colorSubtitle; static const Color labelTextColor = AppColor.colorSubtitle;
static const Color buttonTextColor = AppColor.toastErrorBackgroundColor; static const Color buttonTextColor = AppColor.toastErrorBackgroundColor;
static EdgeInsetsGeometry getBannerMargin(
BuildContext context,
ResponsiveUtils responsiveUtils
) {
if (PlatformInfo.isWeb) {
if (responsiveUtils.isDesktop(context)) {
return const EdgeInsetsDirectional.only(end: 16, bottom: 8);
} else if (responsiveUtils.isTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 24, end: 24);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 12, end: 12);
}
} else {
if (responsiveUtils.isPortraitTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 32, end: 32);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 16, end: 16);
}
}
}
} }
@@ -1,5 +1,7 @@
import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class BannerEmptyTrashStyles { class BannerEmptyTrashStyles {
@@ -7,9 +9,6 @@ class BannerEmptyTrashStyles {
static const double buttonBorderRadius = 20; static const double buttonBorderRadius = 20;
static const double horizontalPadding = 16; static const double horizontalPadding = 16;
static const double verticalPadding = 10; static const double verticalPadding = 10;
static const double webEndMargin = 16;
static const double webTopMargin = 8;
static const double mobileMargin = 16;
static const double labelTextSize = 13; static const double labelTextSize = 13;
static const double buttonTextSize = 17; static const double buttonTextSize = 17;
static const double iconSize = 20; static const double iconSize = 20;
@@ -18,4 +17,25 @@ class BannerEmptyTrashStyles {
static const Color borderStrokeColor = AppColor.colorBorderBodyThread; static const Color borderStrokeColor = AppColor.colorBorderBodyThread;
static const Color labelTextColor = AppColor.colorSubtitle; static const Color labelTextColor = AppColor.colorSubtitle;
static const Color buttonTextColor = AppColor.toastErrorBackgroundColor; static const Color buttonTextColor = AppColor.toastErrorBackgroundColor;
static EdgeInsetsGeometry getBannerMargin(
BuildContext context,
ResponsiveUtils responsiveUtils
) {
if (PlatformInfo.isWeb) {
if (responsiveUtils.isDesktop(context)) {
return const EdgeInsetsDirectional.only(end: 16, bottom: 8);
} else if (responsiveUtils.isTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 24, end: 24);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 12, end: 12);
}
} else {
if (responsiveUtils.isPortraitTablet(context)) {
return const EdgeInsetsDirectional.only(bottom: 8, start: 32, end: 32);
} else {
return const EdgeInsetsDirectional.only(bottom: 8, start: 16, end: 16);
}
}
}
} }
@@ -3,11 +3,14 @@ import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SpamReportBannerWebStyles { class SpamReportBannerWebStyles {
static const double horizontalMargin = 16;
static const double verticalMargin = 16;
static const double verticalPadding = 8;
static const double horizontalPadding = 16;
static const double borderRadius = 12; static const double borderRadius = 12;
static Color backgroundColor = AppColor.colorSpamReportBannerBackground.withOpacity(0.12); static Color backgroundColor = AppColor.colorSpamReportBannerBackground.withOpacity(0.12);
static const Color strokeBorderColor = AppColor.colorSpamReportBannerStrokeBorder; static const Color strokeBorderColor = AppColor.colorSpamReportBannerStrokeBorder;
static const EdgeInsetsGeometry bannerPadding = EdgeInsetsDirectional.symmetric(
horizontal: 16,
vertical: 8);
static const EdgeInsetsGeometry bannerMargin = EdgeInsetsDirectional.only(
end: 16,
bottom: 8);
} }
@@ -0,0 +1,25 @@
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/material.dart';
class ThreadViewStyle {
static EdgeInsetsGeometry getBannerMargin(
BuildContext context,
ResponsiveUtils responsiveUtils
) {
if (PlatformInfo.isWeb) {
if (responsiveUtils.isMobile(context) || responsiveUtils.isTabletLarge(context)) {
return const EdgeInsetsDirectional.only(start: 12, end: 12, bottom: 8);
} else {
return const EdgeInsetsDirectional.only(start: 24, end: 24, bottom: 8);
}
} else {
if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeTablet(context)) {
return const EdgeInsetsDirectional.only(start: 16, end: 16, bottom: 8);
} else {
return const EdgeInsetsDirectional.only(start: 32, end: 32, bottom: 8);
}
}
}
}
@@ -22,10 +22,9 @@ import 'package:tmail_ui_user/features/thread/domain/state/get_all_email_state.d
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart'; import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/loading_more_status.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/loading_more_status.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/banner_delete_all_spam_emails_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/banner_empty_trash_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/item_email_tile_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/scroll_to_top_button_widget_styles.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/scroll_to_top_button_widget_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/thread_view_style.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar/app_bar_thread_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar/app_bar_thread_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/banner_delete_all_spam_emails_widget.dart'; import 'package:tmail_ui_user/features/thread/presentation/widgets/banner_delete_all_spam_emails_widget.dart';
@@ -112,22 +111,26 @@ class ThreadView extends GetWidget<ThreadController>
SearchBarView( SearchBarView(
key: const Key('email_search_bar_view'), key: const Key('email_search_bar_view'),
imagePaths: controller.imagePaths, imagePaths: controller.imagePaths,
margin: _getBannerMargin(context, controller.responsiveUtils), margin: ThreadViewStyle.getBannerMargin(
context,
controller.responsiveUtils),
hintTextSearch: AppLocalizations.of(context).search_emails, hintTextSearch: AppLocalizations.of(context).search_emails,
onOpenSearchViewAction: controller.goToSearchView onOpenSearchViewAction: controller.goToSearchView
), ),
SpamReportBannerWidget( SpamReportBannerWidget(
spamReportController: controller.mailboxDashBoardController.spamReportController, spamReportController: controller.mailboxDashBoardController.spamReportController,
margin: _getBannerMargin(context, controller.responsiveUtils), margin: ThreadViewStyle.getBannerMargin(
), context,
QuotasBannerWidget( controller.responsiveUtils),
margin: _getBannerMargin(context, controller.responsiveUtils),
), ),
QuotasBannerWidget(),
Obx(() { Obx(() {
final vacation = controller.mailboxDashBoardController.vacationResponse.value; final vacation = controller.mailboxDashBoardController.vacationResponse.value;
if (vacation?.vacationResponderIsValid == true) { if (vacation?.vacationResponderIsValid == true) {
return VacationNotificationMessageWidget( return VacationNotificationMessageWidget(
margin: _getBannerMargin(context, controller.responsiveUtils), margin: ThreadViewStyle.getBannerMargin(
context,
controller.responsiveUtils),
vacationResponse: vacation!, vacationResponse: vacation!,
actionGotoVacationSetting: controller.mailboxDashBoardController.goToVacationSetting, actionGotoVacationSetting: controller.mailboxDashBoardController.goToVacationSetting,
actionEndNow: controller.mailboxDashBoardController.disableVacationResponder actionEndNow: controller.mailboxDashBoardController.disableVacationResponder
@@ -145,13 +148,10 @@ class ThreadView extends GetWidget<ThreadController>
Obx(() { Obx(() {
final presentationMailbox = controller.mailboxDashBoardController.selectedMailbox.value; final presentationMailbox = controller.mailboxDashBoardController.selectedMailbox.value;
if (controller.mailboxDashBoardController.isEmptyTrashBannerEnabledOnMobile(context, presentationMailbox)) { if (controller.mailboxDashBoardController.isEmptyTrashBannerEnabledOnMobile(context, presentationMailbox)) {
return Padding( return BannerEmptyTrashWidget(
padding: const EdgeInsetsDirectional.symmetric( onTapAction: () => controller.deleteSelectionEmailsPermanently(
horizontal: BannerEmptyTrashStyles.mobileMargin context,
), DeleteActionType.all)
child: BannerEmptyTrashWidget(
onTapAction: () => controller.deleteSelectionEmailsPermanently(context, DeleteActionType.all)
),
); );
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -160,13 +160,8 @@ class ThreadView extends GetWidget<ThreadController>
Obx(() { Obx(() {
final presentationMailbox = controller.mailboxDashBoardController.selectedMailbox.value; final presentationMailbox = controller.mailboxDashBoardController.selectedMailbox.value;
if (controller.mailboxDashBoardController.isEmptySpamBannerEnabledOnMobile(context, presentationMailbox)) { if (controller.mailboxDashBoardController.isEmptySpamBannerEnabledOnMobile(context, presentationMailbox)) {
return Padding( return BannerDeleteAllSpamEmailsWidget(
padding: const EdgeInsetsDirectional.symmetric( onTapAction: () => controller.mailboxDashBoardController.openDialogEmptySpamFolder(context)
horizontal: BannerDeleteAllSpamEmailsStyles.mobileMargin
),
child: BannerDeleteAllSpamEmailsWidget(
onTapAction: () => controller.mailboxDashBoardController.openDialogEmptySpamFolder(context)
),
); );
} else { } else {
return const SizedBox.shrink(); return const SizedBox.shrink();
@@ -222,22 +217,6 @@ class ThreadView extends GetWidget<ThreadController>
); );
} }
EdgeInsetsGeometry _getBannerMargin(BuildContext context, ResponsiveUtils responsiveUtils) {
if (PlatformInfo.isWeb) {
if (responsiveUtils.isMobile(context) || responsiveUtils.isTabletLarge(context)) {
return const EdgeInsetsDirectional.only(start: 12, end: 12, bottom: 8);
} else {
return const EdgeInsetsDirectional.only(start: 24, end: 24, bottom: 8);
}
} else {
if (responsiveUtils.isPortraitMobile(context) || responsiveUtils.isLandscapeTablet(context)) {
return const EdgeInsetsDirectional.only(start: 16, end: 16, bottom: 8);
} else {
return const EdgeInsetsDirectional.only(start: 32, end: 32, bottom: 8);
}
}
}
bool _supportVerticalDivider(BuildContext context) { bool _supportVerticalDivider(BuildContext context) {
if (PlatformInfo.isWeb) { if (PlatformInfo.isWeb) {
return controller.responsiveUtils.isTabletLarge(context); return controller.responsiveUtils.isTabletLarge(context);
@@ -1,9 +1,11 @@
import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/banner_delete_all_spam_emails_styles.dart'; import 'package:tmail_ui_user/features/thread/presentation/styles/banner_delete_all_spam_emails_styles.dart';
import 'package:tmail_ui_user/features/thread/presentation/styles/banner_empty_trash_styles.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class BannerDeleteAllSpamEmailsWidget extends StatelessWidget { class BannerDeleteAllSpamEmailsWidget extends StatelessWidget {
@@ -15,6 +17,8 @@ class BannerDeleteAllSpamEmailsWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final imagePaths = Get.find<ImagePaths>(); final imagePaths = Get.find<ImagePaths>();
final responsiveUtils = Get.find<ResponsiveUtils>();
return Container( return Container(
decoration: const ShapeDecoration( decoration: const ShapeDecoration(
color: BannerDeleteAllSpamEmailsStyles.backgroundColor, color: BannerDeleteAllSpamEmailsStyles.backgroundColor,
@@ -26,6 +30,7 @@ class BannerDeleteAllSpamEmailsWidget extends StatelessWidget {
borderRadius: BorderRadius.all(Radius.circular(BannerDeleteAllSpamEmailsStyles.borderRadius)), borderRadius: BorderRadius.all(Radius.circular(BannerDeleteAllSpamEmailsStyles.borderRadius)),
), ),
), ),
margin: BannerEmptyTrashStyles.getBannerMargin(context, responsiveUtils),
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
@@ -1,5 +1,6 @@
import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -15,6 +16,8 @@ class BannerEmptyTrashWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final imagePaths = Get.find<ImagePaths>(); final imagePaths = Get.find<ImagePaths>();
final responsiveUtils = Get.find<ResponsiveUtils>();
return Container( return Container(
decoration: const ShapeDecoration( decoration: const ShapeDecoration(
color: BannerEmptyTrashStyles.backgroundColor, color: BannerEmptyTrashStyles.backgroundColor,
@@ -26,6 +29,7 @@ class BannerEmptyTrashWidget extends StatelessWidget {
borderRadius: BorderRadius.all(Radius.circular(BannerEmptyTrashStyles.borderRadius)), borderRadius: BorderRadius.all(Radius.circular(BannerEmptyTrashStyles.borderRadius)),
), ),
), ),
margin: BannerEmptyTrashStyles.getBannerMargin(context, responsiveUtils),
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
@@ -21,20 +21,12 @@ class SpamReportBannerWebWidget extends StatelessWidget {
return Obx(() { return Obx(() {
if (spamReportController.spamReportState.value == SpamReportState.disabled if (spamReportController.spamReportState.value == SpamReportState.disabled
|| spamReportController.presentationSpamMailbox.value == null) { || spamReportController.presentationSpamMailbox.value == null) {
return const SizedBox( return const SizedBox.shrink();
height: 8,
);
} }
return Container( return Container(
margin: const EdgeInsetsDirectional.only( margin: SpamReportBannerWebStyles.bannerMargin,
end: SpamReportBannerWebStyles.horizontalMargin,
top: SpamReportBannerWebStyles.verticalMargin,
),
width: double.infinity, width: double.infinity,
padding: const EdgeInsetsDirectional.symmetric( padding: SpamReportBannerWebStyles.bannerPadding,
horizontal: SpamReportBannerWebStyles.horizontalPadding,
vertical: SpamReportBannerWebStyles.verticalPadding,
),
decoration: ShapeDecoration( decoration: ShapeDecoration(
color: SpamReportBannerWebStyles.backgroundColor, color: SpamReportBannerWebStyles.backgroundColor,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(