Browse Source

[editor] Impl image and flutter logo test embed builders

Jaylen Bian 3 years ago
parent
commit
a728e16469

+ 12 - 1
app_flowy/packages/flowy_editor/example/assets/block_document.fdoc

@@ -13,7 +13,18 @@
          "flutter_logo": ""
       },
       "attributes":{
-         "size": 50.0
+         "size": 200.0
+      }
+   },
+   {
+      "insert":"\n"
+   },
+   {
+      "insert": {
+         "test_block_type": "test_data"
+      },
+      "attributes":{
+         
       }
    },
    {

+ 0 - 6
app_flowy/packages/flowy_editor/lib/src/widget/builder.dart

@@ -1,12 +1,6 @@
-import 'dart:convert';
-import 'dart:io' as io;
-
-import 'package:flutter/foundation.dart';
 import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
-import 'package:string_validator/string_validator.dart';
 
-import '../model/document/node/leaf.dart';
 import '../widget/raw_editor.dart';
 import '../widget/selection.dart';
 import '../rendering/editor.dart';

+ 6 - 31
app_flowy/packages/flowy_editor/lib/src/widget/editor.dart

@@ -1,22 +1,18 @@
-import 'dart:io' as io;
-import 'dart:convert';
 import 'dart:ui';
 
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:url_launcher/url_launcher.dart';
-import 'package:string_validator/string_validator.dart';
 
 import '../widget/raw_editor.dart';
 import '../widget/builder.dart';
+import '../widget/embed.dart';
 import '../widget/proxy.dart';
-import '../widget/image_viewer_screen.dart';
 import '../model/document/attribute.dart';
 import '../model/document/document.dart';
-import '../model/document/node/embed.dart';
 import '../model/document/node/line.dart';
 import '../model/document/node/container.dart' as container_node;
-import '../model/document/node/leaf.dart' as leaf;
+import '../model/document/node/leaf.dart' show Leaf;
 import '../service/controller.dart';
 import '../service/cursor.dart';
 import '../service/style.dart';
@@ -61,13 +57,13 @@ class FlowyEditor extends StatefulWidget {
     this.textCapitalization = TextCapitalization.sentences,
     this.keyboardAppearance = Brightness.light,
     this.scrollPhysics,
-    this.embedBuilder = EmbedBuilder.defaultBuilder,
     this.onLaunchUrl,
     this.onTapDown,
     this.onTapUp,
     this.onLongPressStart,
     this.onLongPressMoveUpdate,
     this.onLongPressEnd,
+    this.embedProvider = EmbedBaseProvider.buildEmbedWidget,
   });
 
   factory FlowyEditor.basic({
@@ -105,7 +101,7 @@ class FlowyEditor extends StatefulWidget {
   final TextCapitalization textCapitalization;
   final Brightness keyboardAppearance;
   final ScrollPhysics? scrollPhysics;
-  final EmbedBuilderFuncion embedBuilder;
+  final EmbedBuilderFuncion embedProvider;
 
   // Callback
 
@@ -222,7 +218,7 @@ class _FlowyEditorState extends State<FlowyEditor> implements EditorTextSelectio
         widget.keyboardAppearance,
         widget.enableInteractiveSelection,
         widget.scrollPhysics,
-        widget.embedBuilder,
+        widget.embedProvider,
       ),
     );
   }
@@ -429,7 +425,7 @@ class _FlowyEditorSelectionGestureDetectorBuilder extends EditorTextSelectionGes
     }
 
     // Link
-    final segment = segmentResult.node as leaf.Leaf;
+    final segment = segmentResult.node as Leaf;
     if (segment.style.containsKey(Attribute.link.key)) {
       var launchUrl = getEditor()!.widget.onLaunchUrl;
       launchUrl ??= _launchUrl;
@@ -444,27 +440,6 @@ class _FlowyEditorSelectionGestureDetectorBuilder extends EditorTextSelectionGes
       return false;
     }
 
