diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json index 95ef4aee75..4034ff517c 100644 --- a/frontend/app_flowy/assets/translations/en.json +++ b/frontend/app_flowy/assets/translations/en.json @@ -314,12 +314,18 @@ "date": { "timeHintTextInTwelveHour": "01:00 PM", "timeHintTextInTwentyFourHour": "13:00" + }, + "slashMenu": { + "board": { + "selectABoardToLinkTo": "Select a board to link to" + } } }, "board": { "column": { "create_new_card": "New" - } + }, + "menuName": "Board" }, "calendar": { "menuName": "Calendar", diff --git a/frontend/app_flowy/lib/plugins/board/board.dart b/frontend/app_flowy/lib/plugins/board/board.dart index 457e8446ef..8313f2f38e 100644 --- a/frontend/app_flowy/lib/plugins/board/board.dart +++ b/frontend/app_flowy/lib/plugins/board/board.dart @@ -1,8 +1,10 @@ +import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/plugins/util.dart'; +import 'package:app_flowy/startup/plugin/plugin.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; -import 'package:app_flowy/startup/plugin/plugin.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'presentation/board_page.dart'; @@ -18,7 +20,7 @@ class BoardPluginBuilder implements PluginBuilder { } @override - String get menuName => "Board"; + String get menuName => LocaleKeys.board_menuName.tr(); @override String get menuIcon => "editor/board"; diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart index 4c8777a204..bb61850263 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart @@ -4,34 +4,40 @@ import 'dart:collection'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/plugins/board/application/card/card_data_controller.dart'; -import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; +import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/row/row_data_controller.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_detail.dart'; -import 'package:appflowy_board/appflowy_board.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; -import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-grid/row_entities.pb.dart'; +import 'package:appflowy_board/appflowy_board.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; + import '../application/board_bloc.dart'; import 'card/card.dart'; import 'card/card_cell_builder.dart'; import 'toolbar/board_toolbar.dart'; class BoardPage extends StatelessWidget { - final ViewPB view; BoardPage({ required this.view, Key? key, + this.onEditStateChanged, }) : super(key: ValueKey(view.id)); + final ViewPB view; + + /// Called when edit state changed + final VoidCallback? onEditStateChanged; + @override Widget build(BuildContext context) { return BlocProvider( @@ -45,7 +51,9 @@ class BoardPage extends StatelessWidget { const Center(child: CircularProgressIndicator.adaptive()), finish: (result) { return result.successOrFail.fold( - (_) => const BoardContent(), + (_) => BoardContent( + onEditStateChanged: onEditStateChanged, + ), (err) => FlowyErrorPage(err.toString()), ); }, @@ -57,7 +65,12 @@ class BoardPage extends StatelessWidget { } class BoardContent extends StatefulWidget { - const BoardContent({Key? key}) : super(key: key); + const BoardContent({ + Key? key, + this.onEditStateChanged, + }) : super(key: key); + + final VoidCallback? onEditStateChanged; @override State createState() => _BoardContentState(); @@ -79,7 +92,10 @@ class _BoardContentState extends State { @override Widget build(BuildContext context) { return BlocListener( - listener: (context, state) => _handleEditStateChanged(state, context), + listener: (context, state) { + _handleEditStateChanged(state, context); + widget.onEditStateChanged?.call(); + }, child: BlocBuilder( buildWhen: (previous, current) => previous.groupIds != current.groupIds, builder: (context, state) { diff --git a/frontend/app_flowy/lib/plugins/document/document_page.dart b/frontend/app_flowy/lib/plugins/document/document_page.dart index e2a072fa6c..76b6e9c1d3 100644 --- a/frontend/app_flowy/lib/plugins/document/document_page.dart +++ b/frontend/app_flowy/lib/plugins/document/document_page.dart @@ -1,3 +1,5 @@ +import 'package:app_flowy/plugins/document/presentation/plugins/board/board_menu_item.dart'; +import 'package:app_flowy/plugins/document/presentation/plugins/board/board_node_widget.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart'; @@ -97,7 +99,6 @@ class _DocumentPageState extends State { Widget _renderAppFlowyEditor(EditorState editorState) { final theme = Theme.of(context); - final editorMaxWidth = MediaQuery.of(context).size.width * 0.6; final editor = AppFlowyEditor( editorState: editorState, autoFocus: editorState.document.isEmpty, @@ -108,6 +109,8 @@ class _DocumentPageState extends State { kMathEquationType: MathEquationNodeWidgetBuidler(), // Code Block kCodeBlockType: CodeBlockNodeWidgetBuilder(), + // Board + kBoardType: BoardNodeWidgetBuilder(), // Card kCalloutType: CalloutNodeWidgetBuilder(), }, @@ -128,6 +131,8 @@ class _DocumentPageState extends State { codeBlockMenuItem, // Emoji emojiMenuItem, + // Board + boardMenuItem, ], themeData: theme.copyWith(extensions: [ ...theme.extensions.values, @@ -138,8 +143,8 @@ class _DocumentPageState extends State { return Expanded( child: Center( child: Container( - constraints: BoxConstraints( - maxWidth: editorMaxWidth, + constraints: const BoxConstraints( + maxWidth: double.infinity, ), child: editor, ), diff --git a/frontend/app_flowy/lib/plugins/document/editor_styles.dart b/frontend/app_flowy/lib/plugins/document/editor_styles.dart index 1e3422aaf1..0220621f34 100644 --- a/frontend/app_flowy/lib/plugins/document/editor_styles.dart +++ b/frontend/app_flowy/lib/plugins/document/editor_styles.dart @@ -9,7 +9,7 @@ EditorStyle customEditorTheme(BuildContext context) { ? EditorStyle.dark : EditorStyle.light; editorStyle = editorStyle.copyWith( - padding: const EdgeInsets.all(0), + padding: const EdgeInsets.symmetric(horizontal: 40), textStyle: editorStyle.textStyle?.copyWith( fontFamily: 'poppins', fontSize: documentStyle.fontSize, diff --git a/frontend/app_flowy/lib/plugins/document/presentation/plugins/board/board_menu_item.dart b/frontend/app_flowy/lib/plugins/document/presentation/plugins/board/board_menu_item.dart new file mode 100644 index 0000000000..f6eda00778 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/document/presentation/plugins/board/board_menu_item.dart @@ -0,0 +1,195 @@ +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:app_flowy/plugins/document/presentation/plugins/board/board_node_widget.dart'; +import 'package:app_flowy/workspace/application/app/app_service.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/app.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:dartz/dartz.dart' as dartz; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; + +SelectionMenuItem boardMenuItem = SelectionMenuItem( + name: () => LocaleKeys.board_menuName.tr(), + icon: (editorState, onSelected) { + return svgWidget( + 'editor/board', + size: const Size.square(18.0), + color: onSelected + ? editorState.editorStyle.selectionMenuItemSelectedIconColor + : editorState.editorStyle.selectionMenuItemIconColor, + ); + }, + keywords: ['board'], + handler: _showLinkToPageMenu, +); + +EditorState? _editorState; +OverlayEntry? _linkToPageMenu; +void _dismissLinkToPageMenu() { + _linkToPageMenu?.remove(); + _linkToPageMenu = null; + + _editorState?.service.selectionService.currentSelection + .removeListener(_dismissLinkToPageMenu); + _editorState = null; +} + +void _showLinkToPageMenu( + EditorState editorState, + SelectionMenuService menuService, + BuildContext context, +) { + final aligment = menuService.alignment; + final offset = menuService.offset; + menuService.dismiss(); + + _editorState = editorState; + + _linkToPageMenu?.remove(); + _linkToPageMenu = OverlayEntry(builder: (context) { + return Positioned( + top: aligment == Alignment.bottomLeft ? offset.dy : null, + bottom: aligment == Alignment.topLeft ? offset.dy : null, + left: offset.dx, + child: Material( + color: Colors.transparent, + child: LinkToPageMenu( + editorState: editorState, + ), + ), + ); + }); + + Overlay.of(context)?.insert(_linkToPageMenu!); + + editorState.service.selectionService.currentSelection + .addListener(_dismissLinkToPageMenu); +} + +class LinkToPageMenu extends StatefulWidget { + final EditorState editorState; + + const LinkToPageMenu({ + super.key, + required this.editorState, + }); + + @override + State createState() => _LinkToPageMenuState(); +} + +class _LinkToPageMenuState extends State { + EditorStyle get style => widget.editorState.editorStyle; + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.transparent, + width: 300, + child: Container( + padding: const EdgeInsets.fromLTRB(10, 6, 10, 6), + decoration: BoxDecoration( + color: style.selectionMenuBackgroundColor, + boxShadow: [ + BoxShadow( + blurRadius: 5, + spreadRadius: 1, + color: Colors.black.withOpacity(0.1), + ), + ], + borderRadius: BorderRadius.circular(6.0), + ), + child: _buildBoardListWidget(context), + ), + ); + } + + Future>>> fetchBoards() async { + return AppService().fetchViews(ViewLayoutTypePB.Board); + } + + Widget _buildBoardListWidget(BuildContext context) { + return FutureBuilder>>>( + builder: (context, snapshot) { + if (snapshot.hasData && + snapshot.connectionState == ConnectionState.done) { + final apps = snapshot.data; + final children = [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: FlowyText.regular( + LocaleKeys.document_slashMenu_board_selectABoardToLinkTo.tr(), + fontSize: 10, + color: Colors.grey, + ), + ), + ]; + if (apps != null && apps.isNotEmpty) { + for (final app in apps) { + if (app.value2.isNotEmpty) { + children.add( + Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: FlowyText.regular( + app.value1.name, + ), + ), + ); + for (final board in app.value2) { + children.add( + FlowyButton( + leftIcon: svgWidget( + 'editor/board', + color: Theme.of(context).colorScheme.onSurface, + ), + text: FlowyText.regular(board.name), + onTap: () => widget.editorState.insertBoard( + app.value1, + board, + ), + ), + ); + } + } + } + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: children, + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + future: fetchBoards(), + ); + } +} + +extension on EditorState { + void insertBoard(AppPB appPB, ViewPB viewPB) { + final selection = service.selectionService.currentSelection.value; + final textNodes = + service.selectionService.currentSelectedNodes.whereType(); + if (selection == null || textNodes.isEmpty) { + return; + } + final transaction = this.transaction; + transaction.insertNode( + selection.end.path, + Node( + type: kBoardType, + attributes: { + kAppID: appPB.id, + kBoardID: viewPB.id, + }, + ), + ); + apply(transaction); + } +} diff --git a/frontend/app_flowy/lib/plugins/document/presentation/plugins/board/board_node_widget.dart b/frontend/app_flowy/lib/plugins/document/presentation/plugins/board/board_node_widget.dart new file mode 100644 index 0000000000..9a8b1884b6 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/document/presentation/plugins/board/board_node_widget.dart @@ -0,0 +1,175 @@ +import 'package:app_flowy/plugins/board/presentation/board_page.dart'; +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/app/app_service.dart'; +import 'package:app_flowy/workspace/application/view/view_ext.dart'; +import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; +import 'package:app_flowy/workspace/presentation/home/menu/menu.dart'; +import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:dartz/dartz.dart' as dartz; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flutter/material.dart'; + +const String kBoardType = 'board'; +const String kAppID = 'app_id'; +const String kBoardID = 'board_id'; + +class BoardNodeWidgetBuilder extends NodeWidgetBuilder { + @override + Widget build(NodeWidgetContext context) { + return _BoardWidget( + key: context.node.key, + node: context.node, + editorState: context.editorState, + ); + } + + @override + NodeValidator get nodeValidator => (node) { + return node.attributes[kBoardID] is String && + node.attributes[kAppID] is String; + }; +} + +class _BoardWidget extends StatefulWidget { + const _BoardWidget({ + Key? key, + required this.node, + required this.editorState, + }) : super(key: key); + + final Node node; + final EditorState editorState; + + @override + State<_BoardWidget> createState() => _BoardWidgetState(); +} + +class _BoardWidgetState extends State<_BoardWidget> with SelectableMixin { + RenderBox get _renderBox => context.findRenderObject() as RenderBox; + + String get boardID { + return widget.node.attributes[kBoardID]; + } + + String get appID { + return widget.node.attributes[kAppID]; + } + + late Future> board; + + @override + void initState() { + super.initState(); + + board = _fetchBoard(); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder>( + builder: (context, snapshot) { + if (snapshot.hasData) { + final board = snapshot.data?.getLeftOrNull(); + if (board != null) { + return _buildBoard(context, board); + } + } + return const Center( + child: CircularProgressIndicator(), + ); + }, + future: board, + ); + } + + Future> _fetchBoard() async { + return AppService().getView(appID, boardID); + } + + Widget _buildBoard(BuildContext context, ViewPB viewPB) { + return MouseRegion( + onHover: (event) { + if (widget.node.isSelected(widget.editorState)) { + widget.editorState.service.scrollService?.disable(); + } + }, + onExit: (event) { + widget.editorState.service.scrollService?.enable(); + }, + child: SizedBox( + height: 400, + child: Stack( + children: [ + Positioned( + top: 0, + left: 20, + child: FlowyTextButton( + viewPB.name, + onPressed: () { + getIt().latestOpenView = viewPB; + getIt().setPlugin(viewPB.plugin()); + }, + ), + ), + BoardPage( + key: ValueKey(viewPB.id), + view: viewPB, + onEditStateChanged: () { + /// Clear selection when the edit state changes, otherwise the editor will prevent the keyboard event when the board is in edit mode. + widget.editorState.service.selectionService.clearSelection(); + }, + ), + ], + ), + ), + ); + } + + @override + bool get shouldCursorBlink => false; + + @override + CursorStyle get cursorStyle => CursorStyle.borderLine; + + @override + Position start() { + return Position(path: widget.node.path, offset: 0); + } + + @override + Position end() { + return Position(path: widget.node.path, offset: 0); + } + + @override + Position getPositionInOffset(Offset start) { + return end(); + } + + @override + List getRectsInSelection(Selection selection) { + return [Offset.zero & _renderBox.size]; + } + + @override + Rect? getCursorRectInPosition(Position position) { + final size = _renderBox.size; + return Rect.fromLTWH(-size.width / 2.0, 0, size.width, size.height); + } + + @override + Selection getSelectionInRange(Offset start, Offset end) { + return Selection.single( + path: widget.node.path, + startOffset: 0, + endOffset: 0, + ); + } + + @override + Offset localToGlobal(Offset offset) { + return _renderBox.localToGlobal(offset); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/app/app_service.dart b/frontend/app_flowy/lib/workspace/application/app/app_service.dart index fb58ae82ef..7b477dbac3 100644 --- a/frontend/app_flowy/lib/workspace/application/app/app_service.dart +++ b/frontend/app_flowy/lib/workspace/application/app/app_service.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart'; import 'package:dartz/dartz.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; @@ -77,4 +78,52 @@ class AppService { return FolderEventMoveFolderItem(payload).send(); } + + Future>>> fetchViews( + ViewLayoutTypePB layoutType) async { + final result = >>[]; + return FolderEventReadCurrentWorkspace().send().then((value) async { + final workspaces = value.getLeftOrNull(); + if (workspaces != null) { + final apps = workspaces.workspace.apps.items; + for (var app in apps) { + final views = await getViews(appId: app.id).then( + (value) => value + .getLeftOrNull>() + ?.where((e) => e.layout == layoutType) + .toList(), + ); + if (views != null && views.isNotEmpty) { + result.add(Tuple2(app, views)); + } + } + } + return result; + }); + } + + Future> getView( + String appID, + String viewID, + ) async { + final payload = AppIdPB.create()..value = appID; + return FolderEventReadApp(payload).send().then((result) { + return result.fold( + (app) => left( + app.belongings.items.firstWhere((e) => e.id == viewID), + ), + (error) => right(error), + ); + }); + } +} + +extension AppFlowy on Either { + T? getLeftOrNull() { + if (isLeft()) { + final result = fold((l) => l, (r) => null); + return result; + } + return null; + } } diff --git a/frontend/app_flowy/packages/appflowy_editor/example/assets/example.json b/frontend/app_flowy/packages/appflowy_editor/example/assets/example.json index 74c82e3227..ea1a6161da 100644 --- a/frontend/app_flowy/packages/appflowy_editor/example/assets/example.json +++ b/frontend/app_flowy/packages/appflowy_editor/example/assets/example.json @@ -23,6 +23,7 @@ ] }, { "type": "text", "delta": [] }, + { "type": "board" }, { "type": "text", "delta": [ diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart b/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart index eab2d43c60..93f58d1b55 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/appflowy_editor.dart @@ -44,3 +44,4 @@ export 'src/plugins/markdown/document_markdown.dart'; export 'src/plugins/quill_delta/delta_document_encoder.dart'; export 'src/commands/text/text_commands.dart'; export 'src/render/toolbar/toolbar_item.dart'; +export 'src/extensions/node_extensions.dart'; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/core/document/node.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/core/document/node.dart index 975ef00df3..1bb26da7fb 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/core/document/node.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/core/document/node.dart @@ -71,7 +71,7 @@ class Node extends ChangeNotifier with LinkedListEntry { Attributes _attributes; // Renderable - GlobalKey? key; + final key = GlobalKey(); final layerLink = LayerLink(); Attributes get attributes => {..._attributes}; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/extensions/node_extensions.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/extensions/node_extensions.dart index 82d28bd469..877a97fb57 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/extensions/node_extensions.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/extensions/node_extensions.dart @@ -1,17 +1,18 @@ import 'package:appflowy_editor/src/core/document/node.dart'; import 'package:appflowy_editor/src/core/document/path.dart'; import 'package:appflowy_editor/src/core/location/selection.dart'; +import 'package:appflowy_editor/src/editor_state.dart'; import 'package:appflowy_editor/src/extensions/object_extensions.dart'; import 'package:appflowy_editor/src/render/selection/selectable.dart'; import 'package:flutter/material.dart'; extension NodeExtensions on Node { RenderBox? get renderBox => - key?.currentContext?.findRenderObject()?.unwrapOrNull(); + key.currentContext?.findRenderObject()?.unwrapOrNull(); - BuildContext? get context => key?.currentContext; + BuildContext? get context => key.currentContext; SelectableMixin? get selectable => - key?.currentState?.unwrapOrNull(); + key.currentState?.unwrapOrNull(); bool inSelection(Selection selection) { if (selection.start.path <= selection.end.path) { @@ -28,4 +29,11 @@ extension NodeExtensions on Node { } return Rect.zero; } + + bool isSelected(EditorState editorState) { + final currentSelectedNodes = + editorState.service.selectionService.currentSelectedNodes; + return currentSelectedNodes.length == 1 && + currentSelectedNodes.first == this; + } } diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart index c296c773bb..d612f839a3 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart @@ -1,5 +1,4 @@ import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:appflowy_editor/src/extensions/node_extensions.dart'; import 'package:flutter/material.dart'; ShortcutEventHandler cursorLeftSelect = (editorState, event) { diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/render_plugin_service.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/render_plugin_service.dart index 38f4b9f8b3..0bc3f6049f 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/render_plugin_service.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/render_plugin_service.dart @@ -74,8 +74,6 @@ class AppFlowyRenderPlugin extends AppFlowyRenderPluginService { node.subtype == null ? node.type : '${node.type}/${node.subtype!}'; final builder = _builders[name]; if (builder != null && builder.nodeValidator(node)) { - final key = GlobalKey(debugLabel: name); - node.key = key; return _autoUpdateNodeWidget(builder, context); } else { // Returns a SizeBox with 0 height if no builder found. diff --git a/frontend/app_flowy/packages/appflowy_editor/test/extensions/node_extension_test.dart b/frontend/app_flowy/packages/appflowy_editor/test/extensions/node_extension_test.dart index 0e31aa5a96..70b18f22a7 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/extensions/node_extension_test.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/extensions/node_extension_test.dart @@ -1,28 +1,18 @@ import 'dart:collection'; -import 'dart:ui'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:appflowy_editor/src/extensions/node_extensions.dart'; class MockNode extends Mock implements Node {} void main() { - final mockNode = MockNode(); - group('NodeExtensions::', () { final selection = Selection( start: Position(path: [0]), end: Position(path: [1]), ); - test('rect - renderBox is null', () { - when(mockNode.renderBox).thenReturn(null); - final result = mockNode.rect; - expect(result, Rect.zero); - }); - test('inSelection', () { // I use an empty implementation instead of mock, because the mocked // version throws error trying to access the path. diff --git a/frontend/app_flowy/packages/appflowy_editor/test/render/rich_text/checkbox_text_test.dart b/frontend/app_flowy/packages/appflowy_editor/test/render/rich_text/checkbox_text_test.dart index b13fa456c9..721b429df8 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/render/rich_text/checkbox_text_test.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/render/rich_text/checkbox_text_test.dart @@ -43,7 +43,7 @@ void main() async { final selection = Selection.single(path: [0], startOffset: 0, endOffset: text.length); var node = editor.nodeAtPath([0]) as TextNode; - var state = node.key?.currentState as DefaultSelectable; + var state = node.key.currentState as DefaultSelectable; var checkboxWidget = find.byKey(state.iconKey!); await tester.tap(checkboxWidget); await tester.pumpAndSettle(); @@ -56,7 +56,7 @@ void main() async { expect(node.allSatisfyStrikethroughInSelection(selection), true); node = editor.nodeAtPath([0]) as TextNode; - state = node.key?.currentState as DefaultSelectable; + state = node.key.currentState as DefaultSelectable; await tester.ensureVisible(find.byKey(state.iconKey!)); await tester.tap(find.byKey(state.iconKey!)); await tester.pump(); diff --git a/frontend/app_flowy/packages/appflowy_editor/test/service/selection_service_test.dart b/frontend/app_flowy/packages/appflowy_editor/test/service/selection_service_test.dart index 5df8e36319..c4f8825d38 100644 --- a/frontend/app_flowy/packages/appflowy_editor/test/service/selection_service_test.dart +++ b/frontend/app_flowy/packages/appflowy_editor/test/service/selection_service_test.dart @@ -21,7 +21,7 @@ void main() async { await editor.startTesting(); final secondTextNode = editor.nodeAtPath([1]); - final finder = find.byKey(secondTextNode!.key!); + final finder = find.byKey(secondTextNode!.key); final rect = tester.getRect(finder); // tap at the beginning @@ -48,7 +48,7 @@ void main() async { await editor.startTesting(); final secondTextNode = editor.nodeAtPath([1]); - final finder = find.byKey(secondTextNode!.key!); + final finder = find.byKey(secondTextNode!.key); final rect = tester.getRect(finder); // double tap @@ -70,7 +70,7 @@ void main() async { await editor.startTesting(); final secondTextNode = editor.nodeAtPath([1]); - final finder = find.byKey(secondTextNode!.key!); + final finder = find.byKey(secondTextNode!.key); final rect = tester.getRect(finder); // triple tap @@ -93,7 +93,7 @@ void main() async { await editor.startTesting(); final secondTextNode = editor.nodeAtPath([1]) as TextNode; - final finder = find.byKey(secondTextNode.key!); + final finder = find.byKey(secondTextNode.key); final rect = tester.getRect(finder); // secondary tap diff --git a/frontend/app_flowy/packages/appflowy_editor_plugins/lib/src/math_ equation/math_equation_node_widget.dart b/frontend/app_flowy/packages/appflowy_editor_plugins/lib/src/math_ equation/math_equation_node_widget.dart index 6892d38ba9..bcb8bcedcd 100644 --- a/frontend/app_flowy/packages/appflowy_editor_plugins/lib/src/math_ equation/math_equation_node_widget.dart +++ b/frontend/app_flowy/packages/appflowy_editor_plugins/lib/src/math_ equation/math_equation_node_widget.dart @@ -47,7 +47,7 @@ SelectionMenuItem mathEquationMenuItem = SelectionMenuItem( final mathEquationState = editorState.document .nodeAtPath(mathEquationNodePath) ?.key - ?.currentState; + .currentState; if (mathEquationState != null && mathEquationState is _MathEquationNodeWidgetState) { mathEquationState.showEditingDialog(); diff --git a/frontend/app_flowy/packages/appflowy_editor_plugins/pubspec.yaml b/frontend/app_flowy/packages/appflowy_editor_plugins/pubspec.yaml index ddb547ca85..a2ccec7754 100644 --- a/frontend/app_flowy/packages/appflowy_editor_plugins/pubspec.yaml +++ b/frontend/app_flowy/packages/appflowy_editor_plugins/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: path: ../appflowy_editor flowy_infra: path: ../flowy_infra - flowy_infra_ui: + flowy_infra_ui: path: ../flowy_infra_ui appflowy_popover: path: ../appflowy_popover