Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TF-3413 Handle mailing list replies #3415

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/features/composer/domain/model/email_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ class EmailRequest with EquatableMixin {
];

bool get isEmailAnswered => emailIdAnsweredOrForwarded != null &&
(emailActionType == EmailActionType.reply || emailActionType == EmailActionType.replyAll);
(emailActionType == EmailActionType.reply
|| emailActionType == EmailActionType.replyToList
|| emailActionType == EmailActionType.replyAll);

bool get isEmailForwarded => emailIdAnsweredOrForwarded != null && emailActionType == EmailActionType.forward;
}
38 changes: 17 additions & 21 deletions lib/features/composer/presentation/composer_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:jmap_dart_client/jmap/mail/email/email.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:jmap_dart_client/jmap/mail/email/individual_header_identifier.dart';
import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart';
import 'package:model/model.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:pointer_interceptor/pointer_interceptor.dart';
Expand Down Expand Up @@ -74,6 +73,7 @@ import 'package:tmail_ui_user/features/email/domain/state/get_email_content_stat
import 'package:tmail_ui_user/features/email/domain/state/transform_html_email_content_state.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart';
import 'package:tmail_ui_user/features/email/domain/usecases/transform_html_email_content_interactor.dart';
import 'package:tmail_ui_user/features/email/presentation/extensions/presentation_email_extension.dart';
import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
Expand Down Expand Up @@ -640,11 +640,13 @@ class ComposerController extends BaseController
_updateStatusEmailSendButton();
break;
case EmailActionType.reply:
case EmailActionType.replyToList:
case EmailActionType.replyAll:
log('ComposerController::_initEmail:listPost = ${arguments.listPost}');
_initEmailAddress(
presentationEmail: arguments.presentationEmail!,
actionType: arguments.emailActionType,
mailboxRole: arguments.presentationEmail!.mailboxContain?.role ?? mailboxDashBoardController.selectedMailbox.value?.role
listPost: arguments.listPost,
);
_initSubjectEmail(
presentationEmail: arguments.presentationEmail!,
Expand Down Expand Up @@ -797,29 +799,23 @@ class ComposerController extends BaseController
void _initEmailAddress({
required PresentationEmail presentationEmail,
required EmailActionType actionType,
Role? mailboxRole,
String? listPost,
}) {
final userName = mailboxDashBoardController.sessionCurrent?.username.value;
final isSender = presentationEmail.from
.asList()
.any((element) => element.emailAddress.isNotEmpty && element.emailAddress == userName);

final recipients = presentationEmail.generateRecipientsEmailAddressForComposer(
emailActionType: actionType,
mailboxRole: mailboxRole
isSender: isSender,
userName: userName,
listPost: listPost,
);
final userName = mailboxDashBoardController.sessionCurrent?.username;
if (userName != null) {
final isSender = presentationEmail.from.asList().every((element) => element.email == userName.value);
if (isSender) {
listToEmailAddress = List.from(recipients.value1.toSet());
listCcEmailAddress = List.from(recipients.value2.toSet());
listBccEmailAddress = List.from(recipients.value3.toSet());
} else {
listToEmailAddress = List.from(recipients.value1.toSet().filterEmailAddress(userName.value));
listCcEmailAddress = List.from(recipients.value2.toSet().filterEmailAddress(userName.value));
listBccEmailAddress = List.from(recipients.value3.toSet().filterEmailAddress(userName.value));
}
} else {
listToEmailAddress = List.from(recipients.value1.toSet());
listCcEmailAddress = List.from(recipients.value2.toSet());
listBccEmailAddress = List.from(recipients.value3.toSet());
}

listToEmailAddress = List.from(recipients.value1);
listCcEmailAddress = List.from(recipients.value2);
listBccEmailAddress = List.from(recipients.value3);

if (listToEmailAddress.isNotEmpty || listCcEmailAddress.isNotEmpty || listBccEmailAddress.isNotEmpty) {
isInitialRecipient.value = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ extension CreateEmailRequestExtension on CreateEmailRequest {

MessageIdsHeaderValue? createInReplyTo() {
if (emailActionType == EmailActionType.reply ||
emailActionType == EmailActionType.replyToList ||
emailActionType == EmailActionType.replyAll
) {
return messageId;
Expand All @@ -83,6 +84,7 @@ extension CreateEmailRequestExtension on CreateEmailRequest {

MessageIdsHeaderValue? createReferences() {
if (emailActionType == EmailActionType.reply ||
emailActionType == EmailActionType.replyToList ||
emailActionType == EmailActionType.replyAll ||
emailActionType == EmailActionType.forward
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extension EmailActionTypeExtension on EmailActionType {
String getSubjectComposer(BuildContext? context, String subject) {
switch(this) {
case EmailActionType.reply:
case EmailActionType.replyToList:
case EmailActionType.replyAll:
if (subject.toLowerCase().startsWith('re:')) {
return subject;
Expand Down Expand Up @@ -60,6 +61,7 @@ extension EmailActionTypeExtension on EmailActionType {
final languageTag = locale.toLanguageTag();
switch(this) {
case EmailActionType.reply:
case EmailActionType.replyToList:
case EmailActionType.replyAll:
final receivedAt = presentationEmail.receivedAt;
final emailAddress = presentationEmail.from.toEscapeHtmlStringUseCommaSeparator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class MobileEditorView extends StatelessWidget with EditorViewMixin {
}
);
case EmailActionType.reply:
case EmailActionType.replyToList:
case EmailActionType.replyAll:
case EmailActionType.forward:
if (contentViewState == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class WebEditorView extends StatelessWidget with EditorViewMixin {
}
);
case EmailActionType.reply:
case EmailActionType.replyToList:
case EmailActionType.replyAll:
case EmailActionType.forward:
if (contentViewState == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,21 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: currentEmailLoaded.value?.emailCurrent?.messageId,
references: currentEmailLoaded.value?.emailCurrent?.references,
listPost: currentEmailLoaded.value?.emailCurrent?.listPost,
)
);
break;
case EmailActionType.replyToList:
log('SingleEmailController::pressEmailAction:replyToList');
mailboxDashBoardController.goToComposer(
ComposerArguments.replyToListEmail(
presentationEmail: presentationEmail,
content: currentEmailLoaded.value?.htmlContent ?? '',
inlineImages: currentEmailLoaded.value?.inlineImages ?? [],
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: currentEmailLoaded.value?.emailCurrent?.messageId,
references: currentEmailLoaded.value?.emailCurrent?.references,
listPost: currentEmailLoaded.value?.emailCurrent?.listPost,
)
);
break;
Expand All @@ -1434,6 +1449,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: currentEmailLoaded.value?.emailCurrent?.messageId,
references: currentEmailLoaded.value?.emailCurrent?.references,
listPost: currentEmailLoaded.value?.emailCurrent?.listPost,
)
);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

import 'package:dartz/dartz.dart';
import 'package:jmap_dart_client/jmap/mail/email/email_address.dart';
import 'package:model/email/email_action_type.dart';
import 'package:model/email/presentation_email.dart';
import 'package:model/extensions/list_email_address_extension.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';

extension PresentationEmailExtension on PresentationEmail {
Tuple3<List<EmailAddress>, List<EmailAddress>, List<EmailAddress>> generateRecipientsEmailAddressForComposer({
required EmailActionType emailActionType,
bool isSender = false,
String? userName,
String? listPost,
}) {
final newFromAddress = from.removeDuplicateEmails();
final newToAddress = to.removeDuplicateEmails();
final newCcAddress = cc.removeDuplicateEmails();
final newBccAddress = bcc.removeDuplicateEmails();
final newReplyToAddress = replyTo.removeDuplicateEmails();

switch (emailActionType) {
case EmailActionType.reply:
final listReplyAddress = isSender ? newToAddress : newFromAddress;
final listReplyAddressWithoutUsername = listReplyAddress.withoutMe(userName);

return Tuple3(listReplyAddressWithoutUsername, [], []);
case EmailActionType.replyToList:
final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? '');

final listToAddressWithoutUsername = recipientRecord.toMailAddresses
.toSet()
.removeDuplicateEmails()
.withoutMe(userName);

final listCcAddressWithoutUsername = recipientRecord.ccMailAddresses
.toSet()
.removeDuplicateEmails()
.withoutMe(userName);

final listBccAddressWithoutUsername = recipientRecord.bccMailAddresses
.toSet()
.removeDuplicateEmails()
.withoutMe(userName);

return Tuple3(
listToAddressWithoutUsername,
listCcAddressWithoutUsername,
listBccAddressWithoutUsername,
);
case EmailActionType.replyAll:
final recipientRecord = EmailUtils.extractRecipientsFromListPost(listPost ?? '');

final listToAddress = recipientRecord.toMailAddresses
+ newReplyToAddress
+ newFromAddress
+ newToAddress;
final listCcAddress = recipientRecord.ccMailAddresses + newCcAddress;
final listBccAddress = recipientRecord.bccMailAddresses + newBccAddress;

final listToAddressWithoutUsername = listToAddress
.toSet()
.removeDuplicateEmails()
.withoutMe(userName);
final listCcAddressWithoutUsername = listCcAddress
.toSet()
.removeDuplicateEmails()
.withoutMe(userName);
final listBccAddressWithoutUsername = listBccAddress
.toSet()
.removeDuplicateEmails()
.withoutMe(userName);

return Tuple3(
listToAddressWithoutUsername,
listCcAddressWithoutUsername,
listBccAddressWithoutUsername,
);
default:
final listToAddressWithoutUsername = newToAddress.withoutMe(userName);
final listCcAddressWithoutUsername = newCcAddress.withoutMe(userName);
final listBccAddressWithoutUsername = newBccAddress.withoutMe(userName);

return Tuple3(
listToAddressWithoutUsername,
listCcAddressWithoutUsername,
listBccAddressWithoutUsername,
);
}
}
}
28 changes: 28 additions & 0 deletions lib/features/email/presentation/model/composer_arguments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ComposerArguments extends RouterArguments {
final ScreenDisplayMode displayMode;
final List<EmailAddress>? cc;
final List<EmailAddress>? bcc;
final String? listPost;

ComposerArguments({
this.emailActionType = EmailActionType.compose,
Expand All @@ -54,6 +55,7 @@ class ComposerArguments extends RouterArguments {
this.displayMode = ScreenDisplayMode.normal,
this.cc,
this.bcc,
this.listPost,
});

factory ComposerArguments.fromSendingEmail(SendingEmail sendingEmail) =>
Expand Down Expand Up @@ -120,6 +122,7 @@ class ComposerArguments extends RouterArguments {
Role? mailboxRole,
MessageIdsHeaderValue? messageId,
MessageIdsHeaderValue? references,
String? listPost,
}) => ComposerArguments(
emailActionType: EmailActionType.reply,
presentationEmail: presentationEmail,
Expand All @@ -128,6 +131,26 @@ class ComposerArguments extends RouterArguments {
mailboxRole: mailboxRole,
messageId: messageId,
references: references,
listPost: listPost,
);

factory ComposerArguments.replyToListEmail({
required PresentationEmail presentationEmail,
required String content,
required List<Attachment> inlineImages,
Role? mailboxRole,
MessageIdsHeaderValue? messageId,
MessageIdsHeaderValue? references,
String? listPost,
}) => ComposerArguments(
emailActionType: EmailActionType.replyToList,
presentationEmail: presentationEmail,
emailContents: content,
inlineImages: inlineImages,
mailboxRole: mailboxRole,
messageId: messageId,
references: references,
listPost: listPost,
);

factory ComposerArguments.replyAllEmail({
Expand All @@ -137,6 +160,7 @@ class ComposerArguments extends RouterArguments {
Role? mailboxRole,
MessageIdsHeaderValue? messageId,
MessageIdsHeaderValue? references,
String? listPost,
}) => ComposerArguments(
emailActionType: EmailActionType.replyAll,
presentationEmail: presentationEmail,
Expand All @@ -145,6 +169,7 @@ class ComposerArguments extends RouterArguments {
mailboxRole: mailboxRole,
messageId: messageId,
references: references,
listPost: listPost,
);

factory ComposerArguments.forwardEmail({
Expand Down Expand Up @@ -206,6 +231,7 @@ class ComposerArguments extends RouterArguments {
displayMode,
cc,
bcc,
listPost,
];

ComposerArguments copyWith({
Expand All @@ -229,6 +255,7 @@ class ComposerArguments extends RouterArguments {
ScreenDisplayMode? displayMode,
List<EmailAddress>? cc,
List<EmailAddress>? bcc,
String? listPost,
}) {
return ComposerArguments(
emailActionType: emailActionType ?? this.emailActionType,
Expand All @@ -251,6 +278,7 @@ class ComposerArguments extends RouterArguments {
displayMode: displayMode ?? this.displayMode,
cc: cc ?? this.cc,
bcc: bcc ?? this.bcc,
listPost: listPost ?? this.listPost,
);
}
}
Loading
Loading