feat: implement bold text in toolbar service

This commit is contained in:
Lucas.Xu 2022-08-02 10:25:18 +08:00
parent 5ecfc4ff2e
commit ba78f0073d
4 changed files with 68 additions and 61 deletions

View File

@ -178,7 +178,7 @@ class TextNode extends Node {
}) : _delta = delta;
TextNode.empty()
: _delta = Delta([TextInsert('')]),
: _delta = Delta([TextInsert(' ')]),
super(
type: 'text',
children: LinkedList(),

View File

@ -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<Map<String, ToolbarEventHandler>>;
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<String, ToolbarEventHandler>;
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<String> 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<ToolbarWidget> {
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<ToolbarWidget> {
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<ToolbarWidget> {
),
),
onTap: () {
debugPrint('tap on $index');
_onTap(items[index]);
},
);
}),
@ -210,6 +200,14 @@ class _ToolbarWidgetState extends State<ToolbarWidget> {
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;

View File

@ -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,
);
}
}
}

View File

@ -35,7 +35,7 @@ class _FlowyToolbarState extends State<FlowyToolbar> with ToolbarService {
editorState: widget.editorState,
layerLink: layerLink,
offset: offset.translate(0, -37.0),
handlers: const [],
handlers: const {},
),
);
Overlay.of(context)?.insert(_toolbarOverlay!);