فهرست منبع

Merge branch 'feat/flowy_editor' into feat/text-delta-to-text-span

Vincent Chan 2 سال پیش
والد
کامیت
e92677d2ce

+ 2 - 4
frontend/app_flowy/packages/flowy_editor/example/assets/document.json

@@ -1,9 +1,7 @@
 {
     "document": {
-      "type": "text",
-      "attributes": {
-        "content": "TITLE"
-      },
+      "type": "editor",
+      "attributes": {},
       "children": [
         {
           "type": "text",

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

@@ -1,5 +1,6 @@
 import 'dart:convert';
 
+import 'package:example/plugin/document_node_widget.dart';
 import 'package:example/plugin/image_node_widget.dart';
 import 'package:example/plugin/text_node_widget.dart';
 import 'package:example/plugin/text_with_check_box_node_widget.dart';
@@ -56,23 +57,16 @@ class MyHomePage extends StatefulWidget {
 
 class _MyHomePageState extends State<MyHomePage> {
   final RenderPlugins renderPlugins = RenderPlugins();
+  late EditorState _editorState;
   @override
   void initState() {
     super.initState();
 
     renderPlugins
-      ..register(
-        'text',
-        TextNodeBuilder.create,
-      )
-      ..register(
-        'image',
-        ImageNodeBuilder.create,
-      )
-      ..register(
-        'text/with-checkbox',
-        TextWithCheckBoxNodeBuilder.create,
-      );
+      ..register('editor', EditorNodeWidgetBuilder.create)
+      ..register('text', TextNodeBuilder.create)
+      ..register('image', ImageNodeBuilder.create)
+      ..register('text/with-checkbox', TextWithCheckBoxNodeBuilder.create);
   }
 
   @override
@@ -83,37 +77,23 @@ class _MyHomePageState extends State<MyHomePage> {
         // the App.build method, and use it to set our appbar title.
         title: Text(widget.title),
       ),
-      body: Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          FutureBuilder<String>(
-            future: rootBundle.loadString('assets/document.json'),
-            builder: (context, snapshot) {
-              if (!snapshot.hasData) {
-                return const Center(
-                  child: CircularProgressIndicator(),
-                );
-              } else {
-                final data =
-                    Map<String, Object>.from(json.decode(snapshot.data!));
-                final document = StateTree.fromJson(data);
-                print(document.root.toString());
-                final editorState = EditorState(
-                  document: document,
-                  renderPlugins: renderPlugins,
-                );
-                return editorState.build(context);
-              }
-            },
-          ),
-          SizedBox(
-            height: 50,
-            width: MediaQuery.of(context).size.width,
-            child: Container(
-              color: Colors.red,
-            ),
-          )
-        ],
+      body: FutureBuilder<String>(
+        future: rootBundle.loadString('assets/document.json'),
+        builder: (context, snapshot) {
+          if (!snapshot.hasData) {
+            return const Center(
+              child: CircularProgressIndicator(),
+            );
+          } else {
+            final data = Map<String, Object>.from(json.decode(snapshot.data!));
+            final document = StateTree.fromJson(data);
+            _editorState = EditorState(
+              document: document,
+              renderPlugins: renderPlugins,
+            );
+            return _editorState.build(context);
+          }
+        },
       ),
     );
   }

+ 50 - 0
frontend/app_flowy/packages/flowy_editor/example/lib/plugin/document_node_widget.dart

@@ -0,0 +1,50 @@
+import 'package:flowy_editor/flowy_editor.dart';
+import 'package:flutter/material.dart';
+
+class EditorNodeWidgetBuilder extends NodeWidgetBuilder {
+  EditorNodeWidgetBuilder.create({
+    required super.editorState,
+    required super.node,
+  }) : super.create();
+
+  @override
+  Widget build(BuildContext buildContext) {
+    return SingleChildScrollView(
+      child: _EditorNodeWidget(
+        node: node,
+        editorState: editorState,
+      ),
+    );
+  }
+}
+
+class _EditorNodeWidget extends StatelessWidget {
+  final Node node;
+  final EditorState editorState;
+
+  const _EditorNodeWidget({
+    Key? key,
+    required this.node,
+    required this.editorState,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SingleChildScrollView(
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: node.children
+            .map(
+              (e) => editorState.renderPlugins.buildWidget(
+                context: NodeWidgetContext(
+                  buildContext: context,
+                  node: e,
+                  editorState: editorState,
+                ),
+              ),
+            )
+            .toList(),
+      ),
+    );
+  }
+}

+ 1 - 8
frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart

@@ -1,7 +1,5 @@
 import 'package:flowy_editor/flowy_editor.dart';
 import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-import 'package:flowy_editor/document/attributes.dart';
 
 class ImageNodeBuilder extends NodeWidgetBuilder {
   ImageNodeBuilder.create({
@@ -33,12 +31,7 @@ class _ImageNodeWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return GestureDetector(
-      child: ChangeNotifierProvider.value(
-        value: node,
-        builder: (_, __) => Consumer<Node>(
-          builder: ((context, value, child) => _build(context)),
-        ),
-      ),
+      child: _build(context),
       onTap: () {
         editorState.update(node, {
           'image_src':

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

@@ -3,7 +3,6 @@ import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flowy_editor/flowy_editor.dart';
 import 'package:flutter/services.dart';
-import 'package:provider/provider.dart';
 import 'package:flowy_editor/document/attributes.dart';
 
 class TextNodeBuilder extends NodeWidgetBuilder {
@@ -98,7 +97,7 @@ class _TextNodeWidget extends StatefulWidget {
 
 class __TextNodeWidgetState extends State<_TextNodeWidget>
     implements TextInputClient {
-  Node get node => widget.node;
+  TextNode get node => widget.node as TextNode;
   EditorState get editorState => widget.editorState;
   TextEditingValue get textEditingValue => const TextEditingValue();
 
@@ -106,47 +105,39 @@ class __TextNodeWidgetState extends State<_TextNodeWidget>
 
   @override
   Widget build(BuildContext context) {
-    return ChangeNotifierProvider.value(
-      value: node,
-      builder: (_, __) => Consumer<Node>(
-        builder: ((context, value, child) {
-          final textNode = value as TextNode;
-          return Column(
-            crossAxisAlignment: CrossAxisAlignment.start,
-            children: [
-              SelectableText.rich(
-                TextSpan(
-                  children: textNode.toTextSpans(),
-                ),
-                onTap: () {
-                  _textInputConnection?.close();
-                  _textInputConnection = TextInput.attach(
-                    this,
-                    const TextInputConfiguration(
-                      enableDeltaModel: false,
-                      inputType: TextInputType.multiline,
-                      textCapitalization: TextCapitalization.sentences,
-                    ),
-                  );
-                  _textInputConnection
-                    ?..show()
-                    ..setEditingState(textEditingValue);
-                },
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        SelectableText.rich(
+          TextSpan(
+            children: node.toTextSpans(),
+          ),
+          onTap: () {
+            _textInputConnection?.close();
+            _textInputConnection = TextInput.attach(
+              this,
+              const TextInputConfiguration(
+                enableDeltaModel: false,
+                inputType: TextInputType.multiline,
+                textCapitalization: TextCapitalization.sentences,
               ),
-              if (node.children.isNotEmpty)
-                ...node.children.map(
-                  (e) => editorState.renderPlugins.buildWidget(
-                    context: NodeWidgetContext(
-                      buildContext: context,
-                      node: e,
-                      editorState: editorState,
-                    ),
-                  ),
-                )
-            ],
-          );
-        }),
-      ),
+            );
+            _textInputConnection
+              ?..show()
+              ..setEditingState(textEditingValue);
+          },
+        ),
+        if (node.children.isNotEmpty)
+          ...node.children.map(
+            (e) => editorState.renderPlugins.buildWidget(
+              context: NodeWidgetContext(
+                buildContext: context,
+                node: e,
+                editorState: editorState,
+              ),
+            ),
+          )
+      ],
     );
   }
 

+ 22 - 1
frontend/app_flowy/packages/flowy_editor/lib/render/node_widget_builder.dart

@@ -2,12 +2,15 @@ import 'package:flowy_editor/editor_state.dart';
 import 'package:flowy_editor/document/node.dart';
 import 'package:flowy_editor/render/render_plugins.dart';
 import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
 
 typedef NodeValidator<T extends Node> = bool Function(T node);
 
 class NodeWidgetBuilder<T extends Node> {
   final EditorState editorState;
   final T node;
+
+  bool rebuildOnNodeChanged;
   NodeValidator<T>? nodeValidator;
 
   RenderPlugins get renderPlugins => editorState.renderPlugins;
@@ -15,6 +18,7 @@ class NodeWidgetBuilder<T extends Node> {
   NodeWidgetBuilder.create({
     required this.editorState,
     required this.node,
+    this.rebuildOnNodeChanged = true,
   });
 
   /// Render the current [Node]
@@ -29,6 +33,23 @@ class NodeWidgetBuilder<T extends Node> {
       throw Exception(
           'Node validate failure, node = { type: ${node.type}, attributes: ${node.attributes} }');
     }
-    return build(buildContext);
+
+    if (rebuildOnNodeChanged) {
+      return _buildNodeChangeNotifier(buildContext);
+    } else {
+      return build(buildContext);
+    }
+  }
+
+  Widget _buildNodeChangeNotifier(BuildContext buildContext) {
+    return ChangeNotifierProvider.value(
+      value: node,
+      builder: (_, __) => Consumer<T>(
+        builder: ((context, value, child) {
+          debugPrint('Node changed, and rebuilding...');
+          return build(context);
+        }),
+      ),
+    );
   }
 }

+ 2 - 0
frontend/app_flowy/packages/flowy_editor/pubspec.yaml

@@ -11,6 +11,8 @@ dependencies:
   flutter:
     sdk: flutter
 
+  provider: ^6.0.3
+
 dev_dependencies:
   flutter_test:
     sdk: flutter