Browse Source

refactor: abstract node widget builder

Lucas.Xu 2 năm trước cách đây
mục cha
commit
cf0da22d63

+ 2 - 2
frontend/app_flowy/packages/flowy_editor/example/lib/main.dart

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

+ 10 - 40
frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart

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

+ 13 - 42
frontend/app_flowy/packages/flowy_editor/example/lib/plugin/text_node_widget.dart

@@ -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 {

+ 1 - 1
frontend/app_flowy/packages/flowy_editor/lib/flowy_editor.dart

@@ -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';

+ 0 - 24
frontend/app_flowy/packages/flowy_editor/lib/render/base_node_widget.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();
-  }
-}

+ 29 - 0
frontend/app_flowy/packages/flowy_editor/lib/render/node_widget_builder.dart

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

+ 13 - 12
frontend/app_flowy/packages/flowy_editor/lib/render/render_plugins.dart

@@ -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]!;
   }