TF-119 Filter messages with unread, attachments, starred

This commit is contained in:
dab246
2022-02-11 14:02:06 +07:00
committed by Dat H. Pham
parent c22bc94052
commit ca69bee4cd
22 changed files with 447 additions and 34 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.0011 14.3525L4.00488 9.355C4.04189 8.71805 4.32102 8.11936 4.7851 7.68153C5.24919 7.24371 5.86311 6.99988 6.50113 7H21.5011C22.1392 6.99988 22.7531 7.24371 23.2172 7.68153C23.6812 8.11936 23.9604 8.71805 23.9974 9.355L14.0011 14.3525ZM14 17.1476L24 12.1476V19.5001C24 20.1631 23.7366 20.799 23.2678 21.2678C22.7989 21.7367 22.163 22.0001 21.5 22.0001H6.5C5.83696 22.0001 5.20107 21.7367 4.73223 21.2678C4.26339 20.799 4 20.1631 4 19.5001V12.1476L14 17.1476Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 632 B

@@ -0,0 +1,3 @@
<svg width="28" height="29" viewBox="0 0 28 29" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.3436 16.7452C19.6707 16.4189 20.2004 16.4195 20.5267 16.7466C20.853 17.0737 20.8523 17.6033 20.5253 17.9296L16.2842 22.1607C13.9505 24.4889 10.1713 24.4844 7.84316 22.1507C7.81783 22.1252 7.81783 22.1252 7.79269 22.0995C5.3946 19.6371 5.40358 15.7098 7.81289 13.2584L14.1667 6.79365C15.8414 5.08969 18.5804 5.06597 20.2843 6.74068C20.3207 6.77644 20.3565 6.81284 20.3915 6.84986L20.4209 6.88083C22.1028 8.65504 22.0839 11.4406 20.3782 13.1919L13.9721 19.7694C12.9866 20.7813 11.3871 20.8608 10.3061 19.9517L10.2358 19.8926C9.15828 18.9864 9.01937 17.3783 9.92553 16.3008C9.95874 16.2613 9.99314 16.2228 10.0287 16.1854L14.34 11.6488C14.6583 11.3139 15.1878 11.3004 15.5227 11.6187C15.8576 11.937 15.871 12.4665 15.5528 12.8014L11.2415 17.338C11.2292 17.3508 11.2174 17.3641 11.206 17.3776C10.8946 17.748 10.9423 18.3007 11.3126 18.6121L11.383 18.6712C11.793 19.0161 12.3997 18.9859 12.7735 18.6021L19.1797 12.0246C20.2588 10.9166 20.2707 9.15431 19.2067 8.03185L19.1773 8.00088C19.1558 7.97818 19.1339 7.95586 19.1116 7.93393C18.0666 6.90692 16.387 6.92146 15.3599 7.96641L9.00614 14.4312C7.23452 16.2338 7.22792 19.1216 8.99129 20.9322C9.00937 20.9507 9.00938 20.9507 9.02761 20.9691C10.7032 22.6486 13.423 22.6518 15.1025 20.9763L19.3436 16.7452Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24ZM18.2071 9.20711C18.5976 8.81658 18.5976 8.18342 18.2071 7.79289C17.8166 7.40237 17.1834 7.40237 16.7929 7.79289L10 14.5858L7.20711 11.7929C6.81658 11.4024 6.18342 11.4024 5.79289 11.7929C5.40237 12.1834 5.40237 12.8166 5.79289 13.2071L9.29289 16.7071C9.68342 17.0976 10.3166 17.0976 10.7071 16.7071L18.2071 9.20711Z" fill="#007AFF"/>
</svg>

After

Width:  |  Height:  |  Size: 600 B

