Skip to content

Commit

Permalink
feat: support creating subpage block in row detail page (#6824)
Browse files Browse the repository at this point in the history
* feat: support creating subpage block in row detail page

* feat: hide the row page from sidebar

* test: support creating a sub-page block in row detail page

* fix: update drag block logic

* feat: support toggle heading in outline

* test: add toggle headings show in outline block test

* fix: unable to get focus when opening subpage from card
  • Loading branch information
LucasXu0 authored Nov 19, 2024
1 parent df7fe97 commit c24b684
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 143 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import 'package:appflowy/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_checklist_cell.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';

import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/desktop_field_cell.dart';
import 'package:appflowy/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_checklist_cell.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/document/document_page.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.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/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
Expand Down Expand Up @@ -76,6 +76,24 @@ void main() {
// The number of emoji should be two. One in the row displayed in the grid
// one in the row detail page.
expect(emojiText, findsNWidgets(2));

// insert a sub page in database
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.pumpAndSettle();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_subPage_name.tr(),
offset: 100,
);
await tester.pumpAndSettle();

// the row detail page should be closed
final rowDetailPage = find.byType(RowDetailPage);
await tester.pumpUntilNotFound(rowDetailPage);

// expect to see a document page
final documentPage = find.byType(DocumentPage);
expect(documentPage, findsOneWidget);
});

testWidgets('remove emoji', (tester) async {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import 'dart:io';

import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/sub_page/sub_page_block_component.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

Expand Down Expand Up @@ -43,6 +44,9 @@ void main() {
* # Heading 1
* ## Heading 2
* ### Heading 3
* > # Heading 1
* > ## Heading 2
* > ### Heading 3
*/

await tester.editor.tapLineOfEditorAt(3);
Expand All @@ -53,7 +57,7 @@ void main() {
of: find.byType(OutlineBlockWidget),
matching: find.text(heading1),
),
findsOneWidget,
findsNWidgets(2),
);

// Heading 2 is prefixed with a bullet
Expand All @@ -62,7 +66,7 @@ void main() {
of: find.byType(OutlineBlockWidget),
matching: find.text(heading2),
),
findsOneWidget,
findsNWidgets(2),
);

// Heading 3 is prefixed with a dash
Expand All @@ -71,7 +75,7 @@ void main() {
of: find.byType(OutlineBlockWidget),
matching: find.text(heading3),
),
findsOneWidget,
findsNWidgets(2),
);

// update the Heading 1 to Heading 1Hello world
Expand Down Expand Up @@ -99,13 +103,16 @@ void main() {
* # Heading 1
* ## Heading 2
* ### Heading 3
* > # Heading 1
* > ## Heading 2
* > ### Heading 3
*/

await tester.editor.tapLineOfEditorAt(3);
await tester.editor.tapLineOfEditorAt(7);
await insertOutlineInDocument(tester);

// expect to find only the `heading1` widget under the [OutlineBlockWidget]
await hoverAndClickDepthOptionAction(tester, [3], 1);
await hoverAndClickDepthOptionAction(tester, [6], 1);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
Expand All @@ -123,7 +130,7 @@ void main() {
//////
/// expect to find only the 'heading1' and 'heading2' under the [OutlineBlockWidget]
await hoverAndClickDepthOptionAction(tester, [3], 2);
await hoverAndClickDepthOptionAction(tester, [6], 2);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
Expand All @@ -134,29 +141,29 @@ void main() {
//////
// expect to find all the headings under the [OutlineBlockWidget]
await hoverAndClickDepthOptionAction(tester, [3], 3);
await hoverAndClickDepthOptionAction(tester, [6], 3);
expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading1),
),
findsOneWidget,
findsNWidgets(2),
);

expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading2),
),
findsOneWidget,
findsNWidgets(2),
);