-    // Image
-    if (getEditor()!.widget.readOnly && segment.value is BlockEmbed) {
-      final blockEmbed = segment.value as BlockEmbed;
-      if (blockEmbed.type == 'image') {
-        final imageUrl = EmbedBuilder.standardizeImageUrl(blockEmbed.data);
-        Navigator.push(
-          getEditor()!.context,
-          MaterialPageRoute(builder: (context) {
-            return ImageTapWrapper(
-              imageProvider: imageUrl.startsWith('http')
-                  ? NetworkImage(imageUrl)
-                  : isBase64(imageUrl)
-                      ? Image.memory(base64.decode(imageUrl)) as ImageProvider<Object>?
-                      : FileImage(io.File(imageUrl)),
-            );
-          }),
-        );
-      }
-      return false;
-    }
-
     // Fallback
     if (_flipListCheckbox(position, line, segmentResult)) {
       return true;

+ 20 - 60
app_flowy/packages/flowy_editor/lib/src/widget/embed.dart

@@ -1,78 +1,38 @@
-import 'dart:convert';
-import 'dart:io' as io;
-
+import 'package:flowy_editor/src/widget/embed_builder/logo_builder.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
-import 'package:string_validator/string_validator.dart';
 
+import '../widget/embed_builder/image_builder.dart';
 import '../model/document/node/leaf.dart' show Embed;
 
 abstract class EmbedWidgetBuilder {
+  const EmbedWidgetBuilder();
+
   bool canHandle(String type);
 
   Widget? buildeWidget(BuildContext context, Embed node);
 }
 
 /* ---------------------------------- Embed --------------------------------- */
-
-class EmbedBuilder {
-  static const kImageTypeKey = 'image';
+class EmbedBaseProvider {
   static const kFlutterLogoTypeKey = 'flutter_logo';
 
-  static const builtInTypes = [kImageTypeKey, kFlutterLogoTypeKey];
-
-  static Widget defaultBuilder(BuildContext context, Embed node) {
-    assert(!kIsWeb, 'Please provide EmbedBuilder for Web');
-    switch (node.value.type) {
-      case kImageTypeKey:
-        return _generateImageEmbed(context, node);
-      case kFlutterLogoTypeKey:
-        return _generateFlutterLogoEmbed(context, node);
-      default:
-        return Align(
-          alignment: Alignment.center,
-          child: _UnsupportedHintBlock(node),
-        );
-    }
-  }
-
-  // Generator
-
-  static Widget _generateImageEmbed(BuildContext context, Embed node) {
-    final imageUrl = standardizeImageUrl(node.value.data);
-    return imageUrl.startsWith('http')
-        ? Image.network(imageUrl)
-        : isBase64(imageUrl)
-            ? Image.memory(base64.decode(imageUrl))
-            : Image.file(io.File(imageUrl));
-  }
-
-  static Widget _generateFlutterLogoEmbed(BuildContext context, Embed node) {
-    final size = node.style.attributes['size'];
-    var logoSize = size != null ? size.value as double? ?? 100.0 : 100.0;
-    return Align(
-      alignment: Alignment.center,
-      child: Container(
-        width: logoSize,
-        height: logoSize,
-        color: Colors.red,
-        child: GestureDetector(
-          onTap: () {
-            print('Flutter logo tapped');
-          },
-          child: FlutterLogo(size: logoSize),
-        ),
-      ),
-    );
-  }
-
-  // Helper
-
-  static String standardizeImageUrl(String url) {
-    if (url.contains('base64')) {
-      return url.split(',')[1];
+  static const builtInProviders = <EmbedWidgetBuilder>[
+    ImageEmbedBuilder(),
+    LogoEmbedBuilder(),
+  ];
+
+  static Widget buildEmbedWidget(BuildContext context, Embed node) {
+    Widget? result;
+    for (final builder in builtInProviders) {
+      if (builder.canHandle(node.value.type)) {
+        result = builder.buildeWidget(context, node);
+        if (result != null) {
+          break;
+        }
+      }
     }
-    return url;
+    return result ?? Align(alignment: Alignment.center, child: _UnsupportedHintBlock(node));
   }
 }
 

+ 52 - 0
app_flowy/packages/flowy_editor/lib/src/widget/embed_builder/image_builder.dart

@@ -0,0 +1,52 @@
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter/material.dart';
+import 'package:string_validator/string_validator.dart';
+
+import '../../model/document/node/leaf.dart' show Embed;
+import '../embed.dart';
+
+/* --------------------------------- Sample --------------------------------- */
+
+///
+/// {
+///   "insert": {
+///     "image": "https://test.com/sample.png"
+///   },
+///   "attributes" : {
+///     "width": "100.0"
+///   }
+/// }
+///
+
+/* --------------------------------- Builder -------------------------------- */
+
+class ImageEmbedBuilder extends EmbedWidgetBuilder {
+  const ImageEmbedBuilder() : super();
+
+  static const kImageTypeKey = 'image';
+
+  @override
+  bool canHandle(String type) {
+    return type == kImageTypeKey;
+  }
+
+  @override
+  Widget? buildeWidget(BuildContext context, Embed node) {
+    final imageUrl = _standardizeImageUrl(node.value.data);
+    return imageUrl.startsWith('http')
+        ? Image.network(imageUrl)
+        : isBase64(imageUrl)
+            ? Image.memory(base64.decode(imageUrl))
+            : Image.file(io.File(imageUrl));
+  }
+
+  String _standardizeImageUrl(String url) {
+    if (url.contains('base64')) {
+      return url.split(',')[1];
+    }
+    return url;
+  }
+}

+ 50 - 0
app_flowy/packages/flowy_editor/lib/src/widget/embed_builder/logo_builder.dart

@@ -0,0 +1,50 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+import '../../model/document/node/leaf.dart';
+import '../../widget/embed.dart';
+
+/* --------------------------------- Sample --------------------------------- */
+
+///
+/// {
+///   "insert": {
+///     "flutter_logo": ""
+///   },
+///   "attributes" : {
+///     "size": 100.0
+///   }
+/// }
+///
+
+/* --------------------------------- Builder -------------------------------- */
+
+class LogoEmbedBuilder extends EmbedWidgetBuilder {
+  const LogoEmbedBuilder() : super();
+
+  static const kImageTypeKey = 'flutter_logo';
+
+  @override
+  bool canHandle(String type) {
+    return type == kImageTypeKey;
+  }
+
+  @override
+  Widget? buildeWidget(BuildContext context, Embed node) {
+    final size = node.style.attributes['size'];
+    var logoSize = size != null ? size.value as double? ?? 100.0 : 100.0;
+    return Align(
+      alignment: Alignment.center,
+      child: Container(
+        width: logoSize,
+        height: logoSize,
+        child: GestureDetector(
+          onTap: () {
+            print('Flutter logo tapped');
+          },
+          child: FlutterLogo(size: logoSize),
+        ),
+      ),
+    );
+  }
+}

+ 3 - 6
app_flowy/packages/flowy_editor/lib/src/widget/proxy.dart

@@ -22,8 +22,7 @@ class BaselineProxy extends SingleChildRenderObjectWidget {
   }
 
   @override
-  void updateRenderObject(
-      BuildContext context, covariant RenderBaselineProxy renderObject) {
+  void updateRenderObject(BuildContext context, covariant RenderBaselineProxy renderObject) {
     renderObject
       ..textStyle = textStyle!
       ..padding = padding!;
@@ -38,8 +37,7 @@ class EmbedProxy extends SingleChildRenderObjectWidget {
   const EmbedProxy(Widget child) : super(child: child);
 
   @override
-  RenderEmbedProxy createRenderObject(BuildContext context) =>
-      RenderEmbedProxy(null);
+  RenderEmbedProxy createRenderObject(BuildContext context) => RenderEmbedProxy(null);
 }
 
 /* ---------------------------------- Text ---------------------------------- */
@@ -82,8 +80,7 @@ class RichTextProxy extends SingleChildRenderObjectWidget {
   }
 
   @override
-  void updateRenderObject(
-      BuildContext context, covariant RenderParagraphProxy renderObject) {
+  void updateRenderObject(BuildContext context, covariant RenderParagraphProxy renderObject) {
     renderObject
       ..textStyle = textStyle
       ..textAlign = textAlign