mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: abstract node widget builder
This commit is contained in:
parent
e3c489612e
commit
cf0da22d63
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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';
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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]!;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user