diff --git a/frontend/appflowy_flutter/ios/Podfile.lock b/frontend/appflowy_flutter/ios/Podfile.lock index 3089e3f56e..d9c5905736 100644 --- a/frontend/appflowy_flutter/ios/Podfile.lock +++ b/frontend/appflowy_flutter/ios/Podfile.lock @@ -56,6 +56,8 @@ PODS: - Flutter - keyboard_height_plugin (0.0.1): - Flutter + - open_file_ios (0.0.1): + - Flutter - open_filex (0.0.2): - Flutter - package_info_plus (0.4.5): @@ -102,6 +104,7 @@ DEPENDENCIES: - integration_test (from `.symlinks/plugins/integration_test/ios`) - irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`) - keyboard_height_plugin (from `.symlinks/plugins/keyboard_height_plugin/ios`) + - open_file_ios (from `.symlinks/plugins/open_file_ios/ios`) - open_filex (from `.symlinks/plugins/open_filex/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -148,6 +151,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/irondash_engine_context/ios" keyboard_height_plugin: :path: ".symlinks/plugins/keyboard_height_plugin/ios" + open_file_ios: + :path: ".symlinks/plugins/open_file_ios/ios" open_filex: :path: ".symlinks/plugins/open_filex/ios" package_info_plus: @@ -184,6 +189,7 @@ SPEC CHECKSUMS: integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9 keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86 + open_file_ios: 461db5853723763573e140de3193656f91990d9e open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 diff --git a/frontend/appflowy_flutter/lib/shared/settings/show_settings.dart b/frontend/appflowy_flutter/lib/shared/settings/show_settings.dart new file mode 100644 index 0000000000..81831346e9 --- /dev/null +++ b/frontend/appflowy_flutter/lib/shared/settings/show_settings.dart @@ -0,0 +1,67 @@ +import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart'; +import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart'; +import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart'; +import 'package:appflowy/workspace/presentation/home/af_focus_manager.dart'; +import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart'; +import 'package:appflowy_backend/log.dart'; +import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart' + show UserProfilePB; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +final GlobalKey _settingsDialogKey = GlobalKey(); + +// show settings dialog with user profile for fully customized settings dialog +void showSettingsDialog( + BuildContext context, + UserProfilePB userProfile, [ + UserWorkspaceBloc? bloc, + SettingsPage? initPage, +]) { + AFFocusManager.of(context).notifyLoseFocus(); + showDialog( + context: context, + builder: (dialogContext) => MultiBlocProvider( + key: _settingsDialogKey, + providers: [ + BlocProvider.value( + value: BlocProvider.of(dialogContext), + ), + BlocProvider.value(value: bloc ?? context.read()), + ], + child: SettingsDialog( + userProfile, + initPage: initPage, + didLogout: () async { + // Pop the dialog using the dialog context + Navigator.of(dialogContext).pop(); + await runAppFlowy(); + }, + dismissDialog: () { + if (Navigator.of(dialogContext).canPop()) { + return Navigator.of(dialogContext).pop(); + } + Log.warn("Can't pop dialog context"); + }, + restartApp: () async { + // Pop the dialog using the dialog context + Navigator.of(dialogContext).pop(); + await runAppFlowy(); + }, + ), + ), + ); +} + +// show settings dialog without user profile for simple settings dialog +// only support +// - language +// - self-host +// - support +void showSimpleSettingsDialog(BuildContext context) { + showDialog( + context: context, + builder: (dialogContext) => const SimpleSettingsDialog(), + ); +} diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/desktop_sign_in_screen.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/desktop_sign_in_screen.dart index 6e94f6a785..6a7509be83 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/desktop_sign_in_screen.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/desktop_sign_in_screen.dart @@ -1,6 +1,7 @@ import 'package:appflowy/core/frameless_window.dart'; import 'package:appflowy/env/cloud_env.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/shared/settings/show_settings.dart'; import 'package:appflowy/shared/window_title_bar.dart'; import 'package:appflowy/user/application/sign_in_bloc.dart'; import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart'; @@ -63,8 +64,15 @@ class DesktopSignInScreen extends StatelessWidget { const Spacer(), - // anonymous sign in - const SignInAnonymousButtonV2(), + // anonymous sign in and settings + const Row( + mainAxisSize: MainAxisSize.min, + children: [ + _SettingsButton(), + HSpace(42), + SignInAnonymousButtonV2(), + ], + ), const VSpace(16), ], ), @@ -84,6 +92,28 @@ class DesktopSignInScreen extends StatelessWidget { } } +class _SettingsButton extends StatelessWidget { + const _SettingsButton(); + + @override + Widget build(BuildContext context) { + return FlowyButton( + useIntrinsicWidth: true, + text: FlowyText( + LocaleKeys.signIn_settings.tr(), + textAlign: TextAlign.center, + fontSize: 12.0, + // fontWeight: FontWeight.w500, + color: Colors.grey, + decoration: TextDecoration.underline, + ), + onTap: () { + showSimpleSettingsDialog(context); + }, + ); + } +} + class _OrDivider extends StatelessWidget { const _OrDivider(); diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/mobile_sign_in_screen.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/mobile_sign_in_screen.dart index 727062a108..863aadc49c 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/mobile_sign_in_screen.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/mobile_sign_in_screen.dart @@ -118,16 +118,7 @@ class MobileSignInScreen extends StatelessWidget { }, ), const HSpace(24), - SignInAnonymousButtonV2( - child: FlowyText( - LocaleKeys.signIn_anonymous.tr(), - textAlign: TextAlign.center, - fontSize: 12.0, - // fontWeight: FontWeight.w500, - color: Colors.grey, - decoration: TextDecoration.underline, - ), - ), + const SignInAnonymousButtonV2(), ], ); } diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/sign_in_anonymous_button.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/sign_in_anonymous_button.dart index 1f7ea5eb6e..bce22a714d 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/sign_in_anonymous_button.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/sign_in_anonymous_button.dart @@ -89,11 +89,8 @@ class SignInAnonymousButton extends StatelessWidget { class SignInAnonymousButtonV2 extends StatelessWidget { const SignInAnonymousButtonV2({ super.key, - this.child, }); - final Widget? child; - @override Widget build(BuildContext context) { return BlocBuilder( @@ -111,9 +108,7 @@ class SignInAnonymousButtonV2 extends StatelessWidget { }, child: BlocBuilder( builder: (context, state) { - final text = state.anonUsers.isEmpty - ? LocaleKeys.signIn_loginStartWithAnonymous.tr() - : LocaleKeys.signIn_continueAnonymousUser.tr(); + final text = LocaleKeys.signIn_anonymous.tr(); final onTap = state.anonUsers.isEmpty ? () { context @@ -125,16 +120,14 @@ class SignInAnonymousButtonV2 extends StatelessWidget { final user = bloc.state.anonUsers.first; bloc.add(AnonUserEvent.openAnonUser(user)); }; - return MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: onTap, - child: child ?? - FlowyText( - text, - color: Colors.blue, - fontSize: 12, - ), + return FlowyButton( + useIntrinsicWidth: true, + onTap: onTap, + text: FlowyText( + text, + color: Colors.grey, + decoration: TextDecoration.underline, + fontSize: 12, ), ); }, diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/third_party_sign_in_buttons.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/third_party_sign_in_buttons.dart index 8f78011fac..5345990330 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/third_party_sign_in_buttons.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/sign_in_screen/widgets/third_party_sign_in_buttons.dart @@ -99,17 +99,20 @@ class _DesktopThirdPartySignInState extends State<_DesktopThirdPartySignIn> { List _buildCollapsedButtons() { return [ const VSpace(padding), - GestureDetector( - onTap: () { - setState(() { - isExpanded = !isExpanded; - }); - }, - child: FlowyText( - LocaleKeys.signIn_continueAnotherWay.tr(), - color: Theme.of(context).colorScheme.onSurface, - decoration: TextDecoration.underline, - fontSize: 14, + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + setState(() { + isExpanded = !isExpanded; + }); + }, + child: FlowyText( + LocaleKeys.signIn_continueAnotherWay.tr(), + color: Theme.of(context).colorScheme.onSurface, + decoration: TextDecoration.underline, + fontSize: 14, + ), ), ), ]; diff --git a/frontend/appflowy_flutter/lib/util/share_log_files.dart b/frontend/appflowy_flutter/lib/util/share_log_files.dart index 240b69716e..99cff27944 100644 --- a/frontend/appflowy_flutter/lib/util/share_log_files.dart +++ b/frontend/appflowy_flutter/lib/util/share_log_files.dart @@ -5,6 +5,7 @@ import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; import 'package:archive/archive_io.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:open_filex/open_filex.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; @@ -59,12 +60,16 @@ Future shareLogFiles(BuildContext? context) async { if (Platform.isIOS) { await Share.shareUri(zipFile.uri); - } else { + // delete the zipped appflowy logs file + await zipFile.delete(); + } else if (Platform.isAndroid) { await Share.shareXFiles([XFile(zipFile.path)]); + // delete the zipped appflowy logs file + await zipFile.delete(); + } else { + // open the directory + await OpenFilex.open(zipFile.path); } - - // delete the zipped appflowy logs file - await zipFile.delete(); } catch (e) { if (context != null && context.mounted) { showToastNotification( diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_manage_data_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_manage_data_view.dart index 2aa1a40037..23f2a8fd84 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_manage_data_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/pages/settings_manage_data_view.dart @@ -6,6 +6,7 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/shared/appflowy_cache_manager.dart'; import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/tasks/rust_sdk.dart'; +import 'package:appflowy/util/share_log_files.dart'; import 'package:appflowy/util/theme_extension.dart'; import 'package:appflowy/workspace/application/settings/setting_file_importer_bloc.dart'; import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart'; @@ -112,6 +113,20 @@ class SettingsManageDataView extends StatelessWidget { ], ), ], + SettingsCategory( + title: LocaleKeys.workspace_errorActions_exportLogFiles.tr(), + children: [ + SingleSettingAction( + labelMaxLines: 4, + label: + LocaleKeys.workspace_errorActions_exportLogFiles.tr(), + buttonLabel: LocaleKeys.settings_files_export.tr(), + onPressed: () { + shareLogFiles(context); + }, + ), + ], + ), SettingsCategory( title: LocaleKeys.settings_manageDataPage_cache_title.tr(), children: [ diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart index c633aa3577..95bb8d4976 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/settings_dialog.dart @@ -1,5 +1,9 @@ -import 'package:flutter/material.dart'; - +import 'package:appflowy/env/cloud_env.dart'; +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/shared/appflowy_cache_manager.dart'; +import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy/util/share_log_files.dart'; +import 'package:appflowy/workspace/application/settings/appflowy_cloud_urls_bloc.dart'; import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart'; import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart'; import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/settings_ai_view.dart'; @@ -9,12 +13,18 @@ import 'package:appflowy/workspace/presentation/settings/pages/settings_manage_d import 'package:appflowy/workspace/presentation/settings/pages/settings_plan_view.dart'; import 'package:appflowy/workspace/presentation/settings/pages/settings_shortcuts_view.dart'; import 'package:appflowy/workspace/presentation/settings/pages/settings_workspace_view.dart'; +import 'package:appflowy/workspace/presentation/settings/shared/settings_category.dart'; +import 'package:appflowy/workspace/presentation/settings/shared/settings_category_spacer.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/feature_flags/feature_flag_page.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/members/workspace_member_page.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_notifications_view.dart'; +import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; +import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'widgets/setting_cloud.dart'; @@ -28,11 +38,11 @@ class SettingsDialog extends StatelessWidget { this.initPage, }) : super(key: ValueKey(user.id)); + final UserProfilePB user; + final SettingsPage? initPage; final VoidCallback dismissDialog; final VoidCallback didLogout; final VoidCallback restartApp; - final UserProfilePB user; - final SettingsPage? initPage; @override Widget build(BuildContext context) { @@ -144,3 +154,164 @@ class SettingsDialog extends StatelessWidget { } } } + +class SimpleSettingsDialog extends StatefulWidget { + const SimpleSettingsDialog({super.key}); + + @override + State createState() => _SimpleSettingsDialogState(); +} + +class _SimpleSettingsDialogState extends State { + SettingsPage page = SettingsPage.cloud; + + @override + Widget build(BuildContext context) { + return FlowyDialog( + width: MediaQuery.of(context).size.width * 0.7, + constraints: const BoxConstraints(maxWidth: 784, minWidth: 564), + child: const Padding( + padding: EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // language + _LanguageSettings(), + SettingsCategorySpacer(), + // self-host cloud + _SelfHostSettings(), + SettingsCategorySpacer(), + // support + _SupportSettings(), + ], + ), + ), + ); + } +} + +class _LanguageSettings extends StatelessWidget { + const _LanguageSettings(); + + @override + Widget build(BuildContext context) { + return SettingsCategory( + title: LocaleKeys.settings_workspacePage_language_title.tr(), + children: const [LanguageDropdown()], + ); + } +} + +class _SelfHostSettings extends StatefulWidget { + const _SelfHostSettings(); + + @override + State<_SelfHostSettings> createState() => _SelfHostSettingsState(); +} + +class _SelfHostSettingsState extends State<_SelfHostSettings> { + final textController = TextEditingController(); + + @override + void initState() { + super.initState(); + + getAppFlowyCloudUrl().then((url) { + textController.text = url; + }); + } + + @override + void dispose() { + textController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SettingsCategory( + title: LocaleKeys.settings_menu_cloudAppFlowySelfHost.tr(), + children: [ + SizedBox( + height: 48, + child: FlowyTextField( + controller: textController, + autoFocus: false, + textStyle: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + ), + onEditingComplete: _saveSelfHostUrl, + ), + ), + ], + ); + } + + void _saveSelfHostUrl() { + final url = textController.text; + if (url.isEmpty) { + return; + } + + validateUrl(url).fold( + (url) async { + Navigator.of(context).pop(); + await useSelfHostedAppFlowyCloudWithURL(url); + await runAppFlowy(); + }, + (err) => Log.error(err), + ); + } +} + +class _SupportSettings extends StatelessWidget { + const _SupportSettings(); + + @override + Widget build(BuildContext context) { + return SettingsCategory( + title: LocaleKeys.settings_mobile_support.tr(), + children: [ + // export logs + Row( + children: [ + FlowyText( + LocaleKeys.workspace_errorActions_exportLogFiles.tr(), + ), + const Spacer(), + OutlinedRoundedButton( + text: LocaleKeys.settings_files_export.tr(), + onTap: () { + shareLogFiles(context); + }, + ), + ], + ), + // clear cache + Row( + children: [ + FlowyText( + LocaleKeys.settings_files_clearCache.tr(), + ), + const Spacer(), + OutlinedRoundedButton( + text: LocaleKeys.button_clear.tr(), + onTap: () async { + await getIt().clearAllCache(); + if (context.mounted) { + showToastNotification( + context, + message: LocaleKeys + .settings_manageDataPage_cache_dialog_successHint + .tr(), + ); + } + }, + ), + ], + ), + ], + ); + } +} diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_cloud.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_cloud.dart index 10f4d66e4d..3f84d525e2 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_cloud.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_cloud.dart @@ -23,7 +23,10 @@ import 'package:universal_platform/universal_platform.dart'; import 'setting_appflowy_cloud.dart'; class SettingCloud extends StatelessWidget { - const SettingCloud({required this.restartAppFlowy, super.key}); + const SettingCloud({ + super.key, + required this.restartAppFlowy, + }); final VoidCallback restartAppFlowy; diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart index 38cd49831d..fbb1cf5801 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_menu.dart @@ -1,6 +1,3 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/shared/feature_flags.dart'; @@ -9,6 +6,8 @@ import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_e import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; class SettingsMenu extends StatelessWidget { const SettingsMenu({ @@ -147,3 +146,56 @@ class SettingsMenu extends StatelessWidget { ); } } + +class SimpleSettingsMenu extends StatelessWidget { + const SimpleSettingsMenu({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8) + + const EdgeInsets.only(left: 8, right: 4), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8), + ), + ), + child: SingleChildScrollView( + // Right padding is added to make the scrollbar centered + // in the space between the menu and the content + padding: const EdgeInsets.only(right: 4) + + const EdgeInsets.symmetric(vertical: 16), + physics: const ClampingScrollPhysics(), + child: SeparatedColumn( + separatorBuilder: () => const VSpace(16), + children: [ + SettingsMenuElement( + page: SettingsPage.cloud, + selectedPage: SettingsPage.cloud, + label: LocaleKeys.settings_menu_cloudSettings.tr(), + icon: const Icon(Icons.sync), + changeSelectedPage: () {}, + ), + if (kDebugMode) + SettingsMenuElement( + // no need to translate this page + page: SettingsPage.featureFlags, + selectedPage: SettingsPage.cloud, + label: 'Feature Flags', + icon: const Icon(Icons.flag), + changeSelectedPage: () {}, + ), + ], + ), + ), + ), + ), + ], + ); + } +} diff --git a/frontend/appflowy_flutter/macos/Podfile.lock b/frontend/appflowy_flutter/macos/Podfile.lock index 300519a5dc..f33b8850f0 100644 --- a/frontend/appflowy_flutter/macos/Podfile.lock +++ b/frontend/appflowy_flutter/macos/Podfile.lock @@ -25,6 +25,8 @@ PODS: - FlutterMacOS - local_notifier (0.1.0): - FlutterMacOS + - open_file_mac (0.0.1): + - FlutterMacOS - package_info_plus (0.0.1): - FlutterMacOS - path_provider_foundation (0.0.1): @@ -66,6 +68,7 @@ DEPENDENCIES: - hotkey_manager (from `Flutter/ephemeral/.symlinks/plugins/hotkey_manager/macos`) - irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`) - local_notifier (from `Flutter/ephemeral/.symlinks/plugins/local_notifier/macos`) + - open_file_mac (from `Flutter/ephemeral/.symlinks/plugins/open_file_mac/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) @@ -108,6 +111,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos local_notifier: :path: Flutter/ephemeral/.symlinks/plugins/local_notifier/macos + open_file_mac: + :path: Flutter/ephemeral/.symlinks/plugins/open_file_mac/macos package_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos path_provider_foundation: @@ -143,6 +148,7 @@ SPEC CHECKSUMS: hotkey_manager: c32bf0bfe8f934b7bc17ab4ad5c4c142960b023c irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478 local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff + open_file_mac: 0e554648e2a87ce59e9438e3e5ca3e552e90d89a package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979