refactor: abstract node widget builder

This commit is contained in:
Lucas.Xu 2022-07-12 21:27:13 +08:00
parent e3c489612e
commit cf0da22d63
7 changed files with 68 additions and 121 deletions

View File

@ -62,11 +62,11 @@ class _MyHomePageState extends State<MyHomePage> {
renderPlugins renderPlugins
..register( ..register(
'text', 'text',
textNodeWidgetBuilder, TextNodeBuilder.create,
) )
..register( ..register(
'image', 'image',
imageNodeWidgetBuilder, ImageNodeBuilder.create,
); );
} }

View File

@ -1,55 +1,25 @@
import 'package:flowy_editor/flowy_editor.dart'; import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
NodeWidgetBuilder<Node> imageNodeWidgetBuilder = class ImageNodeBuilder extends NodeWidgetBuilder {
(node, renderPlugins) => ImageNodeWidget( ImageNodeBuilder.create({required super.node, required super.renderPlugins})
node: node, : super.create();
renderPlugins: renderPlugins,
);
class ImageNodeWidget extends BaseNodeWidget {
const ImageNodeWidget({
super.key,
required super.node,
required super.renderPlugins,
});
@override
State<ImageNodeWidget> createState() => _ImageNodeWidgetState();
}
class _ImageNodeWidgetState extends State<ImageNodeWidget> {
Node get node => widget.node;
String get src => node.attributes['image_src'] as String; String get src => node.attributes['image_src'] as String;
@override @override
Widget build(BuildContext context) { Widget build() {
final childWidget = renderChildren(); final childrenWidget = buildChildren();
final image = Image.network(src); final image = Image.network(src);
if (childWidget != null) { if (childrenWidget != null) {
return Column( return Column(
children: [image, childWidget], children: [
image,
childrenWidget,
],
); );
} else { } else {
return image; return image;
} }
} }
// manage children's render
Widget? renderChildren() {
if (node.children.isEmpty) {
return null;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: node.children
.map(
(e) => widget.renderPlugins.buildWidgetWithNode(
e,
),
)
.toList(),
);
}
} }

View File

@ -1,61 +1,32 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flowy_editor/flowy_editor.dart'; import 'package:flowy_editor/flowy_editor.dart';
NodeWidgetBuilder<Node> textNodeWidgetBuilder = class TextNodeBuilder extends NodeWidgetBuilder {
(node, renderPlugins) => TextNodeWidget( TextNodeBuilder.create({required super.node, required super.renderPlugins})
node: node, : super.create();
renderPlugins: renderPlugins,
);
class TextNodeWidget extends BaseNodeWidget<Node> { String get content => node.attributes['content'] as String;
const TextNodeWidget({
super.key,
required super.node,
required super.renderPlugins,
});
@override @override
State<TextNodeWidget> createState() => _TextNodeWidgetState(); Widget build() {
} final childrenWidget = buildChildren();
final richText = SelectableText.rich(
class _TextNodeWidgetState extends State<TextNodeWidget> { TextSpan(
Node get node => widget.node;
@override
Widget build(BuildContext context) {
final childWidget = renderChildren();
final richText = RichText(
text: TextSpan(
text: node.attributes['content'] as String, text: node.attributes['content'] as String,
style: node.attributes.toTextStyle(), style: node.attributes.toTextStyle(),
), ),
); );
if (childWidget != null) { if (childrenWidget != null) {
return Column( return Column(
children: [richText, childWidget], children: [
richText,
childrenWidget,
],
); );
} else { } else {
return richText; return richText;
} }
} }
// manage children's render
Widget? renderChildren() {
if (node.children.isEmpty) {
return null;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: node.children
.map(
(e) => widget.renderPlugins.buildWidgetWithNode(
e,
),
)
.toList(),
);
}
} }
extension on Attributes { extension on Attributes {

View File

@ -4,4 +4,4 @@ export 'package:flowy_editor/document/state_tree.dart';
export 'package:flowy_editor/document/node.dart'; export 'package:flowy_editor/document/node.dart';
export 'package:flowy_editor/document/path.dart'; export 'package:flowy_editor/document/path.dart';
export 'package:flowy_editor/render/render_plugins.dart'; export 'package:flowy_editor/render/render_plugins.dart';
export 'package:flowy_editor/render/base_node_widget.dart'; export 'package:flowy_editor/render/node_widget_builder.dart';

View File

@ -1,24 +0,0 @@
import 'package:flutter/material.dart';
import '../document/node.dart';
import '../render/render_plugins.dart';
class BaseNodeWidget<T extends Node> extends StatefulWidget {
final T node;
final RenderPlugins renderPlugins;
const BaseNodeWidget({
Key? key,
required this.node,
required this.renderPlugins,
}) : super(key: key);
@override
State<BaseNodeWidget> createState() => _BaseNodeWidgetState();
}
class _BaseNodeWidgetState extends State<BaseNodeWidget> {
@override
Widget build(BuildContext context) {
throw UnimplementedError();
}
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import '../document/node.dart';
import '../render/render_plugins.dart';
class NodeWidgetBuilder<T extends Node> {
final T node;
final RenderPlugins renderPlugins;
NodeWidgetBuilder.create({required this.node, required this.renderPlugins});
Widget call() => build();
Widget build() => throw UnimplementedError();
Widget? buildChildren() {
if (node.children.isEmpty) {
return null;
}
// default layout
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: node.children
.map(
(e) => renderPlugins.buildWidgetWithNode(e),
)
.toList(),
);
}
}

View File

@ -1,21 +1,22 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart';
import '../document/node.dart'; import '../document/node.dart';
import '../render/base_node_widget.dart'; import 'node_widget_builder.dart';
typedef NodeWidgetBuilder<T extends Node> = BaseNodeWidget Function( typedef NodeWidgetBuilderF<T extends Node, A extends NodeWidgetBuilder> = A
T node, Function({
RenderPlugins plugins, required T node,
); required RenderPlugins renderPlugins,
});
// unused // unused
typedef NodeBuilder<T extends Node> = T Function(Node node); // typedef NodeBuilder<T extends Node> = T Function(Node node);
class RenderPlugins { class RenderPlugins {
Map<String, NodeWidgetBuilder> nodeWidgetBuilders = {}; Map<String, NodeWidgetBuilderF> nodeWidgetBuilders = {};
// unused // unused
// Map<String, NodeBuilder> nodeBuilders = {}; // Map<String, NodeBuilder> nodeBuilders = {};
void register(String name, NodeWidgetBuilder builder) { void register(String name, NodeWidgetBuilderF builder) {
nodeWidgetBuilders[name] = builder; nodeWidgetBuilders[name] = builder;
} }
@ -23,12 +24,12 @@ class RenderPlugins {
nodeWidgetBuilders.removeWhere((key, _) => key == name); nodeWidgetBuilders.removeWhere((key, _) => key == name);
} }
BaseNodeWidget buildWidgetWithNode(Node node) { Widget buildWidgetWithNode(Node node) {
final nodeWidgetBuilder = _nodeWidgetBuilder(node.type); final nodeWidgetBuilder = _nodeWidgetBuilder(node.type);
return nodeWidgetBuilder(node, this); return nodeWidgetBuilder(node: node, renderPlugins: this)();
} }
NodeWidgetBuilder _nodeWidgetBuilder(String name) { NodeWidgetBuilderF _nodeWidgetBuilder(String name) {
assert(nodeWidgetBuilders.containsKey(name)); assert(nodeWidgetBuilders.containsKey(name));
return nodeWidgetBuilders[name]!; return nodeWidgetBuilders[name]!;
} }