Merge pull request #390 from ente-io/ios_fix_send_email
Fix email action for iOS
This commit is contained in:
commit
4d2c9101fa
|
@ -139,6 +139,8 @@ PODS:
|
|||
- nanopb/encode (2.30908.0)
|
||||
- open_file (0.0.1):
|
||||
- Flutter
|
||||
- open_mail_app (0.0.1):
|
||||
- Flutter
|
||||
- OrderedSet (5.0.0)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
|
@ -223,6 +225,7 @@ DEPENDENCIES:
|
|||
- motionphoto (from `.symlinks/plugins/motionphoto/ios`)
|
||||
- move_to_background (from `.symlinks/plugins/move_to_background/ios`)
|
||||
- open_file (from `.symlinks/plugins/open_file/ios`)
|
||||
- open_mail_app (from `.symlinks/plugins/open_mail_app/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
|
||||
|
@ -315,6 +318,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/move_to_background/ios"
|
||||
open_file:
|
||||
:path: ".symlinks/plugins/open_file/ios"
|
||||
open_mail_app:
|
||||
:path: ".symlinks/plugins/open_mail_app/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_ios:
|
||||
|
@ -387,6 +392,7 @@ SPEC CHECKSUMS:
|
|||
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d
|
||||
open_mail_app: 794172f6a22cd16319d3ddaf45e945b2f74952b0
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
|
||||
|
|
|
@ -299,6 +299,7 @@
|
|||
"${BUILT_PRODUCTS_DIR}/move_to_background/move_to_background.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/open_file/open_file.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/open_mail_app/open_mail_app.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/path_provider_ios/path_provider_ios.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
|
||||
|
@ -360,6 +361,7 @@
|
|||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/move_to_background.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_file.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/open_mail_app.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_ios.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
|
||||
|
|
|
@ -22,6 +22,18 @@
|
|||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>googlegmail</string>
|
||||
<string>x-dispatch</string>
|
||||
<string>readdle-spark</string>
|
||||
<string>airmail</string>
|
||||
<string>ms-outlook</string>
|
||||
<string>ymail</string>
|
||||
<string>fastmail</string>
|
||||
<string>superhuman</string>
|
||||
<string>protonmail</string>
|
||||
</array>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_email_sender/flutter_email_sender.dart';
|
||||
import 'package:flutter_sodium/flutter_sodium.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/models/delete_account.dart';
|
||||
|
@ -11,8 +10,8 @@ import 'package:photos/ui/common/gradient_button.dart';
|
|||
import 'package:photos/ui/tools/app_lock.dart';
|
||||
import 'package:photos/utils/auth_util.dart';
|
||||
import 'package:photos/utils/crypto_util.dart';
|
||||
import 'package:photos/utils/email_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class DeleteAccountPage extends StatelessWidget {
|
||||
const DeleteAccountPage({
|
||||
|
@ -81,11 +80,10 @@ class DeleteAccountPage extends StatelessWidget {
|
|||
paddingValue: 4,
|
||||
iconData: Icons.check,
|
||||
onTap: () async {
|
||||
await launchUrl(
|
||||
Uri(
|
||||
scheme: "mailto",
|
||||
path: 'feedback@ente.io',
|
||||
),
|
||||
await sendEmail(
|
||||
context,
|
||||
to: 'feedback@ente.io',
|
||||
subject: '[Feedback]',
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -222,15 +220,11 @@ class DeleteAccountPage extends StatelessWidget {
|
|||
),
|
||||
onPressed: () async {
|
||||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
try {
|
||||
final Email email = Email(
|
||||
recipients: ['account-deletion@ente.io'],
|
||||
isHTML: false,
|
||||
);
|
||||
await FlutterEmailSender.send(email);
|
||||
} catch (e) {
|
||||
launch("mailto:account-deletion@ente.io");
|
||||
}
|
||||
await sendEmail(
|
||||
context,
|
||||
to: 'account-deletion@ente.io',
|
||||
subject: '[Delete account]',
|
||||
);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
|
|
|
@ -21,7 +21,7 @@ import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
|||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:step_progress_indicator/step_progress_indicator.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class StripeSubscriptionPage extends StatefulWidget {
|
||||
final bool isOnboarding;
|
||||
|
@ -224,14 +224,14 @@ class _StripeSubscriptionPageState extends State<StripeSubscriptionPage> {
|
|||
await _launchStripePortal();
|
||||
break;
|
||||
case kPlayStore:
|
||||
launch(
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/account/subscriptions?sku=" +
|
||||
_currentSubscription.productID +
|
||||
"&package=io.ente.photos",
|
||||
);
|
||||
break;
|
||||
case kAppStore:
|
||||
launch("https://apps.apple.com/account/billing");
|
||||
launchUrlString("https://apps.apple.com/account/billing");
|
||||
break;
|
||||
default:
|
||||
_logger.severe(
|
||||
|
|
|
@ -20,7 +20,7 @@ import 'package:photos/ui/payment/subscription_common_widgets.dart';
|
|||
import 'package:photos/ui/payment/subscription_plan_widget.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class SubscriptionPage extends StatefulWidget {
|
||||
final bool isOnboarding;
|
||||
|
@ -213,13 +213,13 @@ class _SubscriptionPageState extends State<SubscriptionPage> {
|
|||
return;
|
||||
}
|
||||
if (Platform.isAndroid) {
|
||||
launch(
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/account/subscriptions?sku=" +
|
||||
_currentSubscription.productID +
|
||||
"&package=io.ente.photos",
|
||||
);
|
||||
} else {
|
||||
launch("https://apps.apple.com/account/billing");
|
||||
launchUrlString("https://apps.apple.com/account/billing");
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
|
|
|
@ -18,7 +18,7 @@ import 'package:photos/utils/data_util.dart';
|
|||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/navigation_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class BackupSectionWidget extends StatefulWidget {
|
||||
const BackupSectionWidget({Key key}) : super(key: key);
|
||||
|
@ -229,11 +229,13 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
|||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
// TODO: Replace with https://pub.dev/packages/in_app_review
|
||||
if (Platform.isAndroid) {
|
||||
launch(
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/apps/details?id=io.ente.photos",
|
||||
);
|
||||
} else {
|
||||
launch("https://apps.apple.com/in/app/ente-photos/id1542026904");
|
||||
launchUrlString(
|
||||
"https://apps.apple.com/in/app/ente-photos/id1542026904",
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -289,11 +291,13 @@ class BackupSectionWidgetState extends State<BackupSectionWidget> {
|
|||
Navigator.of(context, rootNavigator: true).pop('dialog');
|
||||
// TODO: Replace with https://pub.dev/packages/in_app_review
|
||||
if (Platform.isAndroid) {
|
||||
launch(
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/apps/details?id=io.ente.photos",
|
||||
);
|
||||
} else {
|
||||
launch("https://apps.apple.com/in/app/ente-photos/id1542026904");
|
||||
launchUrlString(
|
||||
"https://apps.apple.com/in/app/ente-photos/id1542026904",
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:photos/services/update_service.dart';
|
|||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class SocialSectionWidget extends StatelessWidget {
|
||||
const SocialSectionWidget({Key key}) : super(key: key);
|
||||
|
@ -26,7 +26,7 @@ class SocialSectionWidget extends StatelessWidget {
|
|||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
launch("https://twitter.com/enteio");
|
||||
launchUrlString("https://twitter.com/enteio");
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Twitter", icon: Icons.navigate_next),
|
||||
|
@ -35,7 +35,7 @@ class SocialSectionWidget extends StatelessWidget {
|
|||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
launch("https://ente.io/discord");
|
||||
launchUrlString("https://ente.io/discord");
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Discord", icon: Icons.navigate_next),
|
||||
|
@ -44,7 +44,7 @@ class SocialSectionWidget extends StatelessWidget {
|
|||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
launch("https://reddit.com/r/enteio");
|
||||
launchUrlString("https://reddit.com/r/enteio");
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Reddit", icon: Icons.navigate_next),
|
||||
|
@ -58,11 +58,11 @@ class SocialSectionWidget extends StatelessWidget {
|
|||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
if (Platform.isAndroid) {
|
||||
launch(
|
||||
launchUrlString(
|
||||
"https://play.google.com/store/apps/details?id=io.ente.photos",
|
||||
);
|
||||
} else {
|
||||
launch(
|
||||
launchUrlString(
|
||||
"https://apps.apple.com/in/app/ente-photos/id1542026904",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,16 +2,13 @@ import 'dart:io';
|
|||
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/constants.dart';
|
||||
import 'package:photos/ui/common/web_page.dart';
|
||||
import 'package:photos/ui/settings/common_settings.dart';
|
||||
import 'package:photos/ui/settings/settings_section_title.dart';
|
||||
import 'package:photos/ui/settings/settings_text_item.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/email_util.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class SupportSectionWidget extends StatelessWidget {
|
||||
const SupportSectionWidget({Key key}) : super(key: key);
|
||||
|
@ -34,16 +31,7 @@ class SupportSectionWidget extends StatelessWidget {
|
|||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
try {
|
||||
final Uri emailLaunchUri = Uri(
|
||||
scheme: 'mailto',
|
||||
path: kSupportEmail,
|
||||
);
|
||||
launchUrl(emailLaunchUri);
|
||||
} catch (e) {
|
||||
Logger("SupportSection").severe(e);
|
||||
showErrorDialog(context, "", "Please email us at $kSupportEmail");
|
||||
}
|
||||
await sendEmail(context, to: kSupportEmail);
|
||||
},
|
||||
child:
|
||||
const SettingsTextItem(text: "Email", icon: Icons.navigate_next),
|
||||
|
|
|
@ -2,10 +2,13 @@ import 'dart:io';
|
|||
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:email_validator/email_validator.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_email_sender/flutter_email_sender.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:open_mail_app/open_mail_app.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/error-reporting/super_logging.dart';
|
||||
|
@ -13,7 +16,9 @@ import 'package:photos/ente_theme_data.dart';
|
|||
import 'package:photos/ui/common/dialogs.dart';
|
||||
import 'package:photos/ui/tools/debug/log_file_viewer.dart';
|
||||
import 'package:photos/utils/dialog_util.dart';
|
||||
import 'package:photos/utils/toast_util.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
final Logger _logger = Logger('email_util');
|
||||
|
||||
|
@ -163,7 +168,7 @@ Future<void> shareLogs(
|
|||
"Email logs",
|
||||
"Please send the logs to $toEmail",
|
||||
firstAction: "Copy email",
|
||||
secondAction: "Send",
|
||||
secondAction: "Export logs",
|
||||
);
|
||||
if (result != null && result == DialogUserChoice.firstChoice) {
|
||||
await Clipboard.setData(ClipboardData(text: toEmail));
|
||||
|
@ -174,3 +179,115 @@ Future<void> shareLogs(
|
|||
sharePositionOrigin: Rect.fromLTWH(0, 0, size.width, size.height / 2),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> sendEmail(
|
||||
BuildContext context, {
|
||||
@required String to,
|
||||
String subject,
|
||||
String body,
|
||||
}) async {
|
||||
try {
|
||||
String clientDebugInfo = await _clientInfo();
|
||||
EmailContent email = EmailContent(
|
||||
to: [
|
||||
to,
|
||||
],
|
||||
subject: subject ?? '[Support]',
|
||||
body: (body ?? '') + clientDebugInfo,
|
||||
);
|
||||
if (Platform.isAndroid) {
|
||||
// Special handling due to issue in proton mail android client
|
||||
// https://github.com/ente-io/frame/pull/253
|
||||
final Uri params = Uri(
|
||||
scheme: 'mailto',
|
||||
path: to,
|
||||
query: 'subject=${email.subject}&body=${email.body}',
|
||||
);
|
||||
if (await canLaunchUrl(params)) {
|
||||
await launchUrl(params);
|
||||
} else {
|
||||
// this will trigger _showNoMailAppsDialog
|
||||
throw Exception('Could not launch ${params.toString()}');
|
||||
}
|
||||
} else {
|
||||
OpenMailAppResult result = await OpenMailApp.composeNewEmailInMailApp(
|
||||
nativePickerTitle: 'Select email app',
|
||||
emailContent: email,
|
||||
);
|
||||
if (!result.didOpen && !result.canOpen) {
|
||||
_showNoMailAppsDialog(context, to);
|
||||
} else if (!result.didOpen && result.canOpen) {
|
||||
showCupertinoModalPopup(
|
||||
context: context,
|
||||
builder: (_) => CupertinoActionSheet(
|
||||
title: Text("Select mail app \n $to"),
|
||||
actions: [
|
||||
for (var app in result.options)
|
||||
CupertinoActionSheetAction(
|
||||
child: Text(app.name),
|
||||
onPressed: () {
|
||||
final content = email;
|
||||
if (content != null) {
|
||||
OpenMailApp.composeNewEmailInSpecificMailApp(
|
||||
mailApp: app,
|
||||
emailContent: content,
|
||||
);
|
||||
} else {
|
||||
OpenMailApp.openSpecificMailApp(app);
|
||||
}
|
||||
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
child: const Text("Cancel"),
|
||||
onPressed: () {
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
_logger.severe("Failed to send email to $to", e);
|
||||
_showNoMailAppsDialog(context, to);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _clientInfo() async {
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
String debugInfo = '\n\n\n\n ------------------- \nFollowing information can '
|
||||
'help us in debugging if you are facing any issue '
|
||||
'\nRegistered email: ${Configuration.instance.getEmail()}'
|
||||
'\nClient: ${packageInfo.packageName}'
|
||||
'\nVersion : ${packageInfo.version}';
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
void _showNoMailAppsDialog(BuildContext context, String toEmail) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('Please email us at $toEmail'),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text("Copy email"),
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(text: toEmail));
|
||||
showShortToast(context, 'Copied');
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text("OK"),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -809,6 +809,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
open_mail_app:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: open_mail_app
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.5"
|
||||
package_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -82,7 +82,9 @@ dependencies:
|
|||
motionphoto:
|
||||
git: "https://github.com/ente-io/motionphoto.git"
|
||||
move_to_background: ^1.0.2
|
||||
|
||||
open_file: ^3.2.1
|
||||
open_mail_app: ^0.4.5
|
||||
package_info_plus: ^1.0.1
|
||||
page_transition: ^2.0.2
|
||||
path_provider: ^2.0.1
|
||||
|
|
Loading…
Reference in a new issue