feat: show indicator when importing appflowy data (#4357)

* feat: show indicator when importing appflowy data

* Update frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/setting_file_import_appflowy_data_view.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* chore: fix analyzer

* chore: fix test

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
This commit is contained in:
Nathan.fooo 2024-01-11 09:44:33 +08:00 committed by GitHub
parent b1cc4e485b
commit 6e41359fc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 103 additions and 62 deletions

View File

@ -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<Unit, FlowyError> successOrFail,

View File

@ -103,6 +103,7 @@ class BoardPage extends StatelessWidget {
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
),
),
idle: (_) => const SizedBox.shrink(),
),
),
);

View File

@ -131,6 +131,7 @@ class _GridPageState extends State<GridPage> {
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
),
),
idle: (_) => const SizedBox.shrink(),
);
},
),

View File

@ -97,6 +97,7 @@ class _MobileGridPageState extends State<MobileGridPage> {
howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(),
),
),
idle: (_) => const SizedBox.shrink(),
);
},
),

View File

@ -14,17 +14,20 @@ class DeviceOrApplicationInfoTask extends LaunchTask {
@override
Future<void> 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;
}
}
}

View File

@ -75,7 +75,11 @@ class EncryptSecretBloc extends Bloc<EncryptSecretEvent, EncryptSecretState> {
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;
}

View File

@ -69,6 +69,7 @@ class _EncryptSecretScreenState extends State<EncryptSecretScreen> {
child: CircularProgressIndicator.adaptive(),
),
finish: (result) => const SizedBox.shrink(),
idle: () => const SizedBox.shrink(),
) ??
const SizedBox.shrink();
return Center(

View File

@ -70,6 +70,7 @@ class WorkspaceErrorScreen extends StatelessWidget {
},
);
},
idle: () {},
);
},
),

View File

@ -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<SettingFileImportEvent, SettingFileImportState> {
SettingFileImporterBloc() : super(SettingFileImportState.initial()) {
on<SettingFileImportEvent>((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<SettingFileImportEvent>(
(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<Unit, FlowyError> result,
) = _ImportResult;
}
@freezed
class SettingFileImportState with _$SettingFileImportState {
const factory SettingFileImportState({
required LoadingState loadingState,
required Option<Either<Unit, FlowyError>> successOrFail,
}) = _SettingFileImportState;
factory SettingFileImportState.initial() => SettingFileImportState(
loadingState: const LoadingState.idle(),
successOrFail: none(),
);
}

View File

@ -30,8 +30,8 @@ class _ImportAppFlowyDataState extends State<ImportAppFlowyData> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SettingFileImporterBloc(),
child: BlocListener<SettingFileImporterBloc, SettingFileImportState>(
create: (context) => SettingFileImportBloc(),
child: BlocListener<SettingFileImportBloc, SettingFileImportState>(
listener: (context, state) {
state.successOrFail.fold(
() {},
@ -47,7 +47,7 @@ class _ImportAppFlowyDataState extends State<ImportAppFlowyData> {
},
);
},
child: BlocBuilder<SettingFileImporterBloc, SettingFileImportState>(
child: BlocBuilder<SettingFileImportBloc, SettingFileImportState>(
builder: (context, state) {
return const Column(
children: [
@ -120,24 +120,33 @@ class ImportAppFlowyDataButton extends StatefulWidget {
class _ImportAppFlowyDataButtonState extends State<ImportAppFlowyDataButton> {
@override
Widget build(BuildContext context) {
return SizedBox(
height: 40,
child: FlowyButton(
text: FlowyText(LocaleKeys.settings_menu_importAppFlowyData.tr()),
onTap: () async {
final path = await getIt<FilePickerService>().getDirectoryPath();
if (path == null) {
return;
}
if (!mounted) {
return;
}
return BlocBuilder<SettingFileImportBloc, SettingFileImportState>(
builder: (context, state) {
return Column(
children: [
SizedBox(
height: 40,
child: FlowyButton(
text:
FlowyText(LocaleKeys.settings_menu_importAppFlowyData.tr()),
onTap: () async {
final path =
await getIt<FilePickerService>().getDirectoryPath();
if (path == null || !mounted) {
return;
}
context
.read<SettingFileImporterBloc>()
.add(SettingFileImportEvent.importAppFlowyDataFolder(path));
},
),
context.read<SettingFileImportBloc>().add(
SettingFileImportEvent.importAppFlowyDataFolder(path),
);
},
),
),
if (state.loadingState.isLoading())
const LinearProgressIndicator(minHeight: 1),
],
);
},
);
}
}

View File

@ -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(