expect(
find.descendant(
of: find.byType(OutlineBlockWidget),
matching: find.text(heading3),
),
findsOneWidget,
findsNWidgets(2),
);
//////
});
Expand Down Expand Up @@ -186,7 +193,17 @@ Future<void> hoverAndClickDepthOptionAction(

Future<void> insertHeadingComponent(WidgetTester tester) async {
await tester.editor.tapLineOfEditorAt(0);

// # heading 1-3
await tester.ime.insertText('# $heading1\n');
await tester.ime.insertText('## $heading2\n');
await tester.ime.insertText('### $heading3\n');

// > # toggle heading 1-3
await tester.ime.insertText('> # $heading1\n');
await tester.simulateKeyEvent(LogicalKeyboardKey.backspace);
await tester.ime.insertText('> ## $heading2\n');
await tester.simulateKeyEvent(LogicalKeyboardKey.backspace);
await tester.ime.insertText('> ### $heading3\n');
await tester.simulateKeyEvent(LogicalKeyboardKey.backspace);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import 'package:appflowy/plugins/document/presentation/editor_drop_manager.dart';
import 'package:flutter/material.dart';

import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/row/row_document_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_drop_handler.dart';
import 'package:appflowy/plugins/document/presentation/editor_drop_manager.dart';
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/shared_context/shared_context.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/shared/flowy_error_page.dart';
import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';

class RowDocument extends StatelessWidget {
const RowDocument({
Expand Down Expand Up @@ -103,23 +105,35 @@ class _RowEditor extends StatelessWidget {
child: IntrinsicHeight(
child: Container(
constraints: const BoxConstraints(minHeight: 300),
child: EditorDropHandler(
viewId: view.id,
editorState: editorState,
isLocalMode: context.read<DocumentBloc>().isLocalMode,
dropManagerState: context.read<EditorDropManagerState>(),
child: AppFlowyEditorPage(
shrinkWrap: true,
autoFocus: false,
child: Provider(
create: (_) {
final context = SharedEditorContext();
context.isInDatabaseRowPage = true;
return context;
},
dispose: (_, editorContext) => editorContext.dispose(),
child: EditorDropHandler(
viewId: view.id,
editorState: editorState,
styleCustomizer: EditorStyleCustomizer(
context: context,
padding: const EdgeInsets.only(left: 16, right: 54),
isLocalMode: context.read<DocumentBloc>().isLocalMode,
dropManagerState: context.read<EditorDropManagerState>(),
child: EditorTransactionService(
viewId: view.id,
editorState: editorState,
child: AppFlowyEditorPage(
shrinkWrap: true,
autoFocus: false,
editorState: editorState,
styleCustomizer: EditorStyleCustomizer(
context: context,
padding: const EdgeInsets.only(left: 16, right: 54),
),
showParagraphPlaceholder: (editorState, _) =>
editorState.document.isEmpty,
placeholderText: (_) =>
LocaleKeys.cardDetails_notesPlaceholder.tr(),
),
),
showParagraphPlaceholder: (editorState, _) =>
editorState.document.isEmpty,
placeholderText: (_) =>
LocaleKeys.cardDetails_notesPlaceholder.tr(),
),
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import 'package:appflowy/plugins/document/presentation/editor_drop_handler.dart';
import 'package:flutter/material.dart';

import 'package:appflowy/plugins/database/application/row/related_row_detail_bloc.dart';
import 'package:appflowy/plugins/database/grid/application/row/row_detail_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
Expand All @@ -9,8 +6,10 @@ import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/database/widgets/row/row_property.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/banner.dart';
import 'package:appflowy/plugins/document/presentation/editor_drop_handler.dart';
import 'package:appflowy/plugins/document/presentation/editor_notification.dart';
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/transaction_handler/editor_transaction_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/shared/flowy_error_page.dart';
import 'package:appflowy/startup/startup.dart';
Expand All @@ -19,6 +18,7 @@ import 'package:appflowy/workspace/application/action_navigation/navigation_acti
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// This widget is largely copied from `plugins/document/document_page.dart` intentionally instead of opting for an abstraction. We can make an abstraction after the view refactor is done and there's more clarity in that department.
Expand Down Expand Up @@ -122,11 +122,15 @@ class _DatabaseDocumentPageState extends State<DatabaseDocumentPage> {
),
);

return Column(
children: [
if (state.isDeleted) _buildBanner(context),
Expanded(child: appflowyEditorPage),
],
return EditorTransactionService(
viewId: widget.view.id,
editorState: state.editorState!,
child: Column(
children: [
if (state.isDeleted) _buildBanner(context),
Expanded(child: appflowyEditorPage),
],
),
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'package:flutter/material.dart';

import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
Expand All @@ -13,6 +11,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:collection/collection.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 'database_document_title_bloc.dart';
Expand Down Expand Up @@ -192,6 +191,8 @@ class _TitleSkin extends IEditableTextCellSkin {
child: FlowyText.regular(
name,
overflow: TextOverflow.ellipsis,
fontSize: 14.0,
figmaLineHeight: 18.0,
),
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ class _DocumentPageState extends State<DocumentPage>
create: (_) {
final context = SharedEditorContext();
if (widget.view.name.isEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.coverTitleFocusNode.requestFocus();
});
context.requestCoverTitleFocus = true;
}
return context;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import 'package:appflowy/workspace/presentation/home/af_focus_manager.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:collection/collection.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
Expand Down Expand Up @@ -348,7 +347,10 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage>
// if the last one isn't a empty node, insert a new empty node.
await _focusOnLastEmptyParagraph();
},
child: VSpace(UniversalPlatform.isDesktopOrWeb ? 200 : 400),
child: SizedBox(
width: double.infinity,
height: UniversalPlatform.isDesktopOrWeb ? 200 : 400,
),
),
dropTargetStyle: AppFlowyDropTargetStyle(
color: Theme.of(context).colorScheme.primary.withOpacity(0.8),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,10 @@ Future<void> dragToMoveNode(

Log.info('Moving node($node, ${node.path}) to path($newPath)');

final newPathNode = editorState.getNodeAtPath(newPath);
if (newPathNode == null) {
// if the new path is not a valid path, it means the node is not in the editor.
// we should perform insertion before deletion.
final transaction = editorState.transaction;
transaction.insertNode(newPath, node.copyWith());
transaction.deleteNode(node);
await editorState.apply(transaction);
} else {
// Perform the node move operation
final transaction = editorState.transaction;
transaction.deleteNode(node);
transaction.insertNode(newPath, node.copyWith());
await editorState.apply(transaction);
}
final transaction = editorState.transaction;
transaction.insertNode(newPath, node.copyWith());
transaction.deleteNode(node);
await editorState.apply(transaction);
}

(VerticalPosition, HorizontalPosition, Rect)? getDragAreaPosition(
Expand Down
Loading

0 comments on commit c24b684

Please sign in to comment.