TF-4404 Fix missing subject when perform Mail to attendees action in event email
This commit is contained in:
@@ -7,12 +7,10 @@ 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:model/extensions/utc_date_extension.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
extension EmailActionTypeExtension on EmailActionType {
|
||||
static const String _defaultReplyPrefix = 'Re:';
|
||||
static const String _defaultForwardPrefix = 'Fwd:';
|
||||
|
||||
String getSubjectComposer(BuildContext? context, String subject) {
|
||||
final l10n = context != null ? AppLocalizations.of(context) : null;
|
||||
|
||||
@@ -20,15 +18,15 @@ extension EmailActionTypeExtension on EmailActionType {
|
||||
case EmailActionType.reply:
|
||||
case EmailActionType.replyToList:
|
||||
case EmailActionType.replyAll:
|
||||
return _applyPrefix(
|
||||
return EmailUtils.applyPrefix(
|
||||
subject: subject,
|
||||
defaultPrefix: _defaultReplyPrefix,
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
localizedPrefix: l10n?.prefix_reply_email,
|
||||
);
|
||||
case EmailActionType.forward:
|
||||
return _applyPrefix(
|
||||
return EmailUtils.applyPrefix(
|
||||
subject: subject,
|
||||
defaultPrefix: _defaultForwardPrefix,
|
||||
defaultPrefix: EmailUtils.defaultForwardPrefix,
|
||||
localizedPrefix: l10n?.prefix_forward_email,
|
||||
);
|
||||
case EmailActionType.editDraft:
|
||||
@@ -43,29 +41,6 @@ extension EmailActionTypeExtension on EmailActionType {
|
||||
}
|
||||
}
|
||||
|
||||
String _applyPrefix({
|
||||
required String subject,
|
||||
required String defaultPrefix,
|
||||
String? localizedPrefix,
|
||||
}) {
|
||||
final trimmed = subject.trim();
|
||||
final lowerSubject = trimmed.toLowerCase();
|
||||
|
||||
final prefixes = <String>[
|
||||
defaultPrefix.toLowerCase(),
|
||||
if (localizedPrefix != null) localizedPrefix.toLowerCase(),
|
||||
];
|
||||
|
||||
final hasPrefix = prefixes.any(lowerSubject.startsWith);
|
||||
|
||||
if (hasPrefix) {
|
||||
return subject;
|
||||
}
|
||||
|
||||
final prefix = localizedPrefix ?? defaultPrefix;
|
||||
return '$prefix $subject';
|
||||
}
|
||||
|
||||
String getToastMessageMoveToMailboxSuccess(BuildContext context, {String? destinationPath}) {
|
||||
switch(this) {
|
||||
case EmailActionType.archiveMessage:
|
||||
|
||||
@@ -1499,7 +1499,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
||||
);
|
||||
}
|
||||
|
||||
void handleMailToAttendees(CalendarOrganizer? organizer, List<CalendarAttendee>? attendees) {
|
||||
void handleMailToAttendees(
|
||||
CalendarOrganizer? organizer,
|
||||
List<CalendarAttendee>? attendees,
|
||||
String? eventTitle,
|
||||
) {
|
||||
List<EmailAddress> listEmailAddressAttendees = [];
|
||||
|
||||
if (organizer != null) {
|
||||
@@ -1516,7 +1520,10 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
||||
listEmailAddressAttendees.removeInvalidEmails(ownEmailAddress);
|
||||
log('SingleEmailController::handleMailToAttendees: listEmailAddressMailTo = $listEmailAddressMailTo');
|
||||
mailboxDashBoardController.openComposer(
|
||||
ComposerArguments.fromMailtoUri(listEmailAddress: listEmailAddressMailTo)
|
||||
ComposerArguments.fromMailtoUri(
|
||||
listEmailAddress: listEmailAddressMailTo,
|
||||
subject: eventTitle,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import 'package:jmap_dart_client/jmap/mail/calendar/properties/event_id.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/properties/event_method.dart';
|
||||
import 'package:jmap_dart_client/jmap/mail/calendar/properties/recurrence_rule/recurrence_rule.dart';
|
||||
import 'package:tmail_ui_user/features/email/domain/model/event_action.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
import 'package:tmail_ui_user/main/utils/app_utils.dart';
|
||||
|
||||
@@ -495,4 +496,12 @@ extension CalendarEventExtension on CalendarEvent {
|
||||
excludedCalendarEvents: excludedCalendarEvents ?? this.excludedCalendarEvents,
|
||||
);
|
||||
}
|
||||
|
||||
String getMailToAttendeesEventTitle(AppLocalizations appLocalizations) {
|
||||
return EmailUtils.applyPrefix(
|
||||
subject: title ?? '',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
localizedPrefix: appLocalizations.prefix_reply_email,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,34 @@ class EmailUtils {
|
||||
static const double attachmentItemHeight = 36;
|
||||
static const double attachmentIcon = 20;
|
||||
static const int maxMobileVisibleAttachments = 3;
|
||||
static const String defaultReplyPrefix = 'Re:';
|
||||
static const String defaultForwardPrefix = 'Fwd:';
|
||||
|
||||
EmailUtils._();
|
||||
|
||||
static String applyPrefix({
|
||||
required String subject,
|
||||
required String defaultPrefix,
|
||||
String? localizedPrefix,
|
||||
}) {
|
||||
final trimmed = subject.trim();
|
||||
final lowerSubject = trimmed.toLowerCase();
|
||||
|
||||
final prefixes = <String>[
|
||||
defaultPrefix.toLowerCase(),
|
||||
if (localizedPrefix != null) localizedPrefix.toLowerCase(),
|
||||
];
|
||||
|
||||
final hasPrefix = prefixes.any(lowerSubject.startsWith);
|
||||
|
||||
if (hasPrefix) {
|
||||
return subject;
|
||||
}
|
||||
|
||||
final prefix = localizedPrefix ?? defaultPrefix;
|
||||
return '$prefix $subject';
|
||||
}
|
||||
|
||||
static Properties getPropertiesForEmailGetMethod(Session session, AccountId accountId) {
|
||||
if (CapabilityIdentifier.jamesCalendarEvent.isSupported(session, accountId)) {
|
||||
return ThreadConstants.propertiesCalendarEvent;
|
||||
|
||||
+5
-1
@@ -10,7 +10,11 @@ import 'package:tmail_ui_user/features/email/presentation/styles/calendar_event_
|
||||
import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/event_body_content_widget.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/widgets/calendar_event/event_title_widget.dart';
|
||||
|
||||
typedef OnMailtoAttendeesAction = Function(CalendarOrganizer? organizer, List<CalendarAttendee>? participants);
|
||||
typedef OnMailtoAttendeesAction = Function(
|
||||
CalendarOrganizer? organizer,
|
||||
List<CalendarAttendee>? participants,
|
||||
String? eventTitle,
|
||||
);
|
||||
|
||||
class CalendarEventDetailWidget extends StatelessWidget {
|
||||
|
||||
|
||||
+3
@@ -185,6 +185,9 @@ class CalendarEventInformationWidget extends StatelessWidget {
|
||||
onMailToAttendeesAction: () => onMailtoAttendeesAction?.call(
|
||||
calendarEvent.organizer,
|
||||
calendarEvent.participants,
|
||||
calendarEvent.getMailToAttendeesEventTitle(
|
||||
AppLocalizations.of(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
|
||||
|
||||
void main() {
|
||||
group('EmailUtils::applyPrefix', () {
|
||||
group('Reply prefix', () {
|
||||
test('should add Re: prefix when subject has no prefix', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('Re: Hello'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not add Re: prefix when subject already has Re:', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Re: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('Re: Hello'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not add prefix when subject has Re: case-insensitively', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'RE: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('RE: Hello'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not add prefix when subject has re: lowercase', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 're: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('re: Hello'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Forward prefix', () {
|
||||
test('should add Fwd: prefix when subject has no prefix', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Hello',
|
||||
defaultPrefix: EmailUtils.defaultForwardPrefix,
|
||||
),
|
||||
equals('Fwd: Hello'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not add Fwd: prefix when subject already has Fwd:', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Fwd: Hello',
|
||||
defaultPrefix: EmailUtils.defaultForwardPrefix,
|
||||
),
|
||||
equals('Fwd: Hello'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should not add prefix when subject has FWD: uppercase', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'FWD: Hello',
|
||||
defaultPrefix: EmailUtils.defaultForwardPrefix,
|
||||
),
|
||||
equals('FWD: Hello'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Localized prefix', () {
|
||||
test('should use localized prefix when provided', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
localizedPrefix: 'Rép:',
|
||||
),
|
||||
equals('Rép: Hello'),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'should not add prefix when subject already has localized prefix',
|
||||
() {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Rép: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
localizedPrefix: 'Rép:',
|
||||
),
|
||||
equals('Rép: Hello'),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'should not add prefix when subject has localized prefix '
|
||||
'case-insensitively',
|
||||
() {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'rép: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
localizedPrefix: 'Rép:',
|
||||
),
|
||||
equals('rép: Hello'),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'should not add prefix when subject has default prefix '
|
||||
'even with localized prefix provided',
|
||||
() {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Re: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
localizedPrefix: 'Rép:',
|
||||
),
|
||||
equals('Re: Hello'),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('Edge cases', () {
|
||||
test('should handle empty subject', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: '',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('Re: '),
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle subject with only spaces', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: ' ',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('Re: '),
|
||||
);
|
||||
});
|
||||
|
||||
test('should preserve original subject when prefix already exists', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Re: Hello ',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('Re: Hello '),
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle subject that contains prefix in middle', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: 'Hello Re: World',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals('Re: Hello Re: World'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle subject with leading spaces before prefix', () {
|
||||
expect(
|
||||
EmailUtils.applyPrefix(
|
||||
subject: ' Re: Hello',
|
||||
defaultPrefix: EmailUtils.defaultReplyPrefix,
|
||||
),
|
||||
equals(' Re: Hello'),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user