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
..register(
'text',
textNodeWidgetBuilder,
TextNodeBuilder.create,
)
..register(
'image',
imageNodeWidgetBuilder,
ImageNodeBuilder.create,
);
}

View File

@ -1,55 +1,25 @@
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/material.dart';
NodeWidgetBuilder<Node> imageNodeWidgetBuilder =
(node, renderPlugins) => ImageNodeWidget(
node: node,
renderPlugins: renderPlugins,
);
class ImageNodeBuilder extends NodeWidgetBuilder {
ImageNodeBuilder.create({required super.node, required super.renderPlugins})
: super.create();
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;
@override
Widget build(BuildContext context) {
final childWidget = renderChildren();
Widget build() {
final childrenWidget = buildChildren();
final image = Image.network(src);
if (childWidget != null) {
if (childrenWidget != null) {
return Column(
children: [image, childWidget],
children: [
image,
childrenWidget,
],
);
} else {
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:flowy_editor/flowy_editor.dart';
NodeWidgetBuilder<Node> textNodeWidgetBuilder =
(node, renderPlugins) => TextNodeWidget(
node: node,
renderPlugins: renderPlugins,
);
class TextNodeBuilder extends NodeWidgetBuilder {
TextNodeBuilder.create({required super.node, required super.renderPlugins})
: super.create();
class TextNodeWidget extends BaseNodeWidget<Node> {
const TextNodeWidget({
super.key,
required super.node,
required super.renderPlugins,
});
String get content => node.attributes['content'] as String;
@override
State<TextNodeWidget> createState() => _TextNodeWidgetState();
}
class _TextNodeWidgetState extends State<TextNodeWidget> {
Node get node => widget.node;
@override
Widget build(BuildContext context) {
final childWidget = renderChildren();
final richText = RichText(
text: TextSpan(
Widget build() {
final childrenWidget = buildChildren();
final richText = SelectableText.rich(
TextSpan(
text: node.attributes['content'] as String,
style: node.attributes.toTextStyle(),
),
);
if (childWidget != null) {
if (childrenWidget != null) {
return Column(
children: [richText, childWidget],
children: [
richText,
childrenWidget,
],
);
} else {
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 {

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/path.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 '../render/base_node_widget.dart';
import 'node_widget_builder.dart';
typedef NodeWidgetBuilder<T extends Node> = BaseNodeWidget Function(
T node,
RenderPlugins plugins,
);
typedef NodeWidgetBuilderF<T extends Node, A extends NodeWidgetBuilder> = A
Function({
required T node,
required RenderPlugins renderPlugins,
});
// unused
typedef NodeBuilder<T extends Node> = T Function(Node node);
// typedef NodeBuilder<T extends Node> = T Function(Node node);
class RenderPlugins {
Map<String, NodeWidgetBuilder> nodeWidgetBuilders = {};
Map<String, NodeWidgetBuilderF> nodeWidgetBuilders = {};
// unused
// Map<String, NodeBuilder> nodeBuilders = {};
void register(String name, NodeWidgetBuilder builder) {
void register(String name, NodeWidgetBuilderF builder) {
nodeWidgetBuilders[name] = builder;
}
@ -23,12 +24,12 @@ class RenderPlugins {
nodeWidgetBuilders.removeWhere((key, _) => key == name);
}
BaseNodeWidget buildWidgetWithNode(Node node) {
Widget buildWidgetWithNode(Node node) {
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));
return nodeWidgetBuilders[name]!;
}