diff --git a/CHANGELOG.md b/CHANGELOG.md index d19c5509..87ecc8eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [8.2.3] +- Update `README.md` + ## [8.2.2] - Move the `flutter_quill_test` to seperated package [flutter_quill_test](https://pub.dev/packages/flutter_quill_test) diff --git a/README.md b/README.md index 8efbfc94..472313f9 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,6 @@ Pub: [FlutterQuill] - [Custom Buttons](#custom-buttons) - [Embed Blocks](#embed-blocks) - [Using the embed blocks from `flutter_quill_extensions`](#using-the-embed-blocks-from-flutter_quill_extensions) - - [Custom Size Image for Mobile](#custom-size-image-for-mobile) - - [Custom Size Image for other platforms (excluding web)](#custom-size-image-for-other-platforms-excluding-web) - [Custom Embed Blocks](#custom-embed-blocks) - [Custom Toolbar](#custom-toolbar) - [Translation](#translation) @@ -253,36 +251,6 @@ Provide a list of embed To see how to use the extensions package, please take a look at the [README](./flutter_quill_extensions/README.md) of [FlutterQuill Extensions] -### Custom Size Image for Mobile - -Define `mobileWidth`, `mobileHeight`, `mobileMargin`, `mobileAlignment` as follows: - -```json -{ - "insert": { - "image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png" - }, - "attributes":{ - "style":"mobileWidth: 50; mobileHeight: 50; mobileMargin: 10; mobileAlignment: topLeft" - } -} -``` - -### Custom Size Image for other platforms (excluding web) - -Define `width`, `height`, `margin`, `alignment` as follows: - -```json -{ - "insert": { - "image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png" - }, - "attributes":{ - "style":"width: 50; height: 50; margin: 10; alignment: topLeft" - } -} -``` - ### Custom Embed Blocks Sometimes you want to add some custom content inside your text, custom widgets inside of them. An example is adding notes to the text, or anything custom that you want to add in your text editor. diff --git a/example/assets/sample_data.json b/example/assets/sample_data.json index 467bcadd..2d376d7f 100644 --- a/example/assets/sample_data.json +++ b/example/assets/sample_data.json @@ -531,7 +531,7 @@ }, "attributes": { "width": "230", - "style": "display: block; margin: auto;" + "style": "display: block; margin: auto; width: 500px;" } }, { diff --git a/example/assets/sample_data_nomedia.json b/example/assets/sample_data_nomedia.json index e541d153..37289149 100644 --- a/example/assets/sample_data_nomedia.json +++ b/example/assets/sample_data_nomedia.json @@ -63,16 +63,6 @@ }, "insert": " and " }, - { - "attributes": { - "strike": true, - "color": "black" - }, - "insert": "web" - }, - { - "insert": " is not supported.\nYou are welcome to use " - }, { "attributes": { "link": "https://bulletjournal.us/home/index.html" diff --git a/example/assets/sample_data_testing.json b/example/assets/sample_data_testing.json new file mode 100644 index 00000000..bd725222 --- /dev/null +++ b/example/assets/sample_data_testing.json @@ -0,0 +1,97 @@ +[ + { + "insert": "Here is an image: \n" + }, + { + "insert": "\n" + }, + { + "insert": { + "image": "https://helpx.adobe.com/content/dam/help/en/photoshop/using/convert-color-image-black-white/jcr_content/main-pars/before_and_after/image-before/Landscape-Color.jpg" + }, + "attributes": { + "width": "100", + "height": "100", + "style": "width:250px; height:250px;" + } + }, + { + "insert": "\n" + }, + { + "insert": "\n" + }, + { + "insert": "\nThe image above have 250px width and height in the css style attribute which will be used for web, and 100 width and height that is in the attributes which will be used for desktop and mobile\n" + }, + { + "insert": "\n" + }, + { + "insert": { + "image": "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" + }, + "attributes": { + "width": "100", + "height": "100", + "style": "width:250px; height:250px;" + } + }, + { + "insert": "\n" + }, + { + "insert": "\nThe source of the above image is image base 64 directly without `data:image/png;base64,` in the start" + }, + { + "insert": "\n" + }, + { + "insert": "\n" + }, + { + "insert": "" + }, + { + "insert": { + "image": "data:image/png;base64,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" + }, + "attributes": { + "width": "100", + "height": "100", + "style": "width:250px; height:250px;" + } + }, + { + "insert": "\n" + }, + { + "insert": "\n" + }, + { + "insert": "The source of the above image is also image base 64 but this time it start with `data:image/png;base64,`" + }, + { + "insert": "\n" + }, + { + "insert": "\n" + }, + { + "insert": { + "video": "https://youtu.be/xz6_AlJkDPA" + } + }, + { + "insert": "\n" + }, + { + "insert": "\n" + }, + { + "insert": "And this is just a youtube video" + }, + { + "insert": "\n" + } +] \ No newline at end of file diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 81947f0f..69c9c8a6 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -53,16 +53,19 @@ class _HomePageState extends State { Future _loadFromAssets() async { try { - final result = await rootBundle.loadString(isDesktop() - ? 'assets/sample_data_nomedia.json' - : 'assets/sample_data.json'); + final result = + await rootBundle.loadString('assets/sample_data_testing.json'); + // final result = await rootBundle.loadString(isDesktop() + // ? 'assets/sample_data_nomedia.json' + // : 'assets/sample_data.json'); final doc = Document.fromJson(jsonDecode(result)); _controller = QuillController( document: doc, selection: const TextSelection.collapsed(offset: 0), ); } catch (error) { - final doc = Document()..insert(0, 'Empty asset'); + final doc = Document() + ..insert(0, 'Error while loading the document: ${error.toString()}'); _controller = QuillController( document: doc, selection: const TextSelection.collapsed(offset: 0), diff --git a/example/lib/universal_ui/universal_ui.dart b/example/lib/universal_ui/universal_ui.dart index 0e6d382d..9971b926 100644 --- a/example/lib/universal_ui/universal_ui.dart +++ b/example/lib/universal_ui/universal_ui.dart @@ -1,118 +1,115 @@ library universal_ui; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'; -import 'package:universal_html/html.dart' as html; -import 'package:youtube_player_flutter/youtube_player_flutter.dart'; -import '../widgets/responsive_widget.dart'; -import 'fake_ui.dart' if (dart.library.html) 'real_ui.dart' as ui_instance; +// import '../widgets/responsive_widget.dart'; +// import 'fake_ui.dart' if (dart.library.html) 'real_ui.dart' as ui_instance; -class PlatformViewRegistryFix { - void registerViewFactory(dynamic x, dynamic y) { - if (kIsWeb) { - ui_instance.PlatformViewRegistry.registerViewFactory( - x, - y, - ); - } - } -} +// class PlatformViewRegistryFix { +// void registerViewFactory(dynamic x, dynamic y) { +// if (kIsWeb) { +// ui_instance.PlatformViewRegistry.registerViewFactory( +// x, +// y, +// ); +// } +// } +// } -class UniversalUI { - PlatformViewRegistryFix platformViewRegistry = PlatformViewRegistryFix(); -} +// class UniversalUI { +// PlatformViewRegistryFix platformViewRegistry = PlatformViewRegistryFix(); +// } -var ui = UniversalUI(); +// var ui = UniversalUI(); -class ImageEmbedBuilderWeb extends EmbedBuilder { - @override - String get key => BlockEmbed.imageType; +// class ImageEmbedBuilderWeb extends EmbedBuilder { +// @override +// String get key => BlockEmbed.imageType; - @override - Widget build( - BuildContext context, - QuillController controller, - Embed node, - bool readOnly, - bool inline, - TextStyle textStyle, - ) { - final imageUrl = node.value.data; - if (isImageBase64(imageUrl)) { - // TODO: handle imageUrl of base64 - return const SizedBox(); - } - final size = MediaQuery.sizeOf(context); - UniversalUI().platformViewRegistry.registerViewFactory(imageUrl, (viewId) { - return html.ImageElement() - ..src = imageUrl - ..style.height = 'auto' - ..style.width = 'auto'; - }); - return Padding( - padding: EdgeInsets.only( - right: ResponsiveWidget.isMediumScreen(context) - ? size.width * 0.5 - : (ResponsiveWidget.isLargeScreen(context)) - ? size.width * 0.75 - : size.width * 0.2, - ), - child: SizedBox( - height: size.height * 0.45, - child: HtmlElementView( - viewType: imageUrl, - ), - ), - ); - } -} +// @override +// Widget build( +// BuildContext context, +// QuillController controller, +// Embed node, +// bool readOnly, +// bool inline, +// TextStyle textStyle, +// ) { +// final imageUrl = node.value.data; +// if (isImageBase64(imageUrl)) { +// // TODO: handle imageUrl of base64 +// return const SizedBox(); +// } +// final size = MediaQuery.sizeOf(context); +// UniversalUI().platformViewRegistry.registerViewFactory(imageUrl, +//(viewId) { +// return html.ImageElement() +// ..src = imageUrl +// ..style.height = 'auto' +// ..style.width = 'auto'; +// }); +// return Padding( +// padding: EdgeInsets.only( +// right: ResponsiveWidget.isMediumScreen(context) +// ? size.width * 0.5 +// : (ResponsiveWidget.isLargeScreen(context)) +// ? size.width * 0.75 +// : size.width * 0.2, +// ), +// child: SizedBox( +// height: size.height * 0.45, +// child: HtmlElementView( +// viewType: imageUrl, +// ), +// ), +// ); +// } +// } -class VideoEmbedBuilderWeb extends EmbedBuilder { - @override - String get key => BlockEmbed.videoType; +// class VideoEmbedBuilderWeb extends EmbedBuilder { +// @override +// String get key => BlockEmbed.videoType; - @override - Widget build( - BuildContext context, - QuillController controller, - Embed node, - bool readOnly, - bool inline, - TextStyle textStyle, - ) { - var videoUrl = node.value.data; - if (videoUrl.contains('youtube.com') || videoUrl.contains('youtu.be')) { - final youtubeID = YoutubePlayer.convertUrlToId(videoUrl); - if (youtubeID != null) { - videoUrl = 'https://www.youtube.com/embed/$youtubeID'; - } - } +// @override +// Widget build( +// BuildContext context, +// QuillController controller, +// Embed node, +// bool readOnly, +// bool inline, +// TextStyle textStyle, +// ) { +// var videoUrl = node.value.data; +// if (videoUrl.contains('youtube.com') || videoUrl.contains('youtu.be')) { +// final youtubeID = YoutubePlayer.convertUrlToId(videoUrl); +// if (youtubeID != null) { +// videoUrl = 'https://www.youtube.com/embed/$youtubeID'; +// } +// } - final size = MediaQuery.sizeOf(context); +// final size = MediaQuery.sizeOf(context); - UniversalUI().platformViewRegistry.registerViewFactory( - videoUrl, - (id) => html.IFrameElement() - ..width = size.width.toString() - ..height = size.height.toString() - ..src = videoUrl - ..style.border = 'none', - ); +// UniversalUI().platformViewRegistry.registerViewFactory( +// videoUrl, +// (id) => html.IFrameElement() +// ..width = size.width.toString() +// ..height = size.height.toString() +// ..src = videoUrl +// ..style.border = 'none', +// ); - return SizedBox( - height: 500, - child: HtmlElementView( - viewType: videoUrl, - ), - ); - } -} +// return SizedBox( +// height: 500, +// child: HtmlElementView( +// viewType: videoUrl, +// ), +// ); +// } +// } List get defaultEmbedBuildersWeb => [ + ...FlutterQuillEmbeds.editorsWebBuilders(), // ImageEmbedBuilderWeb(), - const QuillEditorWebImageEmbedBuilder(), - VideoEmbedBuilderWeb(), + // VideoEmbedBuilderWeb(), ]; diff --git a/flutter_quill_extensions/CHANGELOG.md b/flutter_quill_extensions/CHANGELOG.md index 0ae9e262..ce1f9d3a 100644 --- a/flutter_quill_extensions/CHANGELOG.md +++ b/flutter_quill_extensions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.0-dev.6 +- Better support for web +- Smal fixes and updates + ## 0.6.0-dev.5 - Update the camera button diff --git a/flutter_quill_extensions/README.md b/flutter_quill_extensions/README.md index f65bf91b..3e8575cb 100644 --- a/flutter_quill_extensions/README.md +++ b/flutter_quill_extensions/README.md @@ -15,6 +15,9 @@ Currently the support for **Web** is limitied. - [Installation](#installation) - [Platform Spesefic Configurations](#platform-spesefic-configurations) - [Usage](#usage) + - [Embed Blocks](#embed-blocks) + - [Custom Size Image for Mobile](#custom-size-image-for-mobile) + - [Custom Size Image for other platforms (excluding web)](#custom-size-image-for-other-platforms-excluding-web) - [Features](#features) - [Contributing](#contributing) - [License](#license) @@ -110,6 +113,40 @@ QuillProvider( ) ``` +## Embed Blocks + +As of version [flutter_quill](https://pub.dev/packages/flutter_quill) 6.0, embed blocks are not provided by default as part of Flutter quill. Instead, it provides an interface to all the user to provide there own implementations for embed blocks. Implementations for image, video and formula embed blocks is proved in this package + +### Custom Size Image for Mobile + +Define `mobileWidth`, `mobileHeight`, `mobileMargin`, `mobileAlignment` as follows: + +```json +{ + "insert": { + "image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png" + }, + "attributes":{ + "style":"mobileWidth: 50; mobileHeight: 50; mobileMargin: 10; mobileAlignment: topLeft" + } +} +``` + +### Custom Size Image for other platforms (excluding web) + +Define `width`, `height`, `margin`, `alignment` as follows: + +```json +{ + "insert": { + "image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png" + }, + "attributes": { + "style":"width: 50; height: 50; margin: 10; alignment: topLeft" + } +} +``` + ## Features ```markdown diff --git a/flutter_quill_extensions/lib/flutter_quill_extensions.dart b/flutter_quill_extensions/lib/flutter_quill_extensions.dart index 862b6663..a5c372ef 100644 --- a/flutter_quill_extensions/lib/flutter_quill_extensions.dart +++ b/flutter_quill_extensions/lib/flutter_quill_extensions.dart @@ -4,10 +4,10 @@ import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter_quill/flutter_quill.dart'; import 'package:meta/meta.dart' show immutable; -import 'logic/models/config/shared_configurations.dart'; import 'presentation/embeds/editor/image/image.dart'; import 'presentation/embeds/editor/image/image_web.dart'; -import 'presentation/embeds/editor/video.dart'; +import 'presentation/embeds/editor/video/video.dart'; +import 'presentation/embeds/editor/video/video_web.dart'; import 'presentation/embeds/editor/webview.dart'; import 'presentation/embeds/toolbar/camera_button/camera_button.dart'; import 'presentation/embeds/toolbar/formula_button.dart'; @@ -16,8 +16,10 @@ import 'presentation/embeds/toolbar/image_button/image_button.dart'; // ignore: unused_import import 'presentation/embeds/toolbar/media_button/media_button.dart'; import 'presentation/embeds/toolbar/video_button/video_button.dart'; -import 'presentation/models/config/editor/image.dart'; -import 'presentation/models/config/editor/video.dart'; +import 'presentation/models/config/editor/image/image.dart'; +import 'presentation/models/config/editor/image/image_web.dart'; +import 'presentation/models/config/editor/video/video.dart'; +import 'presentation/models/config/editor/video/video_web.dart'; import 'presentation/models/config/editor/webview.dart'; import 'presentation/models/config/toolbar/buttons/camera.dart'; import 'presentation/models/config/toolbar/buttons/formula.dart'; @@ -39,7 +41,7 @@ export 'presentation/embeds/toolbar/media_button/media_button.dart'; export 'presentation/embeds/toolbar/utils/image_video_utils.dart'; export 'presentation/embeds/toolbar/video_button/video_button.dart'; export 'presentation/embeds/utils.dart'; -export 'presentation/models/config/editor/image.dart'; +export 'presentation/models/config/editor/image/image.dart'; export 'presentation/models/config/toolbar/buttons/camera.dart'; export 'presentation/models/config/toolbar/buttons/formula.dart'; export 'presentation/models/config/toolbar/buttons/image.dart'; @@ -112,12 +114,11 @@ class FlutterQuillEmbeds { /// [QuillEditorImageEmbedBuilderWeb] is the embed builder for handling /// images on the web. /// - static List editorsWebBuilders({ - QuillSharedExtensionsConfigurations sharedExtensionsConfigurations = - const QuillSharedExtensionsConfigurations(), - QuillEditorWebImageEmbedConfigurations? imageEmbedConfigurations = - const QuillEditorWebImageEmbedConfigurations(), - }) { + static List editorsWebBuilders( + {QuillEditorWebImageEmbedConfigurations? imageEmbedConfigurations = + const QuillEditorWebImageEmbedConfigurations(), + QuillEditorWebVideoEmbedConfigurations? videoEmbedConfigurations = + const QuillEditorWebVideoEmbedConfigurations()}) { if (!kIsWeb) { throw UnsupportedError( 'The editorsWebBuilders() is only for web, please use editorBuilders() ' @@ -126,7 +127,13 @@ class FlutterQuillEmbeds { } return [ if (imageEmbedConfigurations != null) - const QuillEditorWebImageEmbedBuilder(), + QuillEditorWebImageEmbedBuilder( + configurations: imageEmbedConfigurations, + ), + if (videoEmbedConfigurations != null) + QuillEditorWebVideoEmbedBuilder( + configurations: videoEmbedConfigurations, + ), ]; } @@ -183,6 +190,7 @@ class FlutterQuillEmbeds { controller: cameraButtonOptions.controller ?? controller, options: cameraButtonOptions, ), + // TODO: We will return the support for this later // if (mediaButtonOptions != null) // (controller, toolbarIconSize, iconTheme, dialogTheme) => // QuillToolbarMediaButton( diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart index 666fe993..1c87a0f6 100644 --- a/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart +++ b/flutter_quill_extensions/lib/presentation/embeds/editor/image/image.dart @@ -5,7 +5,7 @@ import 'package:flutter_quill/extensions.dart' as base; import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/translations.dart'; -import '../../../models/config/editor/image.dart'; +import '../../../models/config/editor/image/image.dart'; import '../../embed_types/image.dart'; import '../../utils.dart'; import '../../widgets/image.dart'; @@ -84,7 +84,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder { imageSize = OptionalSize(width, height); image = Padding( padding: EdgeInsets.all(margin), - child: getQuillImageByUrl( + child: getQuillImageByImageSource( imageUrl, width: width, height: height, @@ -97,7 +97,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder { } if (imageSize == null) { - image = getQuillImageByUrl( + image = getQuillImageByImageSource( imageUrl, imageProviderBuilder: configurations.imageProviderBuilder, imageErrorWidgetBuilder: configurations.imageErrorWidgetBuilder, diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/image/image_web.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/image/image_web.dart index 34e40f2d..660c8c02 100644 --- a/flutter_quill_extensions/lib/presentation/embeds/editor/image/image_web.dart +++ b/flutter_quill_extensions/lib/presentation/embeds/editor/image/image_web.dart @@ -4,16 +4,17 @@ import 'package:flutter_quill/extensions.dart' as base; import 'package:flutter_quill/flutter_quill.dart'; import 'package:universal_html/html.dart' as html; +import '../../../models/config/editor/image/image_web.dart'; import '../../utils.dart'; -import 'shims/dart_ui_fake.dart' +import '../shims/dart_ui_fake.dart' if (dart.library.html) 'shims/dart_ui_real.dart' as ui; class QuillEditorWebImageEmbedBuilder extends EmbedBuilder { const QuillEditorWebImageEmbedBuilder({ - this.constraints, + required this.configurations, }); - final BoxConstraints? constraints; + final QuillEditorWebImageEmbedConfigurations configurations; @override String get key => BlockEmbed.imageType; @@ -28,46 +29,94 @@ class QuillEditorWebImageEmbedBuilder extends EmbedBuilder { TextStyle textStyle, ) { assert(kIsWeb, 'ImageEmbedBuilderWeb is only for web platform'); - final imageUrl = node.value.data; - if (isImageBase64(imageUrl)) { - // TODO: handle imageUrl of base64 - return const Text('Image base 64 is not supported yet.'); - } + final (height, width, margin, alignment) = _getImageSizeForWeb(node); - var height = 'auto'; - var width = 'auto'; - - final style = node.style.attributes['style']; - if (style != null) { - final attrs = base.parseKeyValuePairs(style.value.toString(), { - Attribute.width.key, - Attribute.height.key, - Attribute.margin, - Attribute.alignment, - }); - final heightValue = attrs[Attribute.height.key]; - if (heightValue != null) { - height = heightValue; - } - final widthValue = attrs[Attribute.width.key]; - if (widthValue != null) { - width = widthValue; + var imageSource = node.value.data.toString(); + + // This logic make sure if the image is imageBase64 then + // it make sure if the pattern is like + // data:image/png;base64, [base64 encoded image string here] + // if not then it will add the data:image/png;base64, at the first + if (isImageBase64(imageSource)) { + // Sometimes the image base 64 for some reasons + // doesn't displayed with the + if (!(imageSource.startsWith('data:image/') && + imageSource.contains('base64'))) { + imageSource = 'data:image/png;base64, $imageSource'; } } - ui.PlatformViewRegistry().registerViewFactory(imageUrl, (viewId) { + ui.PlatformViewRegistry().registerViewFactory(imageSource, (viewId) { return html.ImageElement() - ..src = imageUrl + ..src = imageSource ..style.height = height - ..style.width = width; + ..style.width = width + ..style.margin = margin + ..style.alignSelf = alignment; }); return ConstrainedBox( - constraints: constraints ?? BoxConstraints.loose(const Size(200, 200)), + constraints: configurations.constraints ?? + BoxConstraints.loose(const Size(200, 200)), child: HtmlElementView( - viewType: imageUrl, + viewType: imageSource, ), ); } } + +/// Prefer the width, and height from the css style attribute if exits +/// it can be `auto` or `100px` so it's specific to HTML && CSS +/// if not, we will use the one from attributes which is usually just an double +( + String height, + String width, + String margin, + String alignment, +) _getImageSizeForWeb( + Node node, +) { + var height = 'auto'; + var width = 'auto'; + const margin = 'auto'; + const alignment = 'center'; + + final cssStyle = node.style.attributes['style']; + + // Usually double value + final heightValue = node.style.attributes[Attribute.height.key]?.value; + final widthValue = node.style.attributes[Attribute.width.key]?.value; + + if (cssStyle != null) { + final attrs = base.parseKeyValuePairs(cssStyle.value.toString(), { + Attribute.width.key, + Attribute.height.key, + Attribute.margin, + Attribute.alignment, + }); + final cssHeightValue = attrs[Attribute.height.key]; + if (cssHeightValue != null) { + height = cssHeightValue; + } else { + height = '${heightValue}px'; + } + final cssWidthValue = attrs[Attribute.width.key]; + if (cssWidthValue != null) { + width = cssWidthValue; + } else if (widthValue != null) { + width = '${widthValue}px'; + } + + return (height, width, margin, alignment); + } + + if (heightValue != null) { + height = '${heightValue}px'; + } + if (widthValue != null) { + width = '${widthValue}px'; + } + + return (height, width, margin, alignment); +} diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/image/shims/dart_ui_fake.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/shims/dart_ui_fake.dart similarity index 100% rename from flutter_quill_extensions/lib/presentation/embeds/editor/image/shims/dart_ui_fake.dart rename to flutter_quill_extensions/lib/presentation/embeds/editor/shims/dart_ui_fake.dart diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/image/shims/dart_ui_real.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/shims/dart_ui_real.dart similarity index 100% rename from flutter_quill_extensions/lib/presentation/embeds/editor/image/shims/dart_ui_real.dart rename to flutter_quill_extensions/lib/presentation/embeds/editor/shims/dart_ui_real.dart diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/video.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/video/video.dart similarity index 92% rename from flutter_quill_extensions/lib/presentation/embeds/editor/video.dart rename to flutter_quill_extensions/lib/presentation/embeds/editor/video/video.dart index 35e927e8..94aa2ea8 100644 --- a/flutter_quill_extensions/lib/presentation/embeds/editor/video.dart +++ b/flutter_quill_extensions/lib/presentation/embeds/editor/video/video.dart @@ -5,10 +5,10 @@ import 'package:flutter_quill/extensions.dart' as base; import 'package:flutter_quill/flutter_quill.dart'; import 'package:math_keyboard/math_keyboard.dart'; -import '../../models/config/editor/video.dart'; -import '../utils.dart'; -import '../widgets/video_app.dart'; -import '../widgets/youtube_video_app.dart'; +import '../../../models/config/editor/video/video.dart'; +import '../../utils.dart'; +import '../../widgets/video_app.dart'; +import '../../widgets/youtube_video_app.dart'; class QuillEditorVideoEmbedBuilder extends EmbedBuilder { const QuillEditorVideoEmbedBuilder({ diff --git a/flutter_quill_extensions/lib/presentation/embeds/editor/video/video_web.dart b/flutter_quill_extensions/lib/presentation/embeds/editor/video/video_web.dart new file mode 100644 index 00000000..4bff6a01 --- /dev/null +++ b/flutter_quill_extensions/lib/presentation/embeds/editor/video/video_web.dart @@ -0,0 +1,57 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_quill/flutter_quill.dart'; +import 'package:universal_html/html.dart' as html; +import 'package:youtube_player_flutter/youtube_player_flutter.dart' + show YoutubePlayer; + +import '../../../models/config/editor/video/video_web.dart'; +import '../../utils.dart'; +import '../shims/dart_ui_fake.dart' + if (dart.library.html) 'shims/dart_ui_real.dart' as ui; + +class QuillEditorWebVideoEmbedBuilder extends EmbedBuilder { + const QuillEditorWebVideoEmbedBuilder({ + required this.configurations, + }); + + final QuillEditorWebVideoEmbedConfigurations configurations; + + @override + String get key => BlockEmbed.videoType; + + @override + Widget build( + BuildContext context, + QuillController controller, + Embed node, + bool readOnly, + bool inline, + TextStyle textStyle, + ) { + var videoUrl = node.value.data; + if (isYouTubeUrl(videoUrl)) { + final youtubeID = YoutubePlayer.convertUrlToId(videoUrl); + if (youtubeID != null) { + videoUrl = 'https://www.youtube.com/embed/$youtubeID'; + } + } + + final size = MediaQuery.sizeOf(context); + + ui.PlatformViewRegistry().registerViewFactory( + videoUrl, + (id) => html.IFrameElement() + ..width = size.width.toString() + ..height = size.height.toString() + ..src = videoUrl + ..style.border = 'none', + ); + + return SizedBox( + height: 500, + child: HtmlElementView( + viewType: videoUrl, + ), + ); + } +} diff --git a/flutter_quill_extensions/lib/presentation/embeds/utils.dart b/flutter_quill_extensions/lib/presentation/embeds/utils.dart index 0d890e4e..f1331f84 100644 --- a/flutter_quill_extensions/lib/presentation/embeds/utils.dart +++ b/flutter_quill_extensions/lib/presentation/embeds/utils.dart @@ -30,7 +30,8 @@ bool isYouTubeUrl(String videoUrl) { final uri = Uri.parse(videoUrl); return uri.host == 'www.youtube.com' || uri.host == 'youtube.com' || - uri.host == 'youtu.be'; + uri.host == 'youtu.be' || + uri.host == 'www.youtu.be'; } catch (_) { return false; } diff --git a/flutter_quill_extensions/lib/presentation/embeds/widgets/image.dart b/flutter_quill_extensions/lib/presentation/embeds/widgets/image.dart index 6d00500c..e73226e2 100644 --- a/flutter_quill_extensions/lib/presentation/embeds/widgets/image.dart +++ b/flutter_quill_extensions/lib/presentation/embeds/widgets/image.dart @@ -28,31 +28,35 @@ String getImageStyleString(QuillController controller) { return s ?? ''; } -Image getQuillImageByUrl( - String imageUrl, { +Image getQuillImageByImageSource( + String imageSource, { required ImageEmbedBuilderProviderBuilder? imageProviderBuilder, required ImageErrorWidgetBuilder? imageErrorWidgetBuilder, double? width, double? height, AlignmentGeometry alignment = Alignment.center, }) { - if (isImageBase64(imageUrl)) { - return Image.memory(base64.decode(imageUrl), - width: width, height: height, alignment: alignment); + if (isImageBase64(imageSource)) { + return Image.memory( + base64.decode(imageSource), + width: width, + height: height, + alignment: alignment, + ); } if (imageProviderBuilder != null) { return Image( - image: imageProviderBuilder(imageUrl), + image: imageProviderBuilder(imageSource), width: width, height: height, alignment: alignment, errorBuilder: imageErrorWidgetBuilder, ); } - if (isHttpBasedUrl(imageUrl)) { + if (isHttpBasedUrl(imageSource)) { return Image.network( - imageUrl, + imageSource, width: width, height: height, alignment: alignment, @@ -60,7 +64,7 @@ Image getQuillImageByUrl( ); } return Image.file( - File(imageUrl), + File(imageSource), width: width, height: height, alignment: alignment, diff --git a/flutter_quill_extensions/lib/presentation/models/config/editor/image.dart b/flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart similarity index 97% rename from flutter_quill_extensions/lib/presentation/models/config/editor/image.dart rename to flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart index 31fa75ef..f33913e7 100644 --- a/flutter_quill_extensions/lib/presentation/models/config/editor/image.dart +++ b/flutter_quill_extensions/lib/presentation/models/config/editor/image/image.dart @@ -3,7 +3,7 @@ import 'dart:io' show File; import 'package:flutter_quill/extensions.dart'; import 'package:meta/meta.dart' show immutable; -import '../../../embeds/embed_types/image.dart'; +import '../../../../embeds/embed_types/image.dart'; /// [QuillEditorImageEmbedConfigurations] for desktop, mobile and /// other platforms @@ -167,8 +167,3 @@ class QuillEditorImageEmbedConfigurations { ); } } - -@immutable -class QuillEditorWebImageEmbedConfigurations { - const QuillEditorWebImageEmbedConfigurations(); -} diff --git a/flutter_quill_extensions/lib/presentation/models/config/editor/image/image_web.dart b/flutter_quill_extensions/lib/presentation/models/config/editor/image/image_web.dart new file mode 100644 index 00000000..8facc8a6 --- /dev/null +++ b/flutter_quill_extensions/lib/presentation/models/config/editor/image/image_web.dart @@ -0,0 +1,11 @@ +import 'package:flutter/widgets.dart' show BoxConstraints; +import 'package:meta/meta.dart' show immutable; + +@immutable +class QuillEditorWebImageEmbedConfigurations { + const QuillEditorWebImageEmbedConfigurations({ + this.constraints, + }); + + final BoxConstraints? constraints; +} diff --git a/flutter_quill_extensions/lib/presentation/models/config/editor/video.dart b/flutter_quill_extensions/lib/presentation/models/config/editor/video/video.dart similarity index 100% rename from flutter_quill_extensions/lib/presentation/models/config/editor/video.dart rename to flutter_quill_extensions/lib/presentation/models/config/editor/video/video.dart diff --git a/flutter_quill_extensions/lib/presentation/models/config/editor/video/video_web.dart b/flutter_quill_extensions/lib/presentation/models/config/editor/video/video_web.dart new file mode 100644 index 00000000..26d7f110 --- /dev/null +++ b/flutter_quill_extensions/lib/presentation/models/config/editor/video/video_web.dart @@ -0,0 +1,11 @@ +import 'package:flutter/widgets.dart' show BoxConstraints; +import 'package:meta/meta.dart' show immutable; + +@immutable +class QuillEditorWebVideoEmbedConfigurations { + const QuillEditorWebVideoEmbedConfigurations({ + this.constraints, + }); + + final BoxConstraints? constraints; +} diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index 3a6948f9..be42577a 100644 --- a/flutter_quill_extensions/pubspec.yaml +++ b/flutter_quill_extensions/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill_extensions description: Embed extensions for flutter_quill including image, video, formula and etc. -version: 0.6.0-dev.5 +version: 0.6.0-dev.6 homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions @@ -45,9 +45,9 @@ dependencies: # In case you are working on changes for both libraries # Comment the dependency_overrides section when publishing the package, # then uncomment it back, this will be automated later -# dependency_overrides: -# flutter_quill: -# path: ../ +dependency_overrides: + flutter_quill: + path: ../ dev_dependencies: flutter_test: diff --git a/lib/src/models/documents/nodes/node.dart b/lib/src/models/documents/nodes/node.dart index bb6a1c59..c196b47f 100644 --- a/lib/src/models/documents/nodes/node.dart +++ b/lib/src/models/documents/nodes/node.dart @@ -21,6 +21,20 @@ abstract base class Node extends LinkedListEntry { /// Current parent of this node. May be null if this node is not mounted. Container? parent; + /// The style attributes + /// Note: This is not the same as style attribute of css + /// + /// Example: + /// + /// { + /// "insert": { + /// "image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png" + /// }, + /// "attributes": { // this one + /// "width": "230", + /// "style": "display: block; margin: auto; width: 500px;" // Not this + /// } + /// }, Style get style => _style; Style _style = const Style(); diff --git a/pubspec.yaml b/pubspec.yaml index b53cd569..63bf0a6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: A rich text editor built for the modern Android, iOS, web and desktop platforms. It is the WYSIWYG editor and a Quill component for Flutter. -version: 8.2.2 +version: 8.2.3 homepage: https://1o24bbs.com/c/bulletjournal/108 repository: https://github.com/singerdmx/flutter-quill