feat: support creating database at the first level (#5627)

* feat: support creating database at the first level

* chore: add loading indicator when importing file
This commit is contained in:
Lucas.Xu 2024-06-26 13:27:33 +08:00 committed by GitHub
parent 7d96c2dfd4
commit f812040f04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 122 additions and 71 deletions

View File

@ -54,6 +54,7 @@ class _MobileSpaceState extends State<MobileSpace> {
context.read<SpaceBloc>().add(
SpaceEvent.createPage(
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout: ViewLayoutPB.Document,
index: 0,
),
);
@ -99,6 +100,7 @@ class _MobileSpaceState extends State<MobileSpace> {
context.read<SpaceBloc>().add(
SpaceEvent.createPage(
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout: ViewLayoutPB.Document,
),
);
}

View File

@ -124,6 +124,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
SpaceEvent.createPage(
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
index: 0,
layout: ViewLayoutPB.Document,
),
);
}
@ -216,7 +217,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
await _setSpaceExpandStatus(space, isExpanded);
emit(state.copyWith(isExpanded: isExpanded));
},
createPage: (name, index) async {
createPage: (name, layout, index) async {
final parentViewId = state.currentSpace?.id;
if (parentViewId == null) {
return;
@ -224,7 +225,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
final result = await ViewBackendService.createView(
name: name,
layoutType: ViewLayoutPB.Document,
layoutType: layout,
parentViewId: parentViewId,
index: index,
);
@ -631,6 +632,7 @@ class SpaceEvent with _$SpaceEvent {
const factory SpaceEvent.expand(ViewPB space, bool isExpanded) = _Expand;
const factory SpaceEvent.createPage({
required String name,
required ViewLayoutPB layout,
int? index,
}) = _CreatePage;
const factory SpaceEvent.delete(ViewPB? space) = _Delete;

View File

@ -158,7 +158,7 @@ class DesktopHomeScreen extends StatelessWidget {
delegate: DesktopHomeScreenStackAdaptor(context),
userProfile: userProfile,
);
final menu = _buildHomeSidebar(
final sidebar = _buildHomeSidebar(
context,
layout: layout,
userProfile: userProfile,
@ -170,7 +170,7 @@ class DesktopHomeScreen extends StatelessWidget {
return _layoutWidgets(
layout: layout,
homeStack: homeStack,
homeMenu: menu,
sidebar: sidebar,
editPanel: editPanel,
bubble: const QuestionBubble(),
homeMenuResizer: homeMenuResizer,
@ -253,7 +253,7 @@ class DesktopHomeScreen extends StatelessWidget {
Widget _layoutWidgets({
required HomeLayout layout,
required Widget homeMenu,
required Widget sidebar,
required Widget homeStack,
required Widget editPanel,
required Widget bubble,
@ -287,7 +287,7 @@ class DesktopHomeScreen extends StatelessWidget {
bottom: 0,
width: layout.editPanelWidth,
),
homeMenu
sidebar
.animatedPanelX(
closeX: -layout.menuWidth,
isClosed: !layout.showMenu,

View File

@ -1,19 +1,21 @@
import 'dart:convert';
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/migration/editor_migration.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/settings/share/import_service.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/import/import_type.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/container.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as p;
@ -67,10 +69,12 @@ class ImportPanel extends StatefulWidget {
class _ImportPanelState extends State<ImportPanel> {
final flowyContainerFocusNode = FocusNode();
final ValueNotifier<bool> showLoading = ValueNotifier(false);
@override
void dispose() {
flowyContainerFocusNode.dispose();
showLoading.dispose();
super.dispose();
}
@ -87,37 +91,52 @@ class _ImportPanelState extends State<ImportPanel> {
FlowyOverlay.pop(context);
}
},
child: FlowyContainer(
Theme.of(context).colorScheme.surface,
height: height,
width: width,
child: GridView.count(
childAspectRatio: 1 / .2,
crossAxisCount: 2,
children: ImportType.values
.where((element) => element.enableOnRelease)
.map(
(e) => Card(
child: FlowyButton(
leftIcon: e.icon(context),
leftIconSize: const Size.square(20),
text: FlowyText.medium(
e.toString(),
fontSize: 15,
overflow: TextOverflow.ellipsis,
color: Theme.of(context).colorScheme.tertiary,
child: Stack(
children: [
FlowyContainer(
Theme.of(context).colorScheme.surface,
height: height,
width: width,
child: GridView.count(
childAspectRatio: 1 / .2,
crossAxisCount: 2,
children: ImportType.values
.where((element) => element.enableOnRelease)
.map(
(e) => Card(
child: FlowyButton(
leftIcon: e.icon(context),
leftIconSize: const Size.square(20),
text: FlowyText.medium(
e.toString(),
fontSize: 15,
overflow: TextOverflow.ellipsis,
color: Theme.of(context).colorScheme.tertiary,
),
onTap: () async {
await _importFile(widget.parentViewId, e);
if (context.mounted) {
FlowyOverlay.pop(context);
}
},
),
),
onTap: () async {
await _importFile(widget.parentViewId, e);
if (context.mounted) {
FlowyOverlay.pop(context);
}
},
),
),
)
.toList(),
),
)
.toList(),
),
),
ValueListenableBuilder(
valueListenable: showLoading,
builder: (context, showLoading, child) {
if (!showLoading) {
return const SizedBox.shrink();
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
],
),
);
}
@ -132,6 +151,8 @@ class _ImportPanelState extends State<ImportPanel> {
return;
}
showLoading.value = true;
for (final file in result.files) {
final path = file.path;
if (path == null) {
@ -145,43 +166,60 @@ class _ImportPanelState extends State<ImportPanel> {
case ImportType.historyDocument:
final bytes = _documentDataFrom(importType, data);
if (bytes != null) {
await ImportBackendService.importData(
final result = await ImportBackendService.importData(
bytes,
name,
parentViewId,
ImportTypePB.HistoryDocument,
);
result.onFailure((error) {
showSnackBarMessage(context, error.msg);
Log.error('Failed to import markdown $error');
});
}
break;
case ImportType.historyDatabase:
await ImportBackendService.importData(
final result = await ImportBackendService.importData(
utf8.encode(data),
name,
parentViewId,
ImportTypePB.HistoryDatabase,
);
result.onFailure((error) {
showSnackBarMessage(context, error.msg);
Log.error('Failed to import history database $error');
});
break;
case ImportType.databaseRawData:
await ImportBackendService.importData(
final result = await ImportBackendService.importData(
utf8.encode(data),
name,
parentViewId,
ImportTypePB.RawDatabase,
);
result.onFailure((error) {
showSnackBarMessage(context, error.msg);
Log.error('Failed to import database raw data $error');
});
break;
case ImportType.databaseCSV:
await ImportBackendService.importData(
final result = await ImportBackendService.importData(
utf8.encode(data),
name,
parentViewId,
ImportTypePB.CSV,
);
result.onFailure((error) {
showSnackBarMessage(context, error.msg);
Log.error('Failed to import CSV $error');
});
break;
default:
assert(false, 'Unsupported Type $importType');
}
}
showLoading.value = false;
widget.importCallback(importType, '', null);
}
}

View File

@ -55,6 +55,7 @@ class SidebarNewPageButton extends StatelessWidget {
SpaceEvent.createPage(
name: viewName,
index: 0,
layout: ViewLayoutPB.Document,
),
);
} else {

View File

@ -6,7 +6,6 @@ import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/favorites/favorite_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/rename_view_dialog.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/create_space_popup.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart';
@ -103,7 +102,11 @@ class _SpaceState extends State<_Space> {
SidebarSpaceHeader(
isExpanded: state.isExpanded,
space: currentSpace,
onAdded: () => _showCreatePagePopup(context, currentSpace),
onAdded: (layout) => _showCreatePagePopup(
context,
currentSpace,
layout,
),
onCreateNewSpace: () => _showCreateSpaceDialog(context),
onCollapseAllPages: () => isExpandedNotifier.value = true,
),
@ -150,23 +153,20 @@ class _SpaceState extends State<_Space> {
);
}
void _showCreatePagePopup(BuildContext context, ViewPB space) {
createViewAndShowRenameDialogIfNeeded(
context,
LocaleKeys.newPageText.tr(),
(viewName, _) {
if (viewName.isNotEmpty) {
context.read<SpaceBloc>().add(
SpaceEvent.createPage(
name: viewName,
index: 0,
),
);
void _showCreatePagePopup(
BuildContext context,
ViewPB space,
ViewLayoutPB layout,
) {
context.read<SpaceBloc>().add(
SpaceEvent.createPage(
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout: layout,
index: 0,
),
);
context.read<SpaceBloc>().add(SpaceEvent.expand(space, true));
}
},
);
context.read<SpaceBloc>().add(SpaceEvent.expand(space, true));
}
void _switchToNextSpace() {

View File

@ -1,6 +1,5 @@
import 'dart:io';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
@ -9,6 +8,7 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/manage_s
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_action_type.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
@ -29,7 +29,7 @@ class SidebarSpaceHeader extends StatefulWidget {
});
final ViewPB space;
final VoidCallback onAdded;
final void Function(ViewLayoutPB layout) onAdded;
final VoidCallback onCreateNewSpace;
final VoidCallback onCollapseAllPages;
final bool isExpanded;
@ -87,7 +87,7 @@ class _SidebarSpaceHeaderState extends State<SidebarSpaceHeader> {
left: 3,
top: 3,
bottom: 3,
right: isHovered.value || onEditing ? 66 : 0,
right: isHovered.value || onEditing ? 88 : 0,
child: SpacePopup(
child: _buildChild(),
),
@ -144,12 +144,20 @@ class _SidebarSpaceHeaderState extends State<SidebarSpaceHeader> {
onAction: _onAction,
),
const HSpace(8.0),
FlowyIconButton(
width: 24,
tooltipText: LocaleKeys.sideBar_addAPage.tr(),
iconPadding: const EdgeInsets.all(4.0),
icon: const FlowySvg(FlowySvgs.view_item_add_s),
onPressed: widget.onAdded,
ViewAddButton(
parentViewId: widget.space.id,
onEditing: (_) {},
onSelected: (
pluginBuilder,
name,
initialDataBytes,
openAfterCreated,
createNewView,
) {
if (createNewView) {
widget.onAdded(pluginBuilder.layoutType!);
}
},
),
],
),