diff --git a/example/lib/presentation/quill/samples/quill_images_sample.dart b/example/lib/presentation/quill/samples/quill_images_sample.dart index 9dadcd2c..0395af1e 100644 --- a/example/lib/presentation/quill/samples/quill_images_sample.dart +++ b/example/lib/presentation/quill/samples/quill_images_sample.dart @@ -5,11 +5,7 @@ final quillImagesSample = [ {'insert': '\n'}, { 'insert': {'image': Assets.images.screenshot1.path}, - 'attributes': { - 'width': '200', - 'height': '500', - 'style': 'width:500px; height:350px; margin: 20px;' - } + 'attributes': {'style': 'width: 40vh; height:350px; margin: 20px;'} }, {'insert': '\n'}, {'insert': 'Here is a network image: \n'}, diff --git a/flutter_quill_extensions/CHANGELOG.md b/flutter_quill_extensions/CHANGELOG.md index 7132f072..02eb65c6 100644 --- a/flutter_quill_extensions/CHANGELOG.md +++ b/flutter_quill_extensions/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. * Fix a bug in the example when inserting an image from url * Flutter Quill Extensions: * Add support for copying the image to the system cliboard + * Add support for other CSS units like (vh, vw) and more ## 9.0.0-dev-2 * An attemp to fix CI automated publishing diff --git a/flutter_quill_extensions/lib/embeds/image/editor/image_embed.dart b/flutter_quill_extensions/lib/embeds/image/editor/image_embed.dart index 12f8f28a..ee0a8f9a 100644 --- a/flutter_quill_extensions/lib/embeds/image/editor/image_embed.dart +++ b/flutter_quill_extensions/lib/embeds/image/editor/image_embed.dart @@ -32,7 +32,10 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder { // assert(!kIsWeb, 'Please provide image EmbedBuilder for Web'); final imageSource = standardizeImageUrl(node.value.data); - final ((imageSize), margin, alignment) = getElementAttributes(node); + final ((imageSize), margin, alignment) = getElementAttributes( + node, + context, + ); final width = imageSize.width; final height = imageSize.height; diff --git a/flutter_quill_extensions/lib/embeds/video/editor/video_embed.dart b/flutter_quill_extensions/lib/embeds/video/editor/video_embed.dart index 831da538..fd1cd8fc 100644 --- a/flutter_quill_extensions/lib/embeds/video/editor/video_embed.dart +++ b/flutter_quill_extensions/lib/embeds/video/editor/video_embed.dart @@ -37,7 +37,10 @@ class QuillEditorVideoEmbedBuilder extends EmbedBuilder { readOnly: readOnly, ); } - final ((elementSize), margin, alignment) = getElementAttributes(node); + final ((elementSize), margin, alignment) = getElementAttributes( + node, + context, + ); final width = elementSize.width; final height = elementSize.height; diff --git a/flutter_quill_extensions/lib/utils/element_utils/element_shared_utils.dart b/flutter_quill_extensions/lib/utils/element_utils/element_shared_utils.dart index 927a97e1..8632fba0 100644 --- a/flutter_quill_extensions/lib/utils/element_utils/element_shared_utils.dart +++ b/flutter_quill_extensions/lib/utils/element_utils/element_shared_utils.dart @@ -1,3 +1,5 @@ +import 'package:flutter/widgets.dart' show BuildContext, MediaQuery; + Map parseCssString(String cssString) { final result = {}; final declarations = cssString.split(';'); @@ -14,16 +16,71 @@ Map parseCssString(String cssString) { return result; } -double? parseCssPropertyAsDouble(String value) { +enum _CssUnit { + px('px'), + percentage('%'), + viewportWidth('vw'), + viewportHeight('vh'), + em('em'), + rem('rem'), + invalid('invalid'); + + const _CssUnit(this.cssName); + + final String cssName; +} + +double? parseCssPropertyAsDouble( + String value, { + required BuildContext context, +}) { if (value.trim().isEmpty) { return null; } - final list = [ - 'px', - // '%', 'vw', 'vh', 'em', 'rem' - ]; - for (final element in list) { - value = value.replaceFirst(element, ''); + + // Try to parse it in case it's a valid double already + var doubleValue = double.tryParse(value); + + if (doubleValue != null) { + return doubleValue; + } + + // If not then if it's a css numberic value then we will try to parse it + final unit = _CssUnit.values + .where((element) => value.endsWith(element.cssName)) + .firstOrNull; + if (unit == null) { + return null; + } + value = value.replaceFirst(unit.cssName, ''); + doubleValue = double.tryParse(value); + if (doubleValue != null) { + switch (unit) { + case _CssUnit.px: + // Do nothing + break; + case _CssUnit.percentage: + // Not supported yet + doubleValue = null; + break; + case _CssUnit.viewportWidth: + doubleValue = (doubleValue / 100) * MediaQuery.sizeOf(context).width; + break; + case _CssUnit.viewportHeight: + doubleValue = (doubleValue / 100) * MediaQuery.sizeOf(context).height; + break; + case _CssUnit.em: + doubleValue = MediaQuery.textScalerOf(context).scale(doubleValue); + break; + case _CssUnit.rem: + // Not fully supported yet + doubleValue = MediaQuery.textScalerOf(context).scale(doubleValue); + break; + case _CssUnit.invalid: + // Ignore + doubleValue = null; + break; + } } - return double.tryParse(value); + return doubleValue; } diff --git a/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart b/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart index 24bd166e..64db01ae 100644 --- a/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart +++ b/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart @@ -1,5 +1,5 @@ import 'package:flutter/foundation.dart' show immutable; -import 'package:flutter/widgets.dart' show Alignment; +import 'package:flutter/widgets.dart' show Alignment, BuildContext; import 'package:flutter_quill/extensions.dart'; import 'package:flutter_quill/flutter_quill.dart' show Attribute, Node; @@ -18,15 +18,20 @@ enum ExtraElementProperties { Alignment alignment, ) getElementAttributes( Node node, + BuildContext context, ) { var elementSize = const ElementSize(null, null); var elementAlignment = Alignment.center; double? elementMargin; final heightValue = parseCssPropertyAsDouble( - node.style.attributes[Attribute.height.key]?.value.toString() ?? ''); + node.style.attributes[Attribute.height.key]?.value.toString() ?? '', + context: context, + ); final widthValue = parseCssPropertyAsDouble( - node.style.attributes[Attribute.width.key]?.value.toString() ?? ''); + node.style.attributes[Attribute.width.key]?.value.toString() ?? '', + context: context, + ); if (heightValue != null) { elementSize = elementSize.copyWith( @@ -47,10 +52,14 @@ enum ExtraElementProperties { final cssAttrs = parseCssString(cssStyle.value.toString()); // todo: This could be improved much better - final cssHeightValue = - parseCssPropertyAsDouble((cssAttrs[Attribute.height.key]) ?? ''); - final cssWidthValue = - parseCssPropertyAsDouble((cssAttrs[Attribute.width.key]) ?? ''); + final cssHeightValue = parseCssPropertyAsDouble( + (cssAttrs[Attribute.height.key]) ?? '', + context: context, + ); + final cssWidthValue = parseCssPropertyAsDouble( + (cssAttrs[Attribute.width.key]) ?? '', + context: context, + ); // cssHeightValue != null && elementSize.height == null if (cssHeightValue != null) { diff --git a/flutter_quill_extensions/lib/utils/utils.dart b/flutter_quill_extensions/lib/utils/utils.dart index b5497033..fc620e9b 100644 --- a/flutter_quill_extensions/lib/utils/utils.dart +++ b/flutter_quill_extensions/lib/utils/utils.dart @@ -58,8 +58,13 @@ Future convertImageToUint8List(String image) async { } return null; } - final file = XFile(image); - return await file.readAsBytes(); + // TODO: Add support for all image providers like AssetImage + try { + final file = XFile(image); + return await file.readAsBytes(); + } catch (e) { + return null; + } } Future saveImage({