+2
View File
@@ -42,6 +42,8 @@ export 'presentation/views/dialog/downloading_file_dialog_builder.dart';
export 'presentation/views/background/background_widget_builder.dart';
export 'presentation/views/html_viewer/html_content_viewer_widget.dart';
export 'presentation/views/floating_button/scrolling_floating_button_animated.dart';
export 'presentation/views/bottom_popup/cupertino_action_sheet_action_builder.dart';
export 'presentation/views/bottom_popup/cupertino_action_sheet_builder.dart';
// Resources
export 'presentation/resources/assets_paths.dart';
@@ -71,6 +71,9 @@ extension AppColor on Color {
static const colorDividerMailbox = Color(0xFF99A2AD);
static const colorArrowUserMailbox = Color(0xFFB8C1CC);
static const colorBgMailbox = Color(0xFFF7F7F7);
static const colorFilterMessageDisabled = Color(0xFF99A2AD);
static const colorFilterMessageEnabled = Color(0xFF007AFF);
static const colorDefaultCupertinoActionSheet = Color(0x66000000);
static const mapGradientColor = [
[Color(0xFF21D4FD), Color(0xFFB721FF)],
@@ -75,6 +75,9 @@ class ImagePaths {
String get icMailboxArchivedV2 => _getImagePath('ic_mailbox_archived_v2.svg');
String get icMailboxSpamV2 => _getImagePath('ic_mailbox_spam_v2.svg');
String get icMailboxTrashV2 => _getImagePath('ic_mailbox_trash_v2.svg');
String get icFilterSelected => _getImagePath('ic_filter_selected.svg');
String get icFilterMessageAll => _getImagePath('ic_filter_message_all.svg');
String get icFilterMessageAttachments => _getImagePath('ic_filter_message_attachments.svg');
String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
@@ -40,7 +40,12 @@ class ResponsiveUtils {
double getWidthLoginButton() => _loginButtonWidth;
EdgeInsets getMarginDestinationPicker(BuildContext context) {
if (isTablet(context)) {
if (isMobileDevice(context) && isLandscape(context)) {
return EdgeInsets.only(
left: _tabletHorizontalMargin,
right: _tabletHorizontalMargin,
top: 50.0);
} else if (isTablet(context)) {
return getSizeHeightScreen(context) <= _tabletVerticalMargin * 2
? EdgeInsets.symmetric(
horizontal: _tabletHorizontalMargin,
@@ -62,7 +67,9 @@ class ResponsiveUtils {
}
BorderRadius radiusDestinationPicker(BuildContext context, double radius) {
if (isTablet(context)) {
if (isMobileDevice(context) && isLandscape(context)) {
return BorderRadius.only(topLeft: Radius.circular(radius), topRight: Radius.circular(radius));
} else if (isTablet(context)) {
return getSizeHeightScreen(context) <= _tabletVerticalMargin * 2
? BorderRadius.only(topLeft: Radius.circular(radius), topRight: Radius.circular(radius))
: BorderRadius.circular(radius);
@@ -0,0 +1,29 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
typedef OnCupertinoActionSheetActionClick<T> = void Function(T data);
abstract class CupertinoActionSheetActionBuilder<T> {
@protected final Key key;
@protected final SvgPicture actionIcon;
@protected final String actionName;
@protected OnCupertinoActionSheetActionClick<T>? onCupertinoActionSheetActionClick;
CupertinoActionSheetActionBuilder(
this.key,
this.actionIcon,
this.actionName
);
void onActionClick(OnCupertinoActionSheetActionClick<T> onCupertinoActionSheetActionClick) {
this.onCupertinoActionSheetActionClick = onCupertinoActionSheetActionClick;
}
TextStyle actionTextStyle() {
return TextStyle(fontSize: 17, color: AppColor.colorNameEmail);
}
Widget build();
}
@@ -0,0 +1,44 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
class CupertinoActionSheetBuilder {
final BuildContext _context;
final List<Widget> _actionTiles = [];
Widget? _titleWidget;
Widget? _messageWidget;
Widget? _cancelWidget;
CupertinoActionSheetBuilder(this._context);
void title(Widget? titleWidget) {
_titleWidget = titleWidget;
}
void message(Widget? messageWidget) {
_messageWidget = messageWidget;
}
void addCancelButton(Widget? cancelWidget) {
_cancelWidget = cancelWidget;
}
void addTiles(List<Widget> tiles) {
_actionTiles.addAll(tiles);
}
void build() {
showCupertinoModalPopup(
context: _context,
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
builder: (context) => CupertinoActionSheet(
title: _titleWidget,
message: _messageWidget,
actions: _actionTiles,
cancelButton: _cancelWidget,
)
);
}
}
@@ -24,7 +24,9 @@ class AppBarDestinationPickerBuilder {
key: Key('app_bar_destination_picker'),
alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12),
color: Colors.white,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20)),
color: Colors.white),
child: MediaQuery(
data: MediaQueryData(padding: EdgeInsets.zero),
child: Row(
@@ -48,6 +48,7 @@ class EmailController extends BaseController {
final emailContents = <EmailContent>[].obs;
final attachments = <Attachment>[].obs;
EmailId? _currentEmailId;
List<Color>? _currentAvatarColor;
EmailController(
this._getEmailContentInteractor,
@@ -66,6 +67,7 @@ class EmailController extends BaseController {
mailboxDashBoardController.selectedEmail.listen((presentationEmail) {
if (_currentEmailId != presentationEmail?.id) {
_currentEmailId = presentationEmail?.id;
_currentAvatarColor = presentationEmail?.avatarColors;
_clearEmailContent();
final accountId = mailboxDashBoardController.accountId.value;
if (accountId != null && presentationEmail != null) {
@@ -151,7 +153,7 @@ class EmailController extends BaseController {
void _markAsEmailReadSuccess(Success success) {
if (success is MarkAsEmailReadSuccess) {
mailboxDashBoardController.setSelectedEmail(success.updatedEmail.toPresentationEmail(selectMode: SelectMode.ACTIVE));
mailboxDashBoardController.setSelectedEmail(success.updatedEmail.toPresentationEmail(selectMode: SelectMode.ACTIVE, avatarColors: _currentAvatarColor));
}
mailboxDashBoardController.dispatchState(Right(success));
@@ -83,10 +83,10 @@ class EmailView extends GetView {
width: double.infinity,
alignment: Alignment.center,
padding: EdgeInsets.only(
left: responsiveUtils.isMobile(context) ? 16 : 24,
right: responsiveUtils.isMobile(context) ? 16 : 24,
bottom: responsiveUtils.isMobile(context) ? 16 : 24,
top: responsiveUtils.isMobile(context) ? 10 : 16),
left: 16,
right: 16,
bottom: 16,
top: 16),
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
@@ -120,9 +120,9 @@ class EmailView extends GetView {
Widget _buildEmailMessage(BuildContext context) {
return Container(
padding: EdgeInsets.only(
bottom: responsiveUtils.isMobile(context) ? 16 : 24,
left: responsiveUtils.isMobile(context) ? 16 : 24,
right: responsiveUtils.isMobile(context) ? 16 : 24,
bottom: 16,
left: 16,
right: 16,
top: 10),
alignment: Alignment.center,
decoration: BoxDecoration(
@@ -42,7 +42,7 @@ class EmailContentItemBuilder {
padding: EdgeInsets.zero,
child: Text(
_emailContent.content,
style: TextStyle(fontSize: 14, color: AppColor.nameUserColor)));
style: TextStyle(fontSize: 14, color: AppColor.colorNameEmail)));
case EmailContentType.other:
return SizedBox.shrink();
}
@@ -0,0 +1,67 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:model/email/presentation_email.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
enum FilterMessageOption {
all,
unread,
attachments,
starred,
}
extension FilterMessageOptionExtension on FilterMessageOption {
bool filterEmail(PresentationEmail email) {
switch(this) {
case FilterMessageOption.all:
return true;
case FilterMessageOption.unread:
return email.isUnReadEmail();
case FilterMessageOption.attachments:
return email.withAttachments;
case FilterMessageOption.starred:
return email.isFlaggedEmail();
}
}
String getIconToast(ImagePaths imagePaths) {
switch(this) {
case FilterMessageOption.all:
return imagePaths.icFilterMessageAll;
case FilterMessageOption.unread:
return imagePaths.icUnreadToast;
case FilterMessageOption.attachments:
return imagePaths.icFilterMessageAttachments;
case FilterMessageOption.starred:
return imagePaths.icStar;
}
}
String getMessageToast(BuildContext context) {
switch(this) {
case FilterMessageOption.all:
return AppLocalizations.of(context).disable_filter_message_toast;
case FilterMessageOption.unread:
return AppLocalizations.of(context).filter_message_toast(AppLocalizations.of(context).unread);
case FilterMessageOption.attachments:
return AppLocalizations.of(context).filter_message_toast(AppLocalizations.of(context).with_attachments);
case FilterMessageOption.starred:
return AppLocalizations.of(context).filter_message_toast(AppLocalizations.of(context).starred);
}
}
String getTitle(BuildContext context) {
switch(this) {
case FilterMessageOption.all:
return '';
case FilterMessageOption.unread:
return AppLocalizations.of(context).with_unread;
case FilterMessageOption.attachments:
return AppLocalizations.of(context).with_attachments.capitalizeFirstEach;
case FilterMessageOption.starred:
return AppLocalizations.of(context).with_starred;
}
}
}
@@ -39,6 +39,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/mark_as_star_multi
import 'package:tmail_ui_user/features/thread/domain/usecases/refresh_changes_emails_in_mailbox_interactor.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/search_email_interactor.dart';
import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_interactor.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/filter_message_option.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
@@ -63,7 +64,9 @@ class ThreadController extends BaseController {
final emailList = <PresentationEmail>[].obs;
final emailListSearch = <PresentationEmail>[].obs;
final emailListFiltered = <PresentationEmail>[].obs;
final currentSelectMode = SelectMode.INACTIVE.obs;
final filterMessageOption = FilterMessageOption.all.obs;
final random = Random();
@@ -204,7 +207,8 @@ class ThreadController extends BaseController {
void _resetToOriginalValue() {
dispatchState(Right(LoadingState()));
emailList.value = <PresentationEmail>[];
emailList.clear();
emailListFiltered.clear();
canLoadMore = true;
disableSearch();
cancelSelectEmail();
@@ -216,6 +220,12 @@ class ThreadController extends BaseController {
.map((email) => email.asAvatarGradientColor(random))
.toList();
emailList.value = listEmailHaveAvatarGradientColor;
if (isFilterMessagesEnabled) {
final emailsFiltered = listEmailHaveAvatarGradientColor
.where((email) => filterMessageOption.value.filterEmail(email))
.toList();
emailListFiltered.addAll(emailsFiltered);
}
}
void _getAllEmailAction(AccountId accountId, {MailboxId? mailboxId}) {
@@ -283,6 +293,13 @@ class ThreadController extends BaseController {
.map((email) => email.asAvatarGradientColor(random))
.toList();
emailList.addAll(listEmailHaveAvatarGradientColor);
if (isFilterMessagesEnabled) {
final emailsFilteredMore = listEmailHaveAvatarGradientColor
.where((email) => filterMessageOption.value.filterEmail(email))
.toList();
emailListFiltered.addAll(emailsFilteredMore);
}
} else {
canLoadMore = false;
}
@@ -307,9 +324,15 @@ class ThreadController extends BaseController {
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.toList();
} else {
emailList.value = emailList
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.toList();
if (isFilterMessagesEnabled) {
emailListFiltered.value = emailListFiltered
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.toList();
} else {
emailList.value = emailList
.map((email) => email.id == presentationEmailSelected.id ? email.toggleSelect() : email)
.toList();
}
}
if (_isUnSelectedAll()) {
@@ -329,7 +352,11 @@ class ThreadController extends BaseController {
if (isSearchActive()) {
return emailListSearch.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
} else {
return emailList.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
if (isFilterMessagesEnabled) {
return emailListFiltered.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
} else {
return emailList.where((email) => email.selectMode == SelectMode.ACTIVE).toList();
}
}
}
@@ -337,7 +364,11 @@ class ThreadController extends BaseController {
if (isSearchActive()) {
return emailListSearch.every((email) => email.selectMode == SelectMode.INACTIVE);
} else {
return emailList.every((email) => email.selectMode == SelectMode.INACTIVE);
if (isFilterMessagesEnabled) {
return emailListFiltered.every((email) => email.selectMode == SelectMode.INACTIVE);
} else {
return emailList.every((email) => email.selectMode == SelectMode.INACTIVE);
}
}
}
@@ -349,7 +380,11 @@ class ThreadController extends BaseController {
if (isSearchActive()) {
emailListSearch.value = emailListSearch.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
} else {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
if (isFilterMessagesEnabled) {
emailListFiltered.value = emailListFiltered.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
} else {
emailList.value = emailList.map((email) => email.toSelectedEmail(selectMode: SelectMode.INACTIVE)).toList();
}
}
currentSelectMode.value = SelectMode.INACTIVE;
}
@@ -397,6 +432,35 @@ class ThreadController extends BaseController {
_appToast.showErrorToast(AppLocalizations.of(Get.context!).an_error_occurred);
}
void openFilterMessagesCupertinoActionSheet(BuildContext context, List<Widget> actionTiles, {Widget? cancelButton}) {
(CupertinoActionSheetBuilder(context)
..addTiles(actionTiles)
..addCancelButton(cancelButton))
.build();
}
void closeFilterMessageActionSheet() {
popBack();
}
bool get isFilterMessagesEnabled => filterMessageOption != FilterMessageOption.all;
void filterMessagesAction(BuildContext context, FilterMessageOption filterOption) {
popBack();
final newFilterOption = filterMessageOption.value == filterOption ? FilterMessageOption.all : filterOption;
final emailsFiltered = emailList.where((email) => newFilterOption.filterEmail(email)).toList();
emailListFiltered.value = emailsFiltered;
filterMessageOption.value = newFilterOption;
_appToast.showToastWithIcon(
Get.overlayContext!,
message: newFilterOption.getMessageToast(context),
icon: newFilterOption.getIconToast(_imagePaths));
}
void openContextMenuSelectedEmail(BuildContext context, List<Widget> actionTiles) {
(ContextMenuBuilder(context)
..addTiles(actionTiles))
@@ -573,7 +637,7 @@ class ThreadController extends BaseController {
void _searchEmailsSuccess(SearchEmailSuccess success) {
final resultEmailSearchList = success.emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox))
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox, random))
.toList();
emailListSearch.value = resultEmailSearchList;
@@ -597,7 +661,7 @@ class ThreadController extends BaseController {
void _searchMoreEmailsSuccess(SearchMoreEmailSuccess success) {
if (success.emailList.isNotEmpty) {
final resultEmailSearchList = success.emailList
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox))
.map((email) => email.toSearchPresentationEmail(mailboxDashBoardController.mapMailbox, random))
.where((email) => !emailListSearch.contains(email))
.toList();
emailListSearch.addAll(resultEmailSearchList);
@@ -1,14 +1,17 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_email_state.dart';
import 'package:tmail_ui_user/features/thread/domain/state/search_more_email_state.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/filter_message_option.dart';
import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/app_bar_thread_widget_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/bottom_bar_thread_selection_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/filter_message_cupertino_action_sheet_action_builder.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_app_bar_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/search_bar_thread_view_widget.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/suggestion_box_widget.dart';
@@ -146,13 +149,72 @@ class ThreadView extends GetWidget<ThreadController> {
responsiveUtils,
controller.mailboxDashBoardController.selectedMailbox.value,
controller.getListEmailSelected(),
controller.currentSelectMode.value)
controller.currentSelectMode.value,
controller.filterMessageOption.value)
..addOpenListMailboxActionClick(() => controller.openMailboxLeftMenu())
..addOnEditThreadAction(() => controller.enableSelectionEmail())
..addOnFilterEmailAction((filterMessageOption) =>
controller.openFilterMessagesCupertinoActionSheet(
context,
_filterMessagesCupertinoActionTile(context, filterMessageOption),
cancelButton: _buildCupertinoActionCancelButton(context)))
..addOnCancelEditThread(() => controller.cancelSelectEmail()))
.build();
}
List<Widget> _filterMessagesCupertinoActionTile(BuildContext context, FilterMessageOption optionCurrent) {
return <Widget>[
_filterMessageWithAttachmentsAction(context, optionCurrent),
_filterMessagesUnreadAction(context, optionCurrent),
_filterMessageStarredAction(context, optionCurrent),
];
}
Widget _buildCupertinoActionCancelButton(BuildContext context) {
return CupertinoActionSheetAction(
child: Text(
AppLocalizations.of(context).cancel,
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20, color: AppColor.colorTextButton)),
onPressed: () => controller.closeFilterMessageActionSheet(),
);
}
Widget _filterMessageWithAttachmentsAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
Key('filter_attachment_action'),
SvgPicture.asset(imagePaths.icAttachment, width: 28, height: 28, fit: BoxFit.fill, color: AppColor.colorTextButton),
AppLocalizations.of(context).with_attachments,
FilterMessageOption.attachments,
optionCurrent: optionCurrent,
actionSelected: SvgPicture.asset(imagePaths.icFilterSelected, fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build();
}
Widget _filterMessagesUnreadAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
Key('filter_unread_action'),
SvgPicture.asset(imagePaths.icUnreadV2, width: 28, height: 28, fit: BoxFit.fill),
AppLocalizations.of(context).unread,
FilterMessageOption.unread,
optionCurrent: optionCurrent,
actionSelected: SvgPicture.asset(imagePaths.icFilterSelected, fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build();
}
Widget _filterMessageStarredAction(BuildContext context, FilterMessageOption optionCurrent) {
return (FilterMessageCupertinoActionSheetActionBuilder(
Key('filter_starred_action'),
SvgPicture.asset(imagePaths.icStar, width: 28, height: 28, fit: BoxFit.fill),
AppLocalizations.of(context).starred,
FilterMessageOption.starred,
optionCurrent: optionCurrent,
actionSelected: SvgPicture.asset(imagePaths.icFilterSelected, fit: BoxFit.fill))
..onActionClick((option) => controller.filterMessagesAction(context, option)))
.build();
}
// Widget _buildAppBarSelectModeActive(BuildContext context) {
// return (AppBarThreadSelectModeActiveBuilder(
// context,
@@ -318,7 +380,9 @@ class ThreadView extends GetWidget<ThreadController> {
return _buildResultSearchEmails(context, controller.emailListSearch);
}
} else {
return _buildResultListEmail(context, controller.emailList);
return _buildResultListEmail(
context,
controller.isFilterMessagesEnabled ? controller.emailListFiltered : controller.emailList);
}
})
);
@@ -4,9 +4,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:model/model.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/filter_message_option.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnFilterEmailAction = void Function();
typedef OnFilterEmailAction = void Function(FilterMessageOption);
typedef OnEditThreadAction = void Function();
typedef OnOpenListMailboxActionClick = void Function();
typedef OnCancelEditThread = void Function();
@@ -23,6 +24,7 @@ class AppBarThreadWidgetBuilder {
final PresentationMailbox? _presentationMailbox;
final List<PresentationEmail> _listSelectionEmail;
final SelectMode _selectMode;
final FilterMessageOption _filterMessageOption;
AppBarThreadWidgetBuilder(
this._context,
@@ -31,6 +33,7 @@ class AppBarThreadWidgetBuilder {
this._presentationMailbox,
this._listSelectionEmail,
this._selectMode,
this._filterMessageOption,
);
void addOnFilterEmailAction(OnFilterEmailAction onFilterEmailAction) {
@@ -69,9 +72,20 @@ class AppBarThreadWidgetBuilder {
if (_selectMode == SelectMode.ACTIVE)
Positioned(left: 40, child: _buildCountItemSelected()),
Positioned(right: 0, child: _buildFilterButton()),
Padding(
padding: EdgeInsets.only(left: 60, right: 40),
child: _buildContentCenterAppBar()),
_filterMessageOption.getTitle(_context).isNotEmpty
? Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Padding(
padding: EdgeInsets.only(left: 60, right: 40),
child: _buildContentCenterAppBar()),
Transform(
transform: Matrix4.translationValues(-2.0, -8.0, 0.0),
child: Text(
_filterMessageOption.getTitle(_context),
style: TextStyle(fontSize: 11, color: AppColor.colorContentEmail)))
])
: Padding(
padding: EdgeInsets.only(left: 60, right: 40),
child: _buildContentCenterAppBar()),
]
))
])
@@ -103,9 +117,13 @@ class AppBarThreadWidgetBuilder {
child: Padding(
padding: EdgeInsets.only(left: 16),
child: IconButton(
color: AppColor.baseTextColor,
icon: SvgPicture.asset(_imagePaths.icFilter, fit: BoxFit.fill),
onPressed: () => _onFilterEmailAction?.call()
icon: SvgPicture.asset(
_imagePaths.icFilter,
color: _filterMessageOption == FilterMessageOption.all
? AppColor.colorFilterMessageDisabled
: AppColor.colorFilterMessageEnabled,
fit: BoxFit.fill),
onPressed: () => _onFilterEmailAction?.call(_filterMessageOption)
)
)
);
@@ -0,0 +1,51 @@
import 'package:core/core.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/filter_message_option.dart';
class FilterMessageCupertinoActionSheetActionBuilder extends CupertinoActionSheetActionBuilder<FilterMessageOption> {
final FilterMessageOption option;
final FilterMessageOption? optionCurrent;
final SvgPicture? actionSelected;
final Color? bgColor;
FilterMessageCupertinoActionSheetActionBuilder(
Key key,
SvgPicture actionIcon,
String actionName,
this.option,
{
this.optionCurrent,
this.actionSelected,
this.bgColor,
}
) : super(key, actionIcon, actionName);
@override
Widget build() {
return Container(
color: bgColor ?? Colors.white,
child: CupertinoActionSheetAction(
key: key,
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Padding(
padding: EdgeInsets.only(left: 12, right: 16),
child: actionIcon),
Expanded(child: Text(actionName, textAlign: TextAlign.left, style: actionTextStyle())),
if (optionCurrent == option && actionSelected != null)
Padding(
padding: EdgeInsets.only(right: 12),
child: actionSelected!),
]),
onPressed: () {
if (onCupertinoActionSheetActionClick != null) {
onCupertinoActionSheetActionClick!(option);
}
},
),
);
}
}
@@ -544,4 +544,45 @@ class AppLocalizations {
'Search for mailboxes',
name: 'hint_search_mailboxes');
}
String get with_attachments {
return Intl.message(
'With attachments',
name: 'with_attachments'
);
}
String get starred {
return Intl.message(
'Starred',
name: 'starred'
);
}
String filter_message_toast(String filterOption) {
return Intl.message(
'Youve filtered messages by "$filterOption"',
name: 'filter_message_toast',
args: [filterOption]
);
}
String get disable_filter_message_toast {
return Intl.message(
'Youve disabled filtered messages',
name: 'disable_filter_message_toast'
);
}
String get with_unread {
return Intl.message(
'With Unread',
name: 'with_unread');
}
String get with_starred {
return Intl.message(
'With Starred',
name: 'with_starred');
}
}
+2
View File
@@ -90,6 +90,8 @@ class PresentationEmail with EquatableMixin {
bool isFlaggedEmail() => keywords?.containsKey(KeyWordIdentifier.emailFlagged) == true;
bool get withAttachments => hasAttachment == true;
String get mailboxName => mailboxNames?.first?.name ?? '';
@override
+5 -2
View File
@@ -1,4 +1,6 @@
import 'dart:ui';
import 'package:http_parser/http_parser.dart';
import 'package:jmap_dart_client/jmap/core/properties/properties.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
@@ -41,7 +43,7 @@ extension EmailExtension on Email {
);
}
PresentationEmail toPresentationEmail({SelectMode selectMode = SelectMode.INACTIVE}) {
PresentationEmail toPresentationEmail({SelectMode selectMode = SelectMode.INACTIVE, List<Color>? avatarColors}) {
return PresentationEmail(
id,
keywords: keywords,
@@ -57,7 +59,8 @@ extension EmailExtension on Email {
bcc: bcc,
replyTo: replyTo,
mailboxIds: mailboxIds,
selectMode: selectMode
selectMode: selectMode,
avatarColors: avatarColors,
);
}
@@ -111,7 +111,7 @@ extension PresentationEmailExtension on PresentationEmail {
}
}
PresentationEmail toSearchPresentationEmail(Map<MailboxId, PresentationMailbox> mapMailboxes) {
PresentationEmail toSearchPresentationEmail(Map<MailboxId, PresentationMailbox> mapMailboxes, Random random) {
mailboxIds?.removeWhere((key, value) => !value);
final listMailboxId = mailboxIds?.entries
@@ -124,6 +124,8 @@ extension PresentationEmailExtension on PresentationEmail {
.where((mailboxName) => mailboxName != null)
.toList();
final newAvatarColors = AppColor.mapGradientColor[random.nextInt(AppColor.mapGradientColor.length)];
return PresentationEmail(
this.id,
keywords: keywords,
@@ -141,7 +143,7 @@ extension PresentationEmailExtension on PresentationEmail {
mailboxIds: mailboxIds,
mailboxNames: listMailboxName,
selectMode: selectMode,
avatarColors: avatarColors
avatarColors: avatarColors ?? newAvatarColors
);
}