From 77a62a2711a278728c37dda644cdbf1a78e9b7c6 Mon Sep 17 00:00:00 2001 From: dab246 Date: Fri, 7 Feb 2025 16:42:19 +0700 Subject: [PATCH] TF-3449 Display mark as important icon in email list Signed-off-by: dab246 --- .../extensions/color_extension.dart | 1 + .../create_email_request_extension.dart | 8 ++--- .../extensions/email_cache_extension.dart | 15 ++++++++ .../data/extensions/email_extension.dart | 3 ++ .../thread/data/model/email_cache.dart | 15 ++++++++ .../domain/constants/thread_constants.dart | 19 +++------- .../thread/domain/model/search_email.dart | 6 ++++ .../mixin/base_email_item_tile.dart | 16 +++++++++ .../widgets/email_tile_builder.dart | 2 ++ .../widgets/email_tile_web_builder.dart | 6 ++++ .../lib/email}/mail_priority_header.dart | 10 +++--- model/lib/email/presentation_email.dart | 32 +++++++++++++++++ model/lib/extensions/email_extension.dart | 27 ++++++++++++-- .../presentation_email_extension.dart | 35 +++++++++++++++---- model/lib/model.dart | 1 + 15 files changed, 161 insertions(+), 35 deletions(-) rename {lib/features/composer/presentation/model => model/lib/email}/mail_priority_header.dart (71%) diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index a3a0113a8..d502f3b7a 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -239,6 +239,7 @@ extension AppColor on Color { static const colorMobileSearchFilterButton = Color(0xFFEBEDF0); static const colorContactViewClearFilterButton = Color(0x001C3D0D); static const steelGrayA540 = Color(0xFF55687D); + static const steelGray200 = Color(0xFFAEB7C2); static const blue700 = Color(0xFF208BFF); static const mapGradientColor = [ diff --git a/lib/features/composer/presentation/extensions/create_email_request_extension.dart b/lib/features/composer/presentation/extensions/create_email_request_extension.dart index 9bf6a9498..cc5adc261 100644 --- a/lib/features/composer/presentation/extensions/create_email_request_extension.dart +++ b/lib/features/composer/presentation/extensions/create_email_request_extension.dart @@ -8,13 +8,13 @@ import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.da import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_action_type.dart'; +import 'package:model/email/mail_priority_header.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:tmail_ui_user/features/composer/domain/model/email_request.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/identity_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/create_email_request.dart'; -import 'package:tmail_ui_user/features/composer/presentation/model/mail_priority_header.dart'; import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart'; import 'package:tmail_ui_user/features/mailbox/domain/model/create_new_mailbox_request.dart'; import 'package:tmail_ui_user/features/sending_queue/domain/extensions/sending_email_extension.dart'; @@ -159,13 +159,13 @@ extension CreateEmailRequestExtension on CreateEmailRequest { ? {IndividualHeaderIdentifier.identityHeader: identity?.id?.id.value} : null, xPriorityHeader: isMarkAsImportant - ? {IndividualHeaderIdentifier.xPriorityHeader: MailPriorityHeader.asImportant().xPriority} + ? {IndividualHeaderIdentifier.xPriorityHeader: MailPriorityHeader.firstXPriority} : null, importanceHeader: isMarkAsImportant - ? {IndividualHeaderIdentifier.importanceHeader: MailPriorityHeader.asImportant().importance} + ? {IndividualHeaderIdentifier.importanceHeader: MailPriorityHeader.highImportance} : null, priorityHeader: isMarkAsImportant - ? {IndividualHeaderIdentifier.priorityHeader: MailPriorityHeader.asImportant().priority} + ? {IndividualHeaderIdentifier.priorityHeader: MailPriorityHeader.urgentPriority} : null, ); } diff --git a/lib/features/thread/data/extensions/email_cache_extension.dart b/lib/features/thread/data/extensions/email_cache_extension.dart index 4edb88c50..31d6f9fe7 100644 --- a/lib/features/thread/data/extensions/email_cache_extension.dart +++ b/lib/features/thread/data/extensions/email_cache_extension.dart @@ -36,6 +36,21 @@ extension EmailCacheExtension on EmailCache { ? Map.fromIterables(headerCalendarEvent!.keys.map((value) => IndividualHeaderIdentifier(value)), headerCalendarEvent!.values) : null, blobId: blobId != null ? Id(blobId!) : null, + xPriorityHeader: xPriorityHeader != null + ? Map.fromIterables( + xPriorityHeader!.keys.map((value) => IndividualHeaderIdentifier(value)), + xPriorityHeader!.values) + : null, + importanceHeader: importanceHeader != null + ? Map.fromIterables( + importanceHeader!.keys.map((value) => IndividualHeaderIdentifier(value)), + importanceHeader!.values) + : null, + priorityHeader: priorityHeader != null + ? Map.fromIterables( + priorityHeader!.keys.map((value) => IndividualHeaderIdentifier(value)), + priorityHeader!.values) + : null, ); } diff --git a/lib/features/thread/data/extensions/email_extension.dart b/lib/features/thread/data/extensions/email_extension.dart index d5c6166bc..afda4747c 100644 --- a/lib/features/thread/data/extensions/email_extension.dart +++ b/lib/features/thread/data/extensions/email_extension.dart @@ -26,6 +26,9 @@ extension EmailExtension on Email { mailboxIds: mailboxIds?.toMapString(), headerCalendarEvent: headerCalendarEvent?.toMapString(), blobId: blobId?.value, + xPriorityHeader: xPriorityHeader?.toMapString(), + importanceHeader: importanceHeader?.toMapString(), + priorityHeader: priorityHeader?.toMapString(), ); } diff --git a/lib/features/thread/data/model/email_cache.dart b/lib/features/thread/data/model/email_cache.dart index 6218d7505..989628ca4 100644 --- a/lib/features/thread/data/model/email_cache.dart +++ b/lib/features/thread/data/model/email_cache.dart @@ -57,6 +57,15 @@ class EmailCache extends HiveObject with EquatableMixin { @HiveField(15) final String? blobId; + @HiveField(16) + Map? xPriorityHeader; + + @HiveField(17) + Map? importanceHeader; + + @HiveField(18) + Map? priorityHeader; + EmailCache( this.id, { @@ -75,6 +84,9 @@ class EmailCache extends HiveObject with EquatableMixin { this.mailboxIds, this.headerCalendarEvent, this.blobId, + this.xPriorityHeader, + this.importanceHeader, + this.priorityHeader, } ); @@ -96,5 +108,8 @@ class EmailCache extends HiveObject with EquatableMixin { mailboxIds, headerCalendarEvent, blobId, + xPriorityHeader, + importanceHeader, + priorityHeader, ]; } \ No newline at end of file diff --git a/lib/features/thread/domain/constants/thread_constants.dart b/lib/features/thread/domain/constants/thread_constants.dart index a7ca6aaea..e4cc44cb8 100644 --- a/lib/features/thread/domain/constants/thread_constants.dart +++ b/lib/features/thread/domain/constants/thread_constants.dart @@ -22,6 +22,9 @@ class ThreadConstants { EmailProperty.hasAttachment, EmailProperty.replyTo, EmailProperty.mailboxIds, + IndividualHeaderIdentifier.xPriorityHeader.value, + IndividualHeaderIdentifier.importanceHeader.value, + IndividualHeaderIdentifier.priorityHeader.value, }); static final propertiesUpdatedDefault = Properties({ EmailProperty.keywords, @@ -64,21 +67,7 @@ class ThreadConstants { }); static final propertiesCalendarEvent = Properties({ - EmailProperty.id, - EmailProperty.blobId, - EmailProperty.subject, - EmailProperty.from, - EmailProperty.to, - EmailProperty.cc, - EmailProperty.bcc, - EmailProperty.keywords, - EmailProperty.size, - EmailProperty.receivedAt, - EmailProperty.sentAt, - EmailProperty.preview, - EmailProperty.hasAttachment, - EmailProperty.replyTo, - EmailProperty.mailboxIds, + ...propertiesDefault.value, IndividualHeaderIdentifier.headerCalendarEvent.value, }); diff --git a/lib/features/thread/domain/model/search_email.dart b/lib/features/thread/domain/model/search_email.dart index 4b995ac08..eee63a9a7 100644 --- a/lib/features/thread/domain/model/search_email.dart +++ b/lib/features/thread/domain/model/search_email.dart @@ -34,6 +34,9 @@ class SearchEmail extends Email { super.headerUserAgent, super.headerMdn, super.headerCalendarEvent, + super.xPriorityHeader, + super.importanceHeader, + super.priorityHeader, super.sMimeStatusHeader, super.identityHeader, required this.searchSnippetSubject, @@ -82,6 +85,9 @@ class SearchEmail extends Email { headerUserAgent: email.headerUserAgent, headerMdn: email.headerMdn, headerCalendarEvent: email.headerCalendarEvent, + xPriorityHeader: email.xPriorityHeader, + importanceHeader: email.importanceHeader, + priorityHeader: email.priorityHeader, sMimeStatusHeader: email.sMimeStatusHeader, identityHeader: email.identityHeader, searchSnippetSubject: searchSnippetSubject, diff --git a/lib/features/thread/presentation/mixin/base_email_item_tile.dart b/lib/features/thread/presentation/mixin/base_email_item_tile.dart index 2f386e15d..3a84cabb4 100644 --- a/lib/features/thread/presentation/mixin/base_email_item_tile.dart +++ b/lib/features/thread/presentation/mixin/base_email_item_tile.dart @@ -354,4 +354,20 @@ mixin BaseEmailItemTile { ), ); } + + Widget buildMarkAsImportantIcon(BuildContext context) { + return Padding( + padding: ItemEmailTileStyles.getSpaceCalendarEventIcon( + context, + responsiveUtils, + ), + child: SvgPicture.asset( + imagePaths.icMarkAsImportant, + width: 20, + height: 20, + fit: BoxFit.fill, + colorFilter: AppColor.steelGray200.asFilter(), + ), + ); + } } \ No newline at end of file diff --git a/lib/features/thread/presentation/widgets/email_tile_builder.dart b/lib/features/thread/presentation/widgets/email_tile_builder.dart index 61023db49..752a65420 100644 --- a/lib/features/thread/presentation/widgets/email_tile_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_builder.dart @@ -104,6 +104,8 @@ class EmailTileBuilder extends StatelessWidget with BaseEmailItemTile { children: [ if (presentationEmail.hasCalendarEvent) buildCalendarEventIcon(context: context, presentationEmail: presentationEmail), + if (presentationEmail.isMarkAsImportant) + buildMarkAsImportantIcon(context), Expanded(child: buildEmailTitle( context, presentationEmail, diff --git a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart index abb8241a4..a114f3d28 100644 --- a/lib/features/thread/presentation/widgets/email_tile_web_builder.dart +++ b/lib/features/thread/presentation/widgets/email_tile_web_builder.dart @@ -140,6 +140,8 @@ class _EmailTileBuilderState extends State with BaseEmailItem context: context, presentationEmail: widget.presentationEmail ), + if (widget.presentationEmail.isMarkAsImportant) + buildMarkAsImportantIcon(context), Expanded( child: buildEmailTitle( context, @@ -257,6 +259,8 @@ class _EmailTileBuilderState extends State with BaseEmailItem context: context, presentationEmail: widget.presentationEmail ), + if (widget.presentationEmail.isMarkAsImportant) + buildMarkAsImportantIcon(context), Expanded( child: buildEmailTitle( context, @@ -611,6 +615,8 @@ class _EmailTileBuilderState extends State with BaseEmailItem return Row(children: [ if (widget.presentationEmail.hasCalendarEvent) buildCalendarEventIcon(context: context, presentationEmail: widget.presentationEmail), + if (widget.presentationEmail.isMarkAsImportant) + buildMarkAsImportantIcon(context), if (widget.presentationEmail.getEmailTitle().isNotEmpty) Container( constraints: BoxConstraints(maxWidth: constraints.maxWidth / 2), diff --git a/lib/features/composer/presentation/model/mail_priority_header.dart b/model/lib/email/mail_priority_header.dart similarity index 71% rename from lib/features/composer/presentation/model/mail_priority_header.dart rename to model/lib/email/mail_priority_header.dart index 518b8fbc0..40282ce4d 100644 --- a/lib/features/composer/presentation/model/mail_priority_header.dart +++ b/model/lib/email/mail_priority_header.dart @@ -2,6 +2,10 @@ import 'package:equatable/equatable.dart'; class MailPriorityHeader with EquatableMixin { + static const String firstXPriority = '1'; + static const String highImportance = 'high'; + static const String urgentPriority = 'urgent'; + final String? xPriority; final String? importance; final String? priority; @@ -12,12 +16,6 @@ class MailPriorityHeader with EquatableMixin { this.priority, }); - factory MailPriorityHeader.asImportant() => MailPriorityHeader( - xPriority: '1', - importance: 'high', - priority: 'urgent', - ); - @override List get props => [ xPriority, diff --git a/model/lib/email/presentation_email.dart b/model/lib/email/presentation_email.dart index d3ec44432..23aff6334 100644 --- a/model/lib/email/presentation_email.dart +++ b/model/lib/email/presentation_email.dart @@ -13,6 +13,7 @@ import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.da import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_content.dart'; +import 'package:model/email/mail_priority_header.dart'; import 'package:model/extensions/email_address_extension.dart'; import 'package:model/extensions/keyword_identifier_extension.dart'; import 'package:model/extensions/media_type_nullable_extension.dart'; @@ -44,6 +45,9 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin { final Set? htmlBody; final Map? bodyValues; final Map? headerCalendarEvent; + final Map? xPriorityHeader; + final Map? importanceHeader; + final Map? priorityHeader; PresentationEmail({ this.id, @@ -68,6 +72,9 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin { this.htmlBody, this.bodyValues, this.headerCalendarEvent, + this.xPriorityHeader, + this.importanceHeader, + this.priorityHeader, }); String getSenderName() { @@ -135,6 +142,22 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin { bool get hasCalendarEvent => headerCalendarEvent?[IndividualHeaderIdentifier.headerCalendarEvent]?.isNotEmpty == true; + bool get isMarkAsImportant { + final xPriority = xPriorityHeader?[IndividualHeaderIdentifier.xPriorityHeader] + ?.trim() + .toLowerCase(); + final importance = importanceHeader?[IndividualHeaderIdentifier.importanceHeader] + ?.trim() + .toLowerCase(); + final priority = priorityHeader?[IndividualHeaderIdentifier.priorityHeader] + ?.trim() + .toLowerCase(); + + return xPriority == MailPriorityHeader.firstXPriority && + importance == MailPriorityHeader.highImportance && + priority == MailPriorityHeader.urgentPriority; + } + List get emailContentList { final newHtmlBody = htmlBody ?.where((emailBody) => emailBody.partId != null && emailBody.type != null) @@ -175,6 +198,9 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin { headerCalendarEvent, searchSnippetSubject, searchSnippetPreview, + xPriorityHeader, + importanceHeader, + priorityHeader, ]; PresentationEmail copyWith({ @@ -200,6 +226,9 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin { Set? htmlBody, Map? bodyValues, Map? headerCalendarEvent, + Map? xPriorityHeader, + Map? importanceHeader, + Map? priorityHeader, }) { return PresentationEmail( id: id ?? this.id, @@ -224,6 +253,9 @@ class PresentationEmail with EquatableMixin, SearchSnippetMixin { htmlBody: htmlBody ?? this.htmlBody, bodyValues: bodyValues ?? this.bodyValues, headerCalendarEvent: headerCalendarEvent ?? this.headerCalendarEvent, + xPriorityHeader: xPriorityHeader ?? this.xPriorityHeader, + importanceHeader: importanceHeader ?? this.importanceHeader, + priorityHeader: priorityHeader ?? this.priorityHeader, ); } } \ No newline at end of file diff --git a/model/lib/extensions/email_extension.dart b/model/lib/extensions/email_extension.dart index fefdee347..1ca90c25c 100644 --- a/model/lib/extensions/email_extension.dart +++ b/model/lib/extensions/email_extension.dart @@ -102,7 +102,10 @@ extension EmailExtension on Email { bodyValues: bodyValues, headerUserAgent: headerUserAgent, attachments: attachments, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ); } @@ -129,7 +132,10 @@ extension EmailExtension on Email { mailboxIds: mailboxIds, selectMode: selectMode, emailHeader: headers?.toList(), - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; @@ -153,6 +159,15 @@ extension EmailExtension on Email { replyTo: updatedProperties.contain(EmailProperty.replyTo) ? newEmail.replyTo : replyTo, mailboxIds: updatedProperties.contain(EmailProperty.mailboxIds) ? newEmail.mailboxIds : mailboxIds, headerCalendarEvent: updatedProperties.contain(IndividualHeaderIdentifier.headerCalendarEvent.value) ? newEmail.headerCalendarEvent : headerCalendarEvent, + xPriorityHeader: updatedProperties.contain(IndividualHeaderIdentifier.xPriorityHeader.value) + ? newEmail.xPriorityHeader + : xPriorityHeader, + importanceHeader: updatedProperties.contain(IndividualHeaderIdentifier.importanceHeader.value) + ? newEmail.importanceHeader + : importanceHeader, + priorityHeader: updatedProperties.contain(IndividualHeaderIdentifier.priorityHeader.value) + ? newEmail.priorityHeader + : priorityHeader, ); } @@ -213,7 +228,10 @@ extension EmailExtension on Email { emailHeader: headers?.toList(), bodyValues: bodyValues, htmlBody: htmlBody, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ); } @@ -250,6 +268,9 @@ extension EmailExtension on Email { headerUserAgent: headerUserAgent, headerMdn: value, headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ); } } \ No newline at end of file diff --git a/model/lib/extensions/presentation_email_extension.dart b/model/lib/extensions/presentation_email_extension.dart index 55decbcc8..d65ba4c99 100644 --- a/model/lib/extensions/presentation_email_extension.dart +++ b/model/lib/extensions/presentation_email_extension.dart @@ -80,7 +80,10 @@ extension PresentationEmailExtension on PresentationEmail { selectMode: selectMode == SelectMode.INACTIVE ? SelectMode.ACTIVE : SelectMode.INACTIVE, routeWeb: routeWeb, mailboxContain: mailboxContain, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; @@ -106,7 +109,10 @@ extension PresentationEmailExtension on PresentationEmail { selectMode: selectMode, routeWeb: routeWeb, mailboxContain: mailboxContain, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; @@ -132,7 +138,10 @@ extension PresentationEmailExtension on PresentationEmail { bodyValues: bodyValues, mailboxIds: mailboxIds, headers: emailHeader?.toSet(), - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ); } @@ -165,7 +174,10 @@ extension PresentationEmailExtension on PresentationEmail { selectMode: selectMode, routeWeb: routeWeb, mailboxContain: matchedMailbox, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; @@ -204,7 +216,10 @@ extension PresentationEmailExtension on PresentationEmail { selectMode: selectMode, routeWeb: routeWeb, mailboxContain: mailboxContain, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; @@ -233,7 +248,10 @@ extension PresentationEmailExtension on PresentationEmail { selectMode: selectMode, routeWeb: routeWeb, mailboxContain: mailboxContain, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; @@ -259,7 +277,10 @@ extension PresentationEmailExtension on PresentationEmail { selectMode: selectMode, routeWeb: routeWeb, mailboxContain: mailboxContain, - headerCalendarEvent: headerCalendarEvent + headerCalendarEvent: headerCalendarEvent, + xPriorityHeader: xPriorityHeader, + importanceHeader: importanceHeader, + priorityHeader: priorityHeader, ) ..searchSnippetSubject = searchSnippetSubject ..searchSnippetPreview = searchSnippetPreview; diff --git a/model/lib/model.dart b/model/lib/model.dart index 00f905bb3..0ba1bc3c6 100644 --- a/model/lib/model.dart +++ b/model/lib/model.dart @@ -25,6 +25,7 @@ export 'email/prefix_email_address.dart'; export 'email/presentation_email.dart'; export 'email/presentation_email_address.dart'; export 'email/read_actions.dart'; +export 'email/mail_priority_header.dart'; export 'extensions/account_extension.dart'; export 'extensions/account_id_extensions.dart'; export 'extensions/attachment_extension.dart';