diff --git a/frontend/appflowy_flutter/lib/plugins/database/application/defines.dart b/frontend/appflowy_flutter/lib/plugins/database/application/defines.dart index 44a67e7ecb..1ad4a9ea1c 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/application/defines.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/application/defines.dart @@ -34,6 +34,7 @@ typedef OnError = void Function(FlowyError); @freezed class LoadingState with _$LoadingState { + const factory LoadingState.idle() = _Idle; const factory LoadingState.loading() = _Loading; const factory LoadingState.finish( Either successOrFail, diff --git a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart index f760b4afb9..fd88098a29 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/board/presentation/board_page.dart @@ -103,6 +103,7 @@ class BoardPage extends StatelessWidget { howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(), ), ), + idle: (_) => const SizedBox.shrink(), ), ), ); diff --git a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/grid_page.dart b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/grid_page.dart index 295262f9cd..75a8b5bad7 100755 --- a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/grid_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/grid_page.dart @@ -131,6 +131,7 @@ class _GridPageState extends State { howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(), ), ), + idle: (_) => const SizedBox.shrink(), ); }, ), diff --git a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/mobile_grid_page.dart b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/mobile_grid_page.dart index 51fbbed209..c035839841 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/mobile_grid_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/mobile_grid_page.dart @@ -97,6 +97,7 @@ class _MobileGridPageState extends State { howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(), ), ), + idle: (_) => const SizedBox.shrink(), ); }, ), diff --git a/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart b/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart index 61225b8f58..27c339ddb5 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/device_info_task.dart @@ -14,17 +14,20 @@ class DeviceOrApplicationInfoTask extends LaunchTask { @override Future initialize(LaunchContext context) async { - final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); - final PackageInfo packageInfo = await PackageInfo.fromPlatform(); + // Can't get the device info from test environment + if (!context.env.isTest) { + final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + final PackageInfo packageInfo = await PackageInfo.fromPlatform(); - if (Platform.isAndroid) { - final androidInfo = await deviceInfoPlugin.androidInfo; - androidSDKVersion = androidInfo.version.sdkInt; - } + if (Platform.isAndroid) { + final androidInfo = await deviceInfoPlugin.androidInfo; + androidSDKVersion = androidInfo.version.sdkInt; + } - if (Platform.isAndroid || Platform.isIOS) { - applicationVersion = packageInfo.version; - buildNumber = packageInfo.buildNumber; + if (Platform.isAndroid || Platform.isIOS) { + applicationVersion = packageInfo.version; + buildNumber = packageInfo.buildNumber; + } } } diff --git a/frontend/appflowy_flutter/lib/user/application/encrypt_secret_bloc.dart b/frontend/appflowy_flutter/lib/user/application/encrypt_secret_bloc.dart index 4f7cab794c..1abb16b98b 100644 --- a/frontend/appflowy_flutter/lib/user/application/encrypt_secret_bloc.dart +++ b/frontend/appflowy_flutter/lib/user/application/encrypt_secret_bloc.dart @@ -75,7 +75,11 @@ class EncryptSecretBloc extends Bloc { bool isLoading() { final loadingState = state.loadingState; if (loadingState != null) { - return loadingState.when(loading: () => true, finish: (_) => false); + return loadingState.when( + loading: () => true, + finish: (_) => false, + idle: () => false, + ); } return false; } diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/encrypt_secret_screen.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/encrypt_secret_screen.dart index 0567421d7a..7d4fe83b61 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/encrypt_secret_screen.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/encrypt_secret_screen.dart @@ -69,6 +69,7 @@ class _EncryptSecretScreenState extends State { child: CircularProgressIndicator.adaptive(), ), finish: (result) => const SizedBox.shrink(), + idle: () => const SizedBox.shrink(), ) ?? const SizedBox.shrink(); return Center( diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/workspace_error_screen.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/workspace_error_screen.dart index b1654e2f0a..7d29ba460d 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/workspace_error_screen.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/workspace_error_screen.dart @@ -70,6 +70,7 @@ class WorkspaceErrorScreen extends StatelessWidget { }, ); }, + idle: () {}, ); }, ), diff --git a/frontend/appflowy_flutter/lib/workspace/application/settings/setting_file_importer_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/settings/setting_file_importer_bloc.dart index 86adaf80fc..320de5f43d 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/settings/setting_file_importer_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/settings/setting_file_importer_bloc.dart @@ -1,3 +1,4 @@ +import 'package:appflowy/plugins/database/application/defines.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; @@ -9,39 +10,51 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'setting_file_importer_bloc.freezed.dart'; -class SettingFileImporterBloc +class SettingFileImportBloc extends Bloc { - SettingFileImporterBloc() : super(SettingFileImportState.initial()) { - on((event, emit) async { - await event.when( - importAppFlowyDataFolder: (String path) async { - final formattedDate = - DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); - final payload = ImportAppFlowyDataPB.create() - ..path = path - ..importContainerName = "appflowy_import_$formattedDate"; - final result = - await FolderEventImportAppFlowyDataFolder(payload).send(); - result.fold( - (l) { - emit( - state.copyWith( - successOrFail: some(left(unit)), - ), - ); - }, - (err) { - Log.error(err); - emit( - state.copyWith( - successOrFail: some(right(err)), - ), - ); - }, - ); - }, - ); - }); + SettingFileImportBloc() : super(SettingFileImportState.initial()) { + on( + (event, emit) async { + await event.when( + importAppFlowyDataFolder: (String path) async { + final formattedDate = + DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + final payload = ImportAppFlowyDataPB.create() + ..path = path + ..importContainerName = "appflowy_import_$formattedDate"; + emit( + state.copyWith(loadingState: const LoadingState.loading()), + ); + FolderEventImportAppFlowyDataFolder(payload).send().then((result) { + if (!isClosed) { + add(SettingFileImportEvent.finishImport(result)); + } + }); + }, + finishImport: (result) { + result.fold( + (l) { + emit( + state.copyWith( + successOrFail: some(left(unit)), + loadingState: LoadingState.finish(left(unit)), + ), + ); + }, + (err) { + Log.error(err); + emit( + state.copyWith( + successOrFail: some(right(err)), + loadingState: LoadingState.finish(right(err)), + ), + ); + }, + ); + }, + ); + }, + ); } } @@ -49,15 +62,20 @@ class SettingFileImporterBloc class SettingFileImportEvent with _$SettingFileImportEvent { const factory SettingFileImportEvent.importAppFlowyDataFolder(String path) = _ImportAppFlowyDataFolder; + const factory SettingFileImportEvent.finishImport( + Either result, + ) = _ImportResult; } @freezed class SettingFileImportState with _$SettingFileImportState { const factory SettingFileImportState({ + required LoadingState loadingState, required Option> successOrFail, }) = _SettingFileImportState; factory SettingFileImportState.initial() => SettingFileImportState( + loadingState: const LoadingState.idle(), successOrFail: none(), ); } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_file_import_appflowy_data_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_file_import_appflowy_data_view.dart index 7d8d19dcf9..e2dc2e582d 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_file_import_appflowy_data_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_file_import_appflowy_data_view.dart @@ -30,8 +30,8 @@ class _ImportAppFlowyDataState extends State { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => SettingFileImporterBloc(), - child: BlocListener( + create: (context) => SettingFileImportBloc(), + child: BlocListener( listener: (context, state) { state.successOrFail.fold( () {}, @@ -47,7 +47,7 @@ class _ImportAppFlowyDataState extends State { }, ); }, - child: BlocBuilder( + child: BlocBuilder( builder: (context, state) { return const Column( children: [ @@ -120,24 +120,33 @@ class ImportAppFlowyDataButton extends StatefulWidget { class _ImportAppFlowyDataButtonState extends State { @override Widget build(BuildContext context) { - return SizedBox( - height: 40, - child: FlowyButton( - text: FlowyText(LocaleKeys.settings_menu_importAppFlowyData.tr()), - onTap: () async { - final path = await getIt().getDirectoryPath(); - if (path == null) { - return; - } - if (!mounted) { - return; - } + return BlocBuilder( + builder: (context, state) { + return Column( + children: [ + SizedBox( + height: 40, + child: FlowyButton( + text: + FlowyText(LocaleKeys.settings_menu_importAppFlowyData.tr()), + onTap: () async { + final path = + await getIt().getDirectoryPath(); + if (path == null || !mounted) { + return; + } - context - .read() - .add(SettingFileImportEvent.importAppFlowyDataFolder(path)); - }, - ), + context.read().add( + SettingFileImportEvent.importAppFlowyDataFolder(path), + ); + }, + ), + ), + if (state.loadingState.isLoading()) + const LinearProgressIndicator(minHeight: 1), + ], + ); + }, ); } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_supabase_cloud.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_supabase_cloud.dart index b2b2ccccdd..72ac7d641f 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_supabase_cloud.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_supabase_cloud.dart @@ -154,6 +154,7 @@ class EnableEncrypt extends StatelessWidget { final indicator = state.loadingState.when( loading: () => const CircularProgressIndicator.adaptive(), finish: (successOrFail) => const SizedBox.shrink(), + idle: () => const SizedBox.shrink(), ); return Column(