TF-3221 Handle mailto with additional cc and bcc
This commit is contained in:
@@ -18,13 +18,13 @@ Summary of URI schemes that can interact with Twake Mail:
|
|||||||
|
|
||||||
- `/mailto?uri=user@example.com`
|
- `/mailto?uri=user@example.com`
|
||||||
- `/mailto/?uri=mailto:user@example.com&subject=TwakeMail&body=HelloWorld`
|
- `/mailto/?uri=mailto:user@example.com&subject=TwakeMail&body=HelloWorld`
|
||||||
- `/mailto/?uri=mailto:user1@example.com,user2@example.com,user3@example.com&subject=TwakeMail&body=HelloWorld`
|
- `/mailto/?uri=mailto:user1@example.com,user2@example.com,user3@example.com&to=user1@example.com,user2@example.com,user3@example.com&cc=user1@example.com,user2@example.com,user3@example.com&bcc=user1@example.com,user2@example.com,user3@example.com&subject=TwakeMail&body=HelloWorld`
|
||||||
|
|
||||||
2. URI scheme encoded
|
2. URI scheme encoded
|
||||||
|
|
||||||
- `%2Fmailto%3Furi%3Duser%40example.com`
|
- `%2Fmailto%3Furi%3Duser%40example.com`
|
||||||
- `%2Fmailto%2F%3Furi%3Dmailto%3Auser%40example.com%26subject%3DTwakeMail%26body%3DHelloWorld`
|
- `%2Fmailto%2F%3Furi%3Dmailto%3Auser%40example.com%26subject%3DTwakeMail%26body%3DHelloWorld`
|
||||||
- `%2Fmailto%2F%3Furi%3Dmailto%3Auser1%40example.com%2Cuser2%40example.com%2Cuser3%40example.com%26subject%3DTwakeMail%26body%3DHelloWorld`
|
- `%2Fmailto%2F%3Furi%3Dmailto%3Auser1%40example.com%2Cuser2%40example.com%2Cuser3%40example.com%26to=user1%40example.com%2Cuser2%40example.com%2Cuser3%40example.com%26cc=user1%40example.com%2Cuser2%40example.com%2Cuser3%40example.com%26bcc=user1%40example.com%2Cuser2%40example.com%2Cuser3%40example.com%26subject%3DTwakeMail%26body%3DHelloWorld`
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
|
|||||||
@@ -629,6 +629,16 @@ class ComposerController extends BaseController
|
|||||||
isInitialRecipient.value = true;
|
isInitialRecipient.value = true;
|
||||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
}
|
}
|
||||||
|
if (arguments.cc?.isNotEmpty == true) {
|
||||||
|
listCcEmailAddress = arguments.cc!;
|
||||||
|
ccRecipientState.value = PrefixRecipientState.enabled;
|
||||||
|
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
|
}
|
||||||
|
if (arguments.bcc?.isNotEmpty == true) {
|
||||||
|
bccRecipientState.value = PrefixRecipientState.enabled;
|
||||||
|
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
|
listBccEmailAddress = arguments.bcc!;
|
||||||
|
}
|
||||||
_getEmailContentFromMailtoUri(arguments.body ?? '');
|
_getEmailContentFromMailtoUri(arguments.body ?? '');
|
||||||
_updateStatusEmailSendButton();
|
_updateStatusEmailSendButton();
|
||||||
break;
|
break;
|
||||||
@@ -1729,10 +1739,15 @@ class ComposerController extends BaseController
|
|||||||
if (bccRecipientState.value == PrefixRecipientState.disabled) {
|
if (bccRecipientState.value == PrefixRecipientState.disabled) {
|
||||||
bccRecipientState.value = PrefixRecipientState.enabled;
|
bccRecipientState.value = PrefixRecipientState.enabled;
|
||||||
}
|
}
|
||||||
listBccEmailAddress = listEmailAddress.toList();
|
if (composerArguments.value?.emailActionType == EmailActionType.composeFromMailtoUri) {
|
||||||
|
listBccEmailAddress = {...listEmailAddress, ...?composerArguments.value?.bcc}.toList();
|
||||||
|
} else {
|
||||||
|
listBccEmailAddress = listEmailAddress.toList();
|
||||||
|
}
|
||||||
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
toAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
ccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
bccAddressExpandMode.value = ExpandMode.COLLAPSE;
|
||||||
|
bccAddressExpandMode.refresh();
|
||||||
_updateStatusEmailSendButton();
|
_updateStatusEmailSendButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1159,13 +1159,21 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> openMailToLink(Uri? uri) async {
|
Future<void> openMailToLink(Uri? uri) async {
|
||||||
|
if (uri == null) return;
|
||||||
|
|
||||||
|
final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(uri.toString());
|
||||||
log('SingleEmailController::openMailToLink(): ${uri.toString()}');
|
log('SingleEmailController::openMailToLink(): ${uri.toString()}');
|
||||||
String address = uri?.path ?? '';
|
if (!RouteUtils.canOpenComposerFromNavigationRouter(navigationRouter)) return;
|
||||||
log('SingleEmailController::openMailToLink(): address: $address');
|
|
||||||
if (address.isNotEmpty) {
|
mailboxDashBoardController.goToComposer(
|
||||||
final emailAddress = EmailAddress(null, address);
|
ComposerArguments.fromMailtoUri(
|
||||||
mailboxDashBoardController.goToComposer(ComposerArguments.fromEmailAddress(emailAddress));
|
listEmailAddress: navigationRouter.listEmailAddress,
|
||||||
}
|
cc: navigationRouter.cc,
|
||||||
|
bcc: navigationRouter.bcc,
|
||||||
|
subject: navigationRouter.subject,
|
||||||
|
body: navigationRouter.body
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteEmailPermanently(BuildContext context, PresentationEmail email) {
|
void deleteEmailPermanently(BuildContext context, PresentationEmail email) {
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
final List<Attachment>? inlineImages;
|
final List<Attachment>? inlineImages;
|
||||||
final bool? hasRequestReadReceipt;
|
final bool? hasRequestReadReceipt;
|
||||||
final ScreenDisplayMode displayMode;
|
final ScreenDisplayMode displayMode;
|
||||||
|
final List<EmailAddress>? cc;
|
||||||
|
final List<EmailAddress>? bcc;
|
||||||
|
|
||||||
ComposerArguments({
|
ComposerArguments({
|
||||||
this.emailActionType = EmailActionType.compose,
|
this.emailActionType = EmailActionType.compose,
|
||||||
@@ -49,7 +51,9 @@ class ComposerArguments extends RouterArguments {
|
|||||||
this.selectedIdentityId,
|
this.selectedIdentityId,
|
||||||
this.inlineImages,
|
this.inlineImages,
|
||||||
this.hasRequestReadReceipt,
|
this.hasRequestReadReceipt,
|
||||||
this.displayMode = ScreenDisplayMode.normal
|
this.displayMode = ScreenDisplayMode.normal,
|
||||||
|
this.cc,
|
||||||
|
this.bcc,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ComposerArguments.fromSendingEmail(SendingEmail sendingEmail) =>
|
factory ComposerArguments.fromSendingEmail(SendingEmail sendingEmail) =>
|
||||||
@@ -76,13 +80,20 @@ class ComposerArguments extends RouterArguments {
|
|||||||
listEmailAddress: [emailAddress]
|
listEmailAddress: [emailAddress]
|
||||||
);
|
);
|
||||||
|
|
||||||
factory ComposerArguments.fromMailtoUri({List<EmailAddress>? listEmailAddress, String? subject, String? body}) =>
|
factory ComposerArguments.fromMailtoUri({
|
||||||
ComposerArguments(
|
List<EmailAddress>? listEmailAddress,
|
||||||
emailActionType: EmailActionType.composeFromMailtoUri,
|
String? subject,
|
||||||
listEmailAddress: listEmailAddress,
|
String? body,
|
||||||
subject: subject,
|
List<EmailAddress>? cc,
|
||||||
body: body,
|
List<EmailAddress>? bcc
|
||||||
);
|
}) => ComposerArguments(
|
||||||
|
emailActionType: EmailActionType.composeFromMailtoUri,
|
||||||
|
listEmailAddress: listEmailAddress,
|
||||||
|
subject: subject,
|
||||||
|
body: body,
|
||||||
|
cc: cc,
|
||||||
|
bcc: bcc,
|
||||||
|
);
|
||||||
|
|
||||||
factory ComposerArguments.editDraftEmail(PresentationEmail presentationEmail) =>
|
factory ComposerArguments.editDraftEmail(PresentationEmail presentationEmail) =>
|
||||||
ComposerArguments(
|
ComposerArguments(
|
||||||
@@ -193,6 +204,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
inlineImages,
|
inlineImages,
|
||||||
hasRequestReadReceipt,
|
hasRequestReadReceipt,
|
||||||
displayMode,
|
displayMode,
|
||||||
|
cc,
|
||||||
|
bcc,
|
||||||
];
|
];
|
||||||
|
|
||||||
ComposerArguments copyWith({
|
ComposerArguments copyWith({
|
||||||
@@ -214,6 +227,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
List<Attachment>? inlineImages,
|
List<Attachment>? inlineImages,
|
||||||
bool? hasRequestReadReceipt,
|
bool? hasRequestReadReceipt,
|
||||||
ScreenDisplayMode? displayMode,
|
ScreenDisplayMode? displayMode,
|
||||||
|
List<EmailAddress>? cc,
|
||||||
|
List<EmailAddress>? bcc,
|
||||||
}) {
|
}) {
|
||||||
return ComposerArguments(
|
return ComposerArguments(
|
||||||
emailActionType: emailActionType ?? this.emailActionType,
|
emailActionType: emailActionType ?? this.emailActionType,
|
||||||
@@ -234,6 +249,8 @@ class ComposerArguments extends RouterArguments {
|
|||||||
inlineImages: inlineImages ?? this.inlineImages,
|
inlineImages: inlineImages ?? this.inlineImages,
|
||||||
hasRequestReadReceipt: hasRequestReadReceipt ?? this.hasRequestReadReceipt,
|
hasRequestReadReceipt: hasRequestReadReceipt ?? this.hasRequestReadReceipt,
|
||||||
displayMode: displayMode ?? this.displayMode,
|
displayMode: displayMode ?? this.displayMode,
|
||||||
|
cc: cc ?? this.cc,
|
||||||
|
bcc: bcc ?? this.bcc,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -460,6 +460,8 @@ class MailboxController extends BaseMailboxController with MailboxActionHandlerM
|
|||||||
mailboxDashBoardController.goToComposer(
|
mailboxDashBoardController.goToComposer(
|
||||||
ComposerArguments.fromMailtoUri(
|
ComposerArguments.fromMailtoUri(
|
||||||
listEmailAddress: _navigationRouter?.listEmailAddress,
|
listEmailAddress: _navigationRouter?.listEmailAddress,
|
||||||
|
cc: _navigationRouter?.cc,
|
||||||
|
bcc: _navigationRouter?.bcc,
|
||||||
subject: _navigationRouter?.subject,
|
subject: _navigationRouter?.subject,
|
||||||
body: _navigationRouter?.body
|
body: _navigationRouter?.body
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class MailtoUrlController extends ReloadableController {
|
|||||||
if (parameters.containsKey('uri')) {
|
if (parameters.containsKey('uri')) {
|
||||||
final mailtoArgument = MailtoArguments(
|
final mailtoArgument = MailtoArguments(
|
||||||
session: session,
|
session: session,
|
||||||
mailtoUri: parameters['uri']
|
mailtoUri: Uri.base.toString(),
|
||||||
);
|
);
|
||||||
popAndPush(
|
popAndPush(
|
||||||
RouteUtils.generateNavigationRoute(AppRoutes.dashboard),
|
RouteUtils.generateNavigationRoute(AppRoutes.dashboard),
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ class NavigationRouter with EquatableMixin {
|
|||||||
final String? subject;
|
final String? subject;
|
||||||
final String? body;
|
final String? body;
|
||||||
final AccountMenuItem accountMenuItem;
|
final AccountMenuItem accountMenuItem;
|
||||||
|
final List<EmailAddress>? cc;
|
||||||
|
final List<EmailAddress>? bcc;
|
||||||
|
|
||||||
NavigationRouter({
|
NavigationRouter({
|
||||||
this.emailId,
|
this.emailId,
|
||||||
@@ -32,6 +34,8 @@ class NavigationRouter with EquatableMixin {
|
|||||||
this.subject,
|
this.subject,
|
||||||
this.body,
|
this.body,
|
||||||
this.accountMenuItem = AccountMenuItem.none,
|
this.accountMenuItem = AccountMenuItem.none,
|
||||||
|
this.cc,
|
||||||
|
this.bcc,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory NavigationRouter.initial() => NavigationRouter();
|
factory NavigationRouter.initial() => NavigationRouter();
|
||||||
@@ -47,5 +51,7 @@ class NavigationRouter with EquatableMixin {
|
|||||||
subject,
|
subject,
|
||||||
body,
|
body,
|
||||||
accountMenuItem,
|
accountMenuItem,
|
||||||
|
cc,
|
||||||
|
bcc,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -25,8 +25,12 @@ abstract class RouteUtils {
|
|||||||
static const String paramMailtoAddress = 'mailtoAddress';
|
static const String paramMailtoAddress = 'mailtoAddress';
|
||||||
static const String paramSubject = 'subject';
|
static const String paramSubject = 'subject';
|
||||||
static const String paramBody = 'body';
|
static const String paramBody = 'body';
|
||||||
|
static const String paramTo = 'to';
|
||||||
|
static const String paramCc = 'cc';
|
||||||
|
static const String paramBcc = 'bcc';
|
||||||
|
|
||||||
static const String mailtoPrefix = 'mailto:';
|
static const String mailtoPrefix = 'mailto';
|
||||||
|
static const String uriPrefix = 'uri';
|
||||||
static const String ADDRESS_SEPARATOR = ',';
|
static const String ADDRESS_SEPARATOR = ',';
|
||||||
static const String INVALID_VALUE = 'invalid';
|
static const String INVALID_VALUE = 'invalid';
|
||||||
|
|
||||||
@@ -107,6 +111,8 @@ abstract class RouteUtils {
|
|||||||
final queryParam = parameters[paramQuery];
|
final queryParam = parameters[paramQuery];
|
||||||
final routeName = parameters[paramRouteName];
|
final routeName = parameters[paramRouteName];
|
||||||
final mailtoAddress = parameters[paramMailtoAddress];
|
final mailtoAddress = parameters[paramMailtoAddress];
|
||||||
|
final mailtoCc = parameters[paramCc];
|
||||||
|
final mailtoBcc = parameters[paramBcc];
|
||||||
final subject = parameters[paramSubject];
|
final subject = parameters[paramSubject];
|
||||||
final body = parameters[paramBody];
|
final body = parameters[paramBody];
|
||||||
|
|
||||||
@@ -116,18 +122,11 @@ abstract class RouteUtils {
|
|||||||
final dashboardType = DashboardType.values.firstWhereOrNull((type) => type.name == typeParam) ?? DashboardType.normal;
|
final dashboardType = DashboardType.values.firstWhereOrNull((type) => type.name == typeParam) ?? DashboardType.normal;
|
||||||
final settingType = AccountMenuItem.values.firstWhereOrNull((type) => type.getAliasBrowser() == typeParam) ?? AccountMenuItem.none;
|
final settingType = AccountMenuItem.values.firstWhereOrNull((type) => type.getAliasBrowser() == typeParam) ?? AccountMenuItem.none;
|
||||||
List<EmailAddress>? listEmailAddress;
|
List<EmailAddress>? listEmailAddress;
|
||||||
if (mailtoAddress is List<String>) {
|
List<EmailAddress>? cc;
|
||||||
listEmailAddress = mailtoAddress
|
List<EmailAddress>? bcc;
|
||||||
.map((address) => EmailAddress(
|
listEmailAddress = _emailAddressesFromMailtoAddress(mailtoAddress);
|
||||||
null,
|
cc = _emailAddressesFromMailtoAddress(mailtoCc);
|
||||||
GetUtils.isEmail(address) ? address : INVALID_VALUE
|
bcc = _emailAddressesFromMailtoAddress(mailtoBcc);
|
||||||
))
|
|
||||||
.toList();
|
|
||||||
} else if (mailtoAddress is String) {
|
|
||||||
listEmailAddress = [
|
|
||||||
EmailAddress(null, GetUtils.isEmail(mailtoAddress) ? mailtoAddress : INVALID_VALUE)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
log('RouteUtils::parsingRouteParametersToNavigationRouter:listEmailAddress = $listEmailAddress');
|
log('RouteUtils::parsingRouteParametersToNavigationRouter:listEmailAddress = $listEmailAddress');
|
||||||
return NavigationRouter(
|
return NavigationRouter(
|
||||||
emailId: emailId,
|
emailId: emailId,
|
||||||
@@ -136,12 +135,27 @@ abstract class RouteUtils {
|
|||||||
dashboardType: dashboardType,
|
dashboardType: dashboardType,
|
||||||
routeName: routeName,
|
routeName: routeName,
|
||||||
listEmailAddress: listEmailAddress,
|
listEmailAddress: listEmailAddress,
|
||||||
|
cc: cc,
|
||||||
|
bcc: bcc,
|
||||||
subject: subject,
|
subject: subject,
|
||||||
body: body,
|
body: body,
|
||||||
accountMenuItem: settingType,
|
accountMenuItem: settingType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<EmailAddress>? _emailAddressesFromMailtoAddress(dynamic mailtoAddress) {
|
||||||
|
if (mailtoAddress is List<String>) {
|
||||||
|
return mailtoAddress
|
||||||
|
.map((address) => EmailAddress(null, address))
|
||||||
|
.toList();
|
||||||
|
} else if (mailtoAddress is String) {
|
||||||
|
return [
|
||||||
|
EmailAddress(null, mailtoAddress)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
static void replaceBrowserHistory({required String title, required Uri url}) {
|
static void replaceBrowserHistory({required String title, required Uri url}) {
|
||||||
log('RouteUtils::replaceBrowserHistory(): title: $title | url: $url');
|
log('RouteUtils::replaceBrowserHistory(): title: $title | url: $url');
|
||||||
html.window.history.replaceState(null, title, url.toString());
|
html.window.history.replaceState(null, title, url.toString());
|
||||||
@@ -152,37 +166,59 @@ abstract class RouteUtils {
|
|||||||
final mapMailto = <String, dynamic>{
|
final mapMailto = <String, dynamic>{
|
||||||
RouteUtils.paramRouteName: AppRoutes.mailtoURL,
|
RouteUtils.paramRouteName: AppRoutes.mailtoURL,
|
||||||
};
|
};
|
||||||
if (mailtoUri?.startsWith(mailtoPrefix) == true) {
|
mailtoUri = mailtoUri == null ? null : Uri.decodeFull(mailtoUri);
|
||||||
final mailtoUrlDecoded = Uri.decodeFull(mailtoUri!);
|
final parsedMailToUri = Uri.tryParse(mailtoUri ?? '');
|
||||||
log('RouteUtils::parseMapMailtoFromUri:mailtoUrlDecoded = $mailtoUrlDecoded');
|
|
||||||
final uri = Uri.tryParse(mailtoUrlDecoded);
|
|
||||||
if (uri == null) return mapMailto;
|
|
||||||
|
|
||||||
final mailtoAddress = uri.path;
|
if (parsedMailToUri?.scheme == mailtoPrefix) {
|
||||||
final mapQueryParam = uri.queryParameters;
|
final to = <String>{
|
||||||
|
...?parsedMailToUri?.path.split(ADDRESS_SEPARATOR),
|
||||||
if (mailtoAddress.contains(ADDRESS_SEPARATOR)) {
|
...?parsedMailToUri?.queryParameters[paramTo]?.split(ADDRESS_SEPARATOR)
|
||||||
final listAddress = mailtoAddress.split(ADDRESS_SEPARATOR);
|
}.toList();
|
||||||
log('RouteUtils::parseMapMailtoFromUri:listAddress = $listAddress');
|
final cc = {
|
||||||
mapMailto[paramMailtoAddress] = listAddress;
|
...?parsedMailToUri?.queryParameters[paramCc]?.split(ADDRESS_SEPARATOR),
|
||||||
} else {
|
}.toList();
|
||||||
log('RouteUtils::parseMapMailtoFromUri:mailtoAddress = $mailtoAddress');
|
final bcc = {
|
||||||
mapMailto[paramMailtoAddress] = mailtoAddress;
|
...?parsedMailToUri?.queryParameters[paramBcc]?.split(ADDRESS_SEPARATOR),
|
||||||
}
|
}.toList();
|
||||||
if (mapQueryParam.containsKey(paramSubject)) {
|
final subject = parsedMailToUri?.queryParameters[paramSubject];
|
||||||
mapMailto[paramSubject] = mapQueryParam[paramSubject];
|
final body = parsedMailToUri?.queryParameters[paramBody];
|
||||||
}
|
mapMailto[paramMailtoAddress] = to;
|
||||||
if (mapQueryParam.containsKey(paramBody)) {
|
mapMailto[paramCc] = cc;
|
||||||
mapMailto[paramBody] = mapQueryParam[paramBody];
|
mapMailto[paramBcc] = bcc;
|
||||||
}
|
mapMailto[paramSubject] = subject;
|
||||||
} else if (mailtoUri != null) {
|
mapMailto[paramBody] = body;
|
||||||
final mailtoUrlDecoded = Uri.decodeFull(mailtoUri);
|
} else if (parsedMailToUri?.path == "/$mailtoPrefix" || parsedMailToUri?.path == "/$mailtoPrefix/") {
|
||||||
log('RouteUtils::parseMapMailtoFromUri:mailtoUrlDecoded = $mailtoUrlDecoded');
|
final to = {
|
||||||
mapMailto[paramMailtoAddress] = mailtoUrlDecoded;
|
...?parsedMailToUri?.queryParameters[uriPrefix]?.split('$mailtoPrefix:').last.split(ADDRESS_SEPARATOR),
|
||||||
|
...?parsedMailToUri?.queryParameters[paramTo]?.split(ADDRESS_SEPARATOR)
|
||||||
|
}.toList();
|
||||||
|
final cc = {
|
||||||
|
...?parsedMailToUri?.queryParameters[paramCc]?.split(ADDRESS_SEPARATOR),
|
||||||
|
}.toList();
|
||||||
|
final bcc = {
|
||||||
|
...?parsedMailToUri?.queryParameters[paramBcc]?.split(ADDRESS_SEPARATOR),
|
||||||
|
}.toList();
|
||||||
|
final subject = parsedMailToUri?.queryParameters[paramSubject];
|
||||||
|
final body = parsedMailToUri?.queryParameters[paramBody];
|
||||||
|
mapMailto[paramMailtoAddress] = to;
|
||||||
|
mapMailto[paramCc] = cc;
|
||||||
|
mapMailto[paramBcc] = bcc;
|
||||||
|
mapMailto[paramSubject] = subject;
|
||||||
|
mapMailto[paramBody] = body;
|
||||||
} else {
|
} else {
|
||||||
mapMailto[paramMailtoAddress] = mailtoUri;
|
mapMailto[paramMailtoAddress] = mailtoUri?.split(ADDRESS_SEPARATOR);
|
||||||
}
|
}
|
||||||
log('RouteUtils::parseMapMailtoFromUri:mapMailto: $mapMailto');
|
|
||||||
|
if (mapMailto[paramMailtoAddress]?.length == 1) {
|
||||||
|
mapMailto[paramMailtoAddress] = mapMailto[paramMailtoAddress].first;
|
||||||
|
}
|
||||||
|
|
||||||
|
log('RouteUtils::parseMapMailtoFromUri:paramMailtoAddress = ${mapMailto[paramMailtoAddress]}');
|
||||||
|
log('RouteUtils::parseMapMailtoFromUri:paramCc = ${mapMailto[paramCc]}');
|
||||||
|
log('RouteUtils::parseMapMailtoFromUri:paramBcc = ${mapMailto[paramBcc]}');
|
||||||
|
log('RouteUtils::parseMapMailtoFromUri:paramSubject = ${mapMailto[paramSubject]}');
|
||||||
|
log('RouteUtils::parseMapMailtoFromUri:paramBody = ${mapMailto[paramBody]}');
|
||||||
|
|
||||||
return mapMailto;
|
return mapMailto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,4 +228,12 @@ abstract class RouteUtils {
|
|||||||
log('RouteUtils::generateNavigationRouterFromMailtoLink:navigationRouter: $navigationRouter');
|
log('RouteUtils::generateNavigationRouterFromMailtoLink:navigationRouter: $navigationRouter');
|
||||||
return navigationRouter;
|
return navigationRouter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool canOpenComposerFromNavigationRouter(NavigationRouter navigationRouter) {
|
||||||
|
return navigationRouter.listEmailAddress?.isNotEmpty == true
|
||||||
|
|| navigationRouter.cc?.isNotEmpty == true
|
||||||
|
|| navigationRouter.bcc?.isNotEmpty == true
|
||||||
|
|| navigationRouter.subject?.isNotEmpty == true
|
||||||
|
|| navigationRouter.body?.isNotEmpty == true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -83,5 +83,146 @@ void main() {
|
|||||||
expect(result[RouteUtils.paramMailtoAddress], containsAll(['test@example.com', 'test2@example.com', 'test3@example.com']));
|
expect(result[RouteUtils.paramMailtoAddress], containsAll(['test@example.com', 'test2@example.com', 'test3@example.com']));
|
||||||
expect(result[RouteUtils.paramSubject], equals('Hello'));
|
expect(result[RouteUtils.paramSubject], equals('Hello'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should parse a valid mailto URI encoded contains every possible parameters',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
const to1 = 'to1@example.com';
|
||||||
|
const to2 = 'to2@example.com';
|
||||||
|
const to3 = 'to3@example.com';
|
||||||
|
const cc1 = 'cc1@example.com';
|
||||||
|
const cc2 = 'cc2@example.com';
|
||||||
|
const bcc1 = 'bcc1@example.com';
|
||||||
|
const bcc2 = 'bcc2@example.com';
|
||||||
|
const subject = 'Hello';
|
||||||
|
const body = 'Bye';
|
||||||
|
const mailtoSchemeUri = 'mailto:$to1,$to2'
|
||||||
|
'?to=$to2,$to3'
|
||||||
|
'&cc=$cc1,$cc2'
|
||||||
|
'&bcc=$bcc1,$bcc2'
|
||||||
|
'&subject=$subject'
|
||||||
|
'&body=$body';
|
||||||
|
|
||||||
|
const mailtoPathUri = 'https://example.com/mailto'
|
||||||
|
'?uri=$to1,$to2'
|
||||||
|
'&to=$to2,$to3'
|
||||||
|
'&cc=$cc1,$cc2'
|
||||||
|
'&bcc=$bcc1,$bcc2'
|
||||||
|
'&subject=$subject'
|
||||||
|
'&body=$body';
|
||||||
|
|
||||||
|
const mailtoPathWithNestedMailtoUri = 'https://example.com/mailto/'
|
||||||
|
'?uri=mailto:$to1,$to2'
|
||||||
|
'&to=$to2,$to3'
|
||||||
|
'&cc=$cc1,$cc2'
|
||||||
|
'&bcc=$bcc1,$bcc2'
|
||||||
|
'&subject=$subject'
|
||||||
|
'&body=$body';
|
||||||
|
|
||||||
|
// act
|
||||||
|
final mailtoSchemeResult = RouteUtils.parseMapMailtoFromUri(
|
||||||
|
Uri.encodeFull(mailtoSchemeUri));
|
||||||
|
final mailtoPathResult = RouteUtils.parseMapMailtoFromUri(
|
||||||
|
Uri.encodeFull(mailtoPathUri));
|
||||||
|
final mailtoPathWithNestedMailtoResult = RouteUtils.parseMapMailtoFromUri(
|
||||||
|
Uri.encodeFull(mailtoPathWithNestedMailtoUri));
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(mailtoSchemeResult, equals(mailtoPathResult));
|
||||||
|
expect(mailtoSchemeResult, equals(mailtoPathWithNestedMailtoResult));
|
||||||
|
expect(mailtoPathResult, equals(mailtoPathWithNestedMailtoResult));
|
||||||
|
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramMailtoAddress],
|
||||||
|
containsAll([to1, to2, to3,])
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramCc],
|
||||||
|
containsAll([cc1, cc2])
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramBcc],
|
||||||
|
containsAll([bcc1, bcc2])
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramSubject],
|
||||||
|
equals(subject)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramBody],
|
||||||
|
equals(body)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test(
|
||||||
|
'should parse a valid mailto URI contains every possible parameters',
|
||||||
|
() {
|
||||||
|
// arrange
|
||||||
|
const to1 = 'to1@example.com';
|
||||||
|
const to2 = 'to2@example.com';
|
||||||
|
const to3 = 'to3@example.com';
|
||||||
|
const cc1 = 'cc1@example.com';
|
||||||
|
const cc2 = 'cc2@example.com';
|
||||||
|
const bcc1 = 'bcc1@example.com';
|
||||||
|
const bcc2 = 'bcc2@example.com';
|
||||||
|
const subject = 'Hello';
|
||||||
|
const body = 'Bye';
|
||||||
|
const mailtoSchemeUri = 'mailto:$to1,$to2'
|
||||||
|
'?to=$to2,$to3'
|
||||||
|
'&cc=$cc1,$cc2'
|
||||||
|
'&bcc=$bcc1,$bcc2'
|
||||||
|
'&subject=$subject'
|
||||||
|
'&body=$body';
|
||||||
|
|
||||||
|
const mailtoPathUri = 'https://example.com/mailto'
|
||||||
|
'?uri=$to1,$to2'
|
||||||
|
'&to=$to2,$to3'
|
||||||
|
'&cc=$cc1,$cc2'
|
||||||
|
'&bcc=$bcc1,$bcc2'
|
||||||
|
'&subject=$subject'
|
||||||
|
'&body=$body';
|
||||||
|
|
||||||
|
const mailtoPathWithNestedMailtoUri = 'https://example.com/mailto/'
|
||||||
|
'?uri=mailto:$to1,$to2'
|
||||||
|
'&to=$to2,$to3'
|
||||||
|
'&cc=$cc1,$cc2'
|
||||||
|
'&bcc=$bcc1,$bcc2'
|
||||||
|
'&subject=$subject'
|
||||||
|
'&body=$body';
|
||||||
|
|
||||||
|
// act
|
||||||
|
final mailtoSchemeResult = RouteUtils.parseMapMailtoFromUri(
|
||||||
|
mailtoSchemeUri);
|
||||||
|
final mailtoPathResult = RouteUtils.parseMapMailtoFromUri(mailtoPathUri);
|
||||||
|
final mailtoPathWithNestedMailtoResult = RouteUtils.parseMapMailtoFromUri(
|
||||||
|
mailtoPathWithNestedMailtoUri);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
expect(mailtoSchemeResult, equals(mailtoPathResult));
|
||||||
|
expect(mailtoSchemeResult, equals(mailtoPathWithNestedMailtoResult));
|
||||||
|
expect(mailtoPathResult, equals(mailtoPathWithNestedMailtoResult));
|
||||||
|
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramMailtoAddress],
|
||||||
|
containsAll([to1, to2, to3,])
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramCc],
|
||||||
|
containsAll([cc1, cc2])
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramBcc],
|
||||||
|
containsAll([bcc1, bcc2])
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramSubject],
|
||||||
|
equals(subject)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mailtoSchemeResult[RouteUtils.paramBody],
|
||||||
|
equals(body)
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user