From ba78f0073dd4e6e6d8991a52b4425bc67e525d32 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 2 Aug 2022 10:25:18 +0800 Subject: [PATCH] feat: implement bold text in toolbar service --- .../flowy_editor/lib/document/node.dart | 2 +- .../lib/render/selection/toolbar_widget.dart | 70 +++++++++---------- .../format_rich_text_style.dart | 55 +++++++++------ .../lib/service/toolbar_service.dart | 2 +- 4 files changed, 68 insertions(+), 61 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart b/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart index bdd6da444d..69852856b0 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/document/node.dart @@ -178,7 +178,7 @@ class TextNode extends Node { }) : _delta = delta; TextNode.empty() - : _delta = Delta([TextInsert('')]), + : _delta = Delta([TextInsert(' ')]), super( type: 'text', children: LinkedList(), diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart index 7266929962..486bd97671 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart @@ -1,43 +1,35 @@ import 'package:flowy_editor/editor_state.dart'; import 'package:flowy_editor/infra/flowy_svg.dart'; +import 'package:flowy_editor/render/rich_text/rich_text_style.dart'; +import 'package:flowy_editor/service/default_text_operations/format_rich_text_style.dart'; import 'package:flutter/material.dart'; -typedef ToolbarEventHandler = void Function( - EditorState editorState, String eventName); +typedef ToolbarEventHandler = void Function(EditorState editorState); -typedef ToolbarEventHandlers = List>; -ToolbarEventHandlers defaultToolbarEventHandlers = [ - { - 'bold': ((editorState, eventName) {}), - 'italic': ((editorState, eventName) {}), - 'strikethrough': ((editorState, eventName) {}), - 'underline': ((editorState, eventName) {}), - 'quote': ((editorState, eventName) {}), - 'number_list': ((editorState, eventName) {}), - 'bulleted_list': ((editorState, eventName) {}), - } -]; +typedef ToolbarEventHandlers = Map; -ToolbarEventHandlers defaultListToolbarEventHandlers = [ - { - 'h1': ((editorState, eventName) {}), - }, - { - 'h2': ((editorState, eventName) {}), - }, - { - 'h3': ((editorState, eventName) {}), - }, - { - 'bulleted_list': ((editorState, eventName) {}), - }, - { - 'quote': ((editorState, eventName) {}), - } +ToolbarEventHandlers defaultToolbarEventHandlers = { + 'bold': ((editorState) { + formatRichTextStyle(editorState, {StyleKey.bold: true}); + }), + 'italic': ((editorState) {}), + 'strikethrough': ((editorState) {}), + 'underline': ((editorState) {}), + 'quote': ((editorState) {}), + 'number_list': ((editorState) {}), + 'bulleted_list': ((editorState) {}), +}; + +List defaultListToolbarEventNames = [ + 'H1', + 'H2', + 'H3', + 'B-List', + 'N-List', ]; class ToolbarWidget extends StatefulWidget { - ToolbarWidget({ + const ToolbarWidget({ Key? key, required this.editorState, required this.layerLink, @@ -137,7 +129,7 @@ class _ToolbarWidgetState extends State { preferBelow: false, message: name, child: GestureDetector( - onTap: onTap ?? () => debugPrint('toolbar tap $name'), + onTap: onTap ?? () => _onTap(name), child: SizedBox.fromSize( size: width != null ? Size(width, toolbarHeight) @@ -154,9 +146,7 @@ class _ToolbarWidgetState extends State { void _onTapListToolbar(BuildContext context) { // TODO: implement more detailed UI. - final items = defaultListToolbarEventHandlers - .map((handler) => handler.keys.first) - .toList(growable: false); + final items = defaultListToolbarEventNames; final renderBox = _listToolbarKey.currentContext?.findRenderObject() as RenderBox; final offset = renderBox @@ -198,7 +188,7 @@ class _ToolbarWidgetState extends State { ), ), onTap: () { - debugPrint('tap on $index'); + _onTap(items[index]); }, ); }), @@ -210,6 +200,14 @@ class _ToolbarWidgetState extends State { Overlay.of(context)?.insert(_listToolbarOverlay!); } + void _onTap(String eventName) { + if (defaultToolbarEventHandlers.containsKey(eventName)) { + defaultToolbarEventHandlers[eventName]!(widget.editorState); + return; + } + assert(false, 'Could not find the event handler for $eventName'); + } + void _onSelectionChange() { _listToolbarOverlay?.remove(); _listToolbarOverlay = null; diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart index 5622785d45..162818ae1d 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart @@ -17,29 +17,38 @@ bool formatRichTextStyle( // 1. All nodes are text nodes. // 2. The first node is not TextNode. // 3. The last node is not TextNode. - for (var i = 0; i < textNodes.length; i++) { - final textNode = textNodes[i]; - if (i == 0 && textNode == nodes.first) { - builder.formatText( - textNode, - selection.start.offset, - textNode.toRawString().length - selection.start.offset, - attributes, - ); - } else if (i == textNodes.length - 1 && textNode == nodes.last) { - builder.formatText( - textNode, - 0, - selection.end.offset, - attributes, - ); - } else { - builder.formatText( - textNode, - 0, - textNode.toRawString().length, - attributes, - ); + if (nodes.length == textNodes.length && textNodes.length == 1) { + builder.formatText( + textNodes.first, + selection.start.offset, + selection.end.offset - selection.start.offset, + attributes, + ); + } else { + for (var i = 0; i < textNodes.length; i++) { + final textNode = textNodes[i]; + if (i == 0 && textNode == nodes.first) { + builder.formatText( + textNode, + selection.start.offset, + textNode.toRawString().length - selection.start.offset, + attributes, + ); + } else if (i == textNodes.length - 1 && textNode == nodes.last) { + builder.formatText( + textNode, + 0, + selection.end.offset, + attributes, + ); + } else { + builder.formatText( + textNode, + 0, + textNode.toRawString().length, + attributes, + ); + } } } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/toolbar_service.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/toolbar_service.dart index b8b8f95e46..feb293aad4 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/toolbar_service.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/toolbar_service.dart @@ -35,7 +35,7 @@ class _FlowyToolbarState extends State with ToolbarService { editorState: widget.editorState, layerLink: layerLink, offset: offset.translate(0, -37.0), - handlers: const [], + handlers: const {}, ), ); Overlay.of(context)?.insert(_toolbarOverlay!);