diff --git a/app_flowy/packages/flowy_editor/example/assets/block_document.fdoc b/app_flowy/packages/flowy_editor/example/assets/block_document.fdoc index 04dc2441e8..a8ab042949 100644 --- a/app_flowy/packages/flowy_editor/example/assets/block_document.fdoc +++ b/app_flowy/packages/flowy_editor/example/assets/block_document.fdoc @@ -8,6 +8,14 @@ }, "insert":"\n" }, + { + "insert": { + "flutter_logo": "" + }, + "attributes":{ + "size": 50.0 + } + }, { "insert":"\n" } diff --git a/app_flowy/packages/flowy_editor/example/ios/Podfile.lock b/app_flowy/packages/flowy_editor/example/ios/Podfile.lock new file mode 100644 index 0000000000..cfcdf38dfe --- /dev/null +++ b/app_flowy/packages/flowy_editor/example/ios/Podfile.lock @@ -0,0 +1,40 @@ +PODS: + - flowy_editor (0.0.1): + - Flutter + - Flutter (1.0.0) + - flutter_keyboard_visibility (0.0.1): + - Flutter + - path_provider (0.0.1): + - Flutter + - url_launcher (0.0.1): + - Flutter + +DEPENDENCIES: + - flowy_editor (from `.symlinks/plugins/flowy_editor/ios`) + - Flutter (from `Flutter`) + - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + +EXTERNAL SOURCES: + flowy_editor: + :path: ".symlinks/plugins/flowy_editor/ios" + Flutter: + :path: Flutter + flutter_keyboard_visibility: + :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + url_launcher: + :path: ".symlinks/plugins/url_launcher/ios" + +SPEC CHECKSUMS: + flowy_editor: bf8d58894ddb03453bd4d8521c57267ad638b837 + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + +PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c + +COCOAPODS: 1.9.3 diff --git a/app_flowy/packages/flowy_editor/lib/src/widget/builder.dart b/app_flowy/packages/flowy_editor/lib/src/widget/builder.dart index bba40b8847..58a6fa009b 100644 --- a/app_flowy/packages/flowy_editor/lib/src/widget/builder.dart +++ b/app_flowy/packages/flowy_editor/lib/src/widget/builder.dart @@ -146,42 +146,3 @@ class EditorTextSelectionGestureDetectorBuilder { ); } } - -/* ---------------------------------- Embed --------------------------------- */ - -class EmbedBuilder { - static const kImageTypeKey = 'image'; - static const kVideoTypeKey = 'video'; - - static Widget defaultBuilder(BuildContext context, Embed node) { - assert(!kIsWeb, 'Please provide EmbedBuilder for Web'); - switch (node.value.type) { - case kImageTypeKey: - return _generateImageEmbed(context, node); - default: - throw UnimplementedError('Embeddable type "${node.value.type}" is not supported by default embed ' - 'builder of QuillEditor. You must pass your own builder function to ' - 'embedBuilder property of QuillEditor or QuillField widgets.'); - } - } - - // 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)); - } - - // Helper - - static String standardizeImageUrl(String url) { - if (url.contains('base64')) { - return url.split(',')[1]; - } - return url; - } -} diff --git a/app_flowy/packages/flowy_editor/lib/src/widget/embed.dart b/app_flowy/packages/flowy_editor/lib/src/widget/embed.dart new file mode 100644 index 0000000000..3448d473f2 --- /dev/null +++ b/app_flowy/packages/flowy_editor/lib/src/widget/embed.dart @@ -0,0 +1,106 @@ +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:string_validator/string_validator.dart'; + +import '../model/document/node/leaf.dart' show Embed; + +abstract class EmbedWidgetBuilder { + bool canHandle(String type); + + Widget? buildeWidget(BuildContext context, Embed node); +} + +/* ---------------------------------- Embed --------------------------------- */ + +class EmbedBuilder { + static const kImageTypeKey = 'image'; + 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]; + } + return url; + } +} + +/* ---------------------------- Unsupported Hint ---------------------------- */ + +class _UnsupportedHintBlock extends StatelessWidget { + final Embed node; + final double height; + + const _UnsupportedHintBlock( + this.node, { + Key? key, + this.height = 80.0, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: height, + child: Column( + children: [ + Icon( + Icons.warning, + color: Colors.red, + ), + Text('Unsupported block type "${node.value.type}"'), + ], + ), + ); + } +}