diff --git a/frontend/appflowy_flutter/ios/Podfile.lock b/frontend/appflowy_flutter/ios/Podfile.lock index c707a32587..97f3d764e6 100644 --- a/frontend/appflowy_flutter/ios/Podfile.lock +++ b/frontend/appflowy_flutter/ios/Podfile.lock @@ -69,6 +69,8 @@ PODS: - SDWebImage (5.14.2): - SDWebImage/Core (= 5.14.2) - SDWebImage/Core (5.14.2) + - share_plus (0.0.1): + - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -99,6 +101,7 @@ DEPENDENCIES: - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - rich_clipboard_ios (from `.symlinks/plugins/rich_clipboard_ios/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `.symlinks/plugins/sqflite/darwin`) - super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`) @@ -146,6 +149,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider_foundation/darwin" rich_clipboard_ios: :path: ".symlinks/plugins/rich_clipboard_ios/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite: @@ -176,6 +181,7 @@ SPEC CHECKSUMS: ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 rich_clipboard_ios: 7588abe18f881a6d0e9ec0b12e51cae2761e8942 SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84 + share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7 diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/setting/launch_settings_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/setting/launch_settings_page.dart index 05aca0ba09..b7e1d59db7 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/setting/launch_settings_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/setting/launch_settings_page.dart @@ -29,6 +29,7 @@ class MobileLaunchSettingsPage extends StatelessWidget { children: [ const LanguageSettingGroup(), if (Env.enableCustomCloud) const SelfHostSettingGroup(), + const SupportSettingGroup(), ], ), ), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/setting/support_setting_group.dart b/frontend/appflowy_flutter/lib/mobile/presentation/setting/support_setting_group.dart index 3995e11b98..03dc888c4c 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/setting/support_setting_group.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/setting/support_setting_group.dart @@ -1,6 +1,9 @@ import 'dart:io'; import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart'; +import 'package:appflowy/mobile/presentation/widgets/widgets.dart'; +import 'package:appflowy/util/share_log_files.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; @@ -33,10 +36,17 @@ class SupportSettingGroup extends StatelessWidget { Icons.chevron_right, ), onTap: () { - final String? version = snapshot.data?.version; - final String os = Platform.operatingSystem; - safeLaunchUrl( - 'https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&projects=&template=bug_report.yaml&title=[Bug]%20Mobile:%20&version=$version&os=$os', + showMobileBottomSheet( + context, + showDragHandle: true, + showHeader: true, + title: LocaleKeys.workspace_errorActions_reportIssue.tr(), + backgroundColor: Theme.of(context).colorScheme.surface, + builder: (context) { + return _ReportIssuesWidget( + version: snapshot.data?.version ?? '', + ); + }, ); }, ), @@ -45,3 +55,35 @@ class SupportSettingGroup extends StatelessWidget { ); } } + +class _ReportIssuesWidget extends StatelessWidget { + const _ReportIssuesWidget({ + required this.version, + }); + + final String version; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + FlowyOptionTile.text( + showTopBorder: false, + text: LocaleKeys.workspace_errorActions_reportIssueOnGithub.tr(), + onTap: () { + final String os = Platform.operatingSystem; + safeLaunchUrl( + 'https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&projects=&template=bug_report.yaml&title=[Bug]%20Mobile:%20&version=$version&os=$os', + ); + }, + ), + FlowyOptionTile.text( + showTopBorder: false, + text: LocaleKeys.workspace_errorActions_exportLogFiles.tr(), + onTap: () => shareLogFiles(context), + ), + ], + ); + } +} diff --git a/frontend/appflowy_flutter/lib/util/share_log_files.dart b/frontend/appflowy_flutter/lib/util/share_log_files.dart new file mode 100644 index 0000000000..9838eb4a40 --- /dev/null +++ b/frontend/appflowy_flutter/lib/util/share_log_files.dart @@ -0,0 +1,57 @@ +import 'dart:io'; + +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/workspace/presentation/home/toast.dart'; +import 'package:archive/archive_io.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; +import 'package:share_plus/share_plus.dart'; + +Future shareLogFiles(BuildContext? context) async { + final dir = await getApplicationSupportDirectory(); + final zipEncoder = ZipEncoder(); + + final archiveLogFiles = dir + .listSync(recursive: true) + .where((e) => p.basename(e.path).startsWith('log.')) + .map((e) { + final bytes = File(e.path).readAsBytesSync(); + return ArchiveFile(p.basename(e.path), bytes.length, bytes); + }); + + if (archiveLogFiles.isEmpty) { + if (context != null && context.mounted) { + showSnackBarMessage( + context, + LocaleKeys.noLogFiles.tr(), + ); + } + return; + } + + final archive = Archive(); + for (final file in archiveLogFiles) { + archive.addFile(file); + } + + final zip = zipEncoder.encode(archive); + if (zip == null) { + return; + } + + // create a zipped appflowy logs file + final path = Platform.isAndroid ? '/storage/emulated/0/Download' : dir.path; + final zipFile = + await File(p.join(path, 'appflowy_logs.zip')).writeAsBytes(zip); + + if (Platform.isIOS) { + await Share.shareUri(zipFile.uri); + } else { + await Share.shareXFiles([XFile(zipFile.path)]); + } + + // delete the zipped appflowy logs file + await zipFile.delete(); +} diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index 90eaf47da5..f05536a7f6 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -1522,6 +1522,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.8" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd + url: "https://pub.dev" + source: hosted + version: "7.2.1" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 + url: "https://pub.dev" + source: hosted + version: "3.3.1" shared_preferences: dependency: "direct main" description: diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index f1aeaac4e0..6d9152a930 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -98,7 +98,7 @@ dependencies: http: ^1.0.0 path: ^1.8.3 mocktail: ^1.0.1 - archive: ^3.3.7 + archive: ^3.4.10 nanoid: ^1.0.0 supabase_flutter: ^1.10.4 envied: ^0.5.2 @@ -128,6 +128,7 @@ dependencies: keyboard_height_plugin: ^0.0.5 scrollable_positioned_list: ^0.3.8 flutter_cache_manager: ^3.3.1 + share_plus: ^7.2.1 dev_dependencies: flutter_lints: ^3.0.1 diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 89d3c3176b..c41b9b067a 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -60,6 +60,8 @@ "failedToLoad": "Something went wrong! Failed to load the workspace. Try to close any open instance of AppFlowy and try again.", "errorActions": { "reportIssue": "Report an issue", + "reportIssueOnGithub": "Report an issue on Github", + "exportLogFiles": "Export log files", "reachOut": "Reach out on Discord" } }, @@ -1243,5 +1245,6 @@ "date": "Date", "addField": "Add field", "userIcon": "User icon" - } + }, + "noLogFiles": "There're no log files" } \ No newline at end of file