From 274b3d1d252caf940e64fdc6a7fc348936ce1074 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Sun, 7 Aug 2022 11:24:41 +0800 Subject: [PATCH 1/5] fix: focusNode lost focus --- .../slash_handler.dart | 9 ++++++++- .../lib/service/keyboard_service.dart | 16 ++++++++++------ .../lib/service/selection_service.dart | 2 ++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/slash_handler.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/slash_handler.dart index d985e2beb7..68bcdca7a6 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/slash_handler.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/internal_key_event_handlers/slash_handler.dart @@ -208,7 +208,14 @@ class _PopupListWidgetState extends State { } if (event.logicalKey == LogicalKeyboardKey.enter) { - widget.items[selectedIndex].handler(widget.editorState); + if (0 <= selectedIndex && selectedIndex < widget.items.length) { + widget.items[selectedIndex].handler(widget.editorState); + return KeyEventResult.handled; + } + } + + if (event.logicalKey == LogicalKeyboardKey.escape) { + clearPopupListOverlay(); return KeyEventResult.handled; } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart index 572babeb3a..01cc0214a1 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/keyboard_service.dart @@ -32,23 +32,23 @@ class FlowyKeyboard extends StatefulWidget { class _FlowyKeyboardState extends State with FlowyKeyboardService { - final FocusNode focusNode = FocusNode(debugLabel: 'flowy_keyboard_service'); + final FocusNode _focusNode = FocusNode(debugLabel: 'flowy_keyboard_service'); bool isFocus = true; @override Widget build(BuildContext context) { return Focus( - focusNode: focusNode, - autofocus: true, + focusNode: _focusNode, onKey: _onKey, + onFocusChange: _onFocusChange, child: widget.child, ); } @override void dispose() { - focusNode.dispose(); + _focusNode.dispose(); super.dispose(); } @@ -56,13 +56,17 @@ class _FlowyKeyboardState extends State @override void enable() { isFocus = true; - focusNode.requestFocus(); + _focusNode.requestFocus(); } @override void disable() { isFocus = false; - focusNode.unfocus(); + _focusNode.unfocus(); + } + + void _onFocusChange(bool value) { + debugPrint('[KeyBoard Service] focus change $value'); } KeyEventResult _onKey(FocusNode node, RawKeyEvent event) { diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart index 55a9230272..8baa54c26f 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/selection_service.dart @@ -265,6 +265,8 @@ class _FlowySelectionState extends State } final selection = Selection.collapsed(position); editorState.updateCursorSelection(selection); + + editorState.service.keyboardService?.enable(); } @override From f6fbe5547720c420c2020175dec20ad8861c13fd Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Sun, 7 Aug 2022 21:43:33 +0800 Subject: [PATCH 2/5] feat: flowy_rich_text supports placeholder and customizes placeholder style --- .../render/rich_text/bulleted_list_text.dart | 1 + .../lib/render/rich_text/checkbox_text.dart | 1 + .../lib/render/rich_text/flowy_rich_text.dart | 45 ++++++++++++++++--- .../lib/render/rich_text/heading_text.dart | 19 ++++++++ .../render/rich_text/number_list_text.dart | 1 + .../lib/render/rich_text/quoted_text.dart | 1 + 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart index 0eae3f22f2..fcba91c3c9 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart @@ -64,6 +64,7 @@ class _BulletedListTextNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'List', textNode: widget.textNode, editorState: widget.editorState, ), diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart index ba2c5b8712..d6eeb65c3d 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart @@ -84,6 +84,7 @@ class _CheckboxNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'To-do', textNode: widget.textNode, editorState: widget.editorState, ) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart index 83d809745c..f7b79342b8 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart @@ -35,15 +35,19 @@ class FlowyRichText extends StatefulWidget { this.cursorHeight, this.cursorWidth = 2.0, this.textSpanDecorator, + this.placeholderText = ' ', + this.placeholderTextSpanDecorator, required this.textNode, required this.editorState, }) : super(key: key); - final double? cursorHeight; - final double cursorWidth; final TextNode textNode; final EditorState editorState; + final double? cursorHeight; + final double cursorWidth; final FlowyTextSpanDecorator? textSpanDecorator; + final String placeholderText; + final FlowyTextSpanDecorator? placeholderTextSpanDecorator; @override State createState() => _FlowyRichTextState(); @@ -51,10 +55,14 @@ class FlowyRichText extends StatefulWidget { class _FlowyRichTextState extends State with Selectable { final _textKey = GlobalKey(); + final _placeholderTextKey = GlobalKey(); RenderParagraph get _renderParagraph => _textKey.currentContext?.findRenderObject() as RenderParagraph; + RenderParagraph get _placeholderRenderParagraph => + _placeholderTextKey.currentContext?.findRenderObject() as RenderParagraph; + @override Widget build(BuildContext context) { return _buildRichText(context); @@ -74,6 +82,7 @@ class _FlowyRichTextState extends State with Selectable { _renderParagraph.getOffsetForCaret(textPosition, Rect.zero); final cursorHeight = widget.cursorHeight ?? _renderParagraph.getFullHeightForCaret(textPosition) ?? + _placeholderRenderParagraph.getFullHeightForCaret(textPosition) ?? 18.0; // default height return Rect.fromLTWH( cursorOffset.dx - (widget.cursorWidth / 2), @@ -129,9 +138,35 @@ class _FlowyRichTextState extends State with Selectable { } Widget _buildRichText(BuildContext context) { - return Align( - alignment: Alignment.centerLeft, - child: _buildSingleRichText(context), + return Stack( + children: [ + _buildPlaceholderText(context), + Align( + alignment: Alignment.centerLeft, + child: _buildSingleRichText(context), + ) + ], + ); + } + + Widget _buildPlaceholderText(BuildContext context) { + final textSpan = TextSpan( + children: [ + TextSpan( + text: widget.placeholderText, + style: TextStyle( + color: widget.textNode.toRawString().isNotEmpty + ? Colors.transparent + : Colors.grey, + ), + ), + ], + ); + return RichText( + key: _placeholderTextKey, + text: widget.placeholderTextSpanDecorator != null + ? widget.placeholderTextSpanDecorator!(textSpan) + : textSpan, ); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart index 4990e90dcf..aacdd9f903 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart @@ -65,6 +65,8 @@ class _HeadingTextNodeWidgetState extends State ), child: FlowyRichText( key: _richTextKey, + placeholderText: 'Heading', + placeholderTextSpanDecorator: _placeholderTextSpanDecorator, textSpanDecorator: _textSpanDecorator, textNode: widget.textNode, editorState: widget.editorState, @@ -90,4 +92,21 @@ class _HeadingTextNodeWidgetState extends State .toList(), ); } + + TextSpan _placeholderTextSpanDecorator(TextSpan textSpan) { + return TextSpan( + children: textSpan.children + ?.whereType() + .map( + (span) => TextSpan( + text: span.text, + style: span.style?.copyWith( + fontSize: widget.textNode.attributes.fontSize, + ), + recognizer: span.recognizer, + ), + ) + .toList(), + ); + } } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart index 1c52b93d4b..12d95f8c9a 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart @@ -65,6 +65,7 @@ class _NumberListTextNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'List', textNode: widget.textNode, editorState: widget.editorState, ), diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart index 41520c560f..e2a43058c8 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart @@ -64,6 +64,7 @@ class _QuotedTextNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'Quote', textNode: widget.textNode, editorState: widget.editorState, ), From 59838f584552b53cdf5afb7f1eb155892a83e3ee Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Sun, 7 Aug 2022 21:46:42 +0800 Subject: [PATCH 3/5] feat: customizes checkbox text style --- .../lib/render/rich_text/checkbox_text.dart | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart index d6eeb65c3d..ee64084901 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart @@ -86,6 +86,7 @@ class _CheckboxNodeWidgetState extends State key: _richTextKey, placeholderText: 'To-do', textNode: widget.textNode, + textSpanDecorator: _textSpanDecorator, editorState: widget.editorState, ) ], @@ -121,4 +122,24 @@ class _CheckboxNodeWidgetState extends State ], ); } + + TextSpan _textSpanDecorator(TextSpan textSpan) { + return TextSpan( + children: textSpan.children + ?.whereType() + .map( + (span) => TextSpan( + text: span.text, + style: widget.textNode.attributes.check + ? span.style?.copyWith( + color: Colors.grey, + decoration: TextDecoration.lineThrough, + ) + : span.style, + recognizer: span.recognizer, + ), + ) + .toList(), + ); + } } From 25387cd0b05e88f777020ad436a8168378b4b4a2 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Sun, 7 Aug 2022 22:03:51 +0800 Subject: [PATCH 4/5] feat: customizes quoted text style --- .../packages/flowy_editor/lib/infra/flowy_svg.dart | 14 ++++++++------ .../lib/render/rich_text/flowy_rich_text.dart | 1 + .../lib/render/rich_text/quoted_text.dart | 11 ++++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/infra/flowy_svg.dart b/frontend/app_flowy/packages/flowy_editor/lib/infra/flowy_svg.dart index 12da5b5dc8..d38fe2d16d 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/infra/flowy_svg.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/infra/flowy_svg.dart @@ -18,12 +18,14 @@ class FlowySvg extends StatelessWidget { @override Widget build(BuildContext context) { if (name != null) { - return SvgPicture.asset( - 'assets/images/$name.svg', - color: color, - package: 'flowy_editor', - width: size.width, - height: size.width, + return SizedBox.fromSize( + size: size, + child: SvgPicture.asset( + 'assets/images/$name.svg', + color: color, + package: 'flowy_editor', + fit: BoxFit.fill, + ), ); } else if (number != null) { final numberText = diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart index f7b79342b8..eb03846711 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart @@ -158,6 +158,7 @@ class _FlowyRichTextState extends State with Selectable { color: widget.textNode.toRawString().isNotEmpty ? Colors.transparent : Colors.grey, + fontSize: baseFontSize, ), ), ], diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart index e2a43058c8..a3b6d2ca79 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart @@ -59,7 +59,10 @@ class _QuotedTextNodeWidgetState extends State return Row( children: [ FlowySvg( - size: Size.square(leftPadding), + size: Size( + leftPadding, + _quoteHeight, + ), name: 'quote', ), FlowyRichText( @@ -71,4 +74,10 @@ class _QuotedTextNodeWidgetState extends State ], ); } + + double get _quoteHeight { + final lines = + widget.textNode.toRawString().characters.where((c) => c == '\n').length; + return (lines + 1) * leftPadding; + } } From 9b9de523da6082a0fd5d528e433c6c9ea3612d02 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 8 Aug 2022 10:54:09 +0800 Subject: [PATCH 5/5] fix: flowy_rich_text will not automatically wrap when the text exceeds a line --- .../lib/render/rich_text/bulleted_list_text.dart | 12 +++++++----- .../lib/render/rich_text/checkbox_text.dart | 16 +++++++++------- .../lib/render/rich_text/flowy_rich_text.dart | 5 +---- .../lib/render/rich_text/heading_text.dart | 16 +++++++++------- .../lib/render/rich_text/number_list_text.dart | 12 +++++++----- .../lib/render/rich_text/quoted_text.dart | 12 +++++++----- 6 files changed, 40 insertions(+), 33 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart index fcba91c3c9..75cde60e39 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart @@ -62,11 +62,13 @@ class _BulletedListTextNodeWidgetState extends State size: Size.square(leftPadding), name: 'point', ), - FlowyRichText( - key: _richTextKey, - placeholderText: 'List', - textNode: widget.textNode, - editorState: widget.editorState, + Expanded( + child: FlowyRichText( + key: _richTextKey, + placeholderText: 'List', + textNode: widget.textNode, + editorState: widget.editorState, + ), ), ], ); diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart index ee64084901..065ae8b595 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart @@ -82,13 +82,15 @@ class _CheckboxNodeWidgetState extends State ..commit(); }, ), - FlowyRichText( - key: _richTextKey, - placeholderText: 'To-do', - textNode: widget.textNode, - textSpanDecorator: _textSpanDecorator, - editorState: widget.editorState, - ) + Expanded( + child: FlowyRichText( + key: _richTextKey, + placeholderText: 'To-do', + textNode: widget.textNode, + textSpanDecorator: _textSpanDecorator, + editorState: widget.editorState, + ), + ), ], ); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart index eb03846711..dbf4e5f63c 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart @@ -141,10 +141,7 @@ class _FlowyRichTextState extends State with Selectable { return Stack( children: [ _buildPlaceholderText(context), - Align( - alignment: Alignment.centerLeft, - child: _buildSingleRichText(context), - ) + _buildSingleRichText(context), ], ); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart index aacdd9f903..2511349e4d 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart @@ -63,13 +63,15 @@ class _HeadingTextNodeWidgetState extends State top: topPadding, bottom: bottomPadding, ), - child: FlowyRichText( - key: _richTextKey, - placeholderText: 'Heading', - placeholderTextSpanDecorator: _placeholderTextSpanDecorator, - textSpanDecorator: _textSpanDecorator, - textNode: widget.textNode, - editorState: widget.editorState, + child: Expanded( + child: FlowyRichText( + key: _richTextKey, + placeholderText: 'Heading', + placeholderTextSpanDecorator: _placeholderTextSpanDecorator, + textSpanDecorator: _textSpanDecorator, + textNode: widget.textNode, + editorState: widget.editorState, + ), ), ) ], diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart index 12d95f8c9a..e9fed70c54 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart @@ -63,11 +63,13 @@ class _NumberListTextNodeWidgetState extends State size: Size.square(leftPadding), number: widget.textNode.attributes.number, ), - FlowyRichText( - key: _richTextKey, - placeholderText: 'List', - textNode: widget.textNode, - editorState: widget.editorState, + Expanded( + child: FlowyRichText( + key: _richTextKey, + placeholderText: 'List', + textNode: widget.textNode, + editorState: widget.editorState, + ), ), ], ); diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart index a3b6d2ca79..00bb393652 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart @@ -65,11 +65,13 @@ class _QuotedTextNodeWidgetState extends State ), name: 'quote', ), - FlowyRichText( - key: _richTextKey, - placeholderText: 'Quote', - textNode: widget.textNode, - editorState: widget.editorState, + Expanded( + child: FlowyRichText( + key: _richTextKey, + placeholderText: 'Quote', + textNode: widget.textNode, + editorState: widget.editorState, + ), ), ], );