diff --git a/example/lib/screens/quill/my_quill_editor.dart b/example/lib/screens/quill/my_quill_editor.dart index d50f75d8d..e7115bcb2 100644 --- a/example/lib/screens/quill/my_quill_editor.dart +++ b/example/lib/screens/quill/my_quill_editor.dart @@ -51,6 +51,7 @@ class MyQuillEditor extends StatelessWidget { height: 1.15, fontWeight: FontWeight.w300, ), + const HorizontalSpacing(0, 0), const VerticalSpacing(16, 0), const VerticalSpacing(0, 0), null, diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart index efac79a07..be514a815 100644 --- a/lib/flutter_quill.dart +++ b/lib/flutter_quill.dart @@ -1,5 +1,6 @@ library flutter_quill; +export 'src/common/structs/horizontal_spacing.dart'; export 'src/common/structs/image_url.dart'; export 'src/common/structs/offset_value.dart'; export 'src/common/structs/optional_size.dart'; diff --git a/lib/src/common/structs/horizontal_spacing.dart b/lib/src/common/structs/horizontal_spacing.dart new file mode 100644 index 000000000..3ed47d576 --- /dev/null +++ b/lib/src/common/structs/horizontal_spacing.dart @@ -0,0 +1,12 @@ +import 'package:flutter/foundation.dart' show immutable; + +@immutable +class HorizontalSpacing { + const HorizontalSpacing( + this.left, + this.right, + ); + + final double left; + final double right; +} diff --git a/lib/src/editor/raw_editor/raw_editor_state.dart b/lib/src/editor/raw_editor/raw_editor_state.dart index 91774bc1a..d216ff252 100644 --- a/lib/src/editor/raw_editor/raw_editor_state.dart +++ b/lib/src/editor/raw_editor/raw_editor_state.dart @@ -20,6 +20,7 @@ import 'package:flutter/services.dart' import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart' show KeyboardVisibilityController; +import '../../common/structs/horizontal_spacing.dart'; import '../../common/structs/offset_value.dart'; import '../../common/structs/vertical_spacing.dart'; import '../../common/utils/cast.dart'; @@ -1011,6 +1012,7 @@ class QuillRawEditorState extends EditorState controller: controller, textDirection: getDirectionOfNode(node), scrollBottomInset: widget.configurations.scrollBottomInset, + horizontalSpacing: _getHorizontalSpacingForBlock(node, _styles), verticalSpacing: _getVerticalSpacingForBlock(node, _styles), textSelection: controller.selection, color: widget.configurations.selectionColor, @@ -1069,7 +1071,7 @@ class QuillRawEditorState extends EditorState node, null, textLine, - 0, + _getHorizontalSpacingForLine(node, _styles), _getVerticalSpacingForLine(node, _styles), _textDirection, controller.selection, @@ -1081,6 +1083,39 @@ class QuillRawEditorState extends EditorState return editableTextLine; } + HorizontalSpacing _getHorizontalSpacingForLine( + Line line, + DefaultStyles? defaultStyles, + ) { + final attrs = line.style.attributes; + if (attrs.containsKey(Attribute.header.key)) { + int level; + if (attrs[Attribute.header.key]!.value is double) { + level = attrs[Attribute.header.key]!.value.toInt(); + } else { + level = attrs[Attribute.header.key]!.value; + } + switch (level) { + case 1: + return defaultStyles!.h1!.horizontalSpacing; + case 2: + return defaultStyles!.h2!.horizontalSpacing; + case 3: + return defaultStyles!.h3!.horizontalSpacing; + case 4: + return defaultStyles!.h4!.horizontalSpacing; + case 5: + return defaultStyles!.h5!.horizontalSpacing; + case 6: + return defaultStyles!.h6!.horizontalSpacing; + default: + throw ArgumentError('Invalid level $level'); + } + } + + return defaultStyles!.paragraph!.horizontalSpacing; + } + VerticalSpacing _getVerticalSpacingForLine( Line line, DefaultStyles? defaultStyles, @@ -1114,6 +1149,23 @@ class QuillRawEditorState extends EditorState return defaultStyles!.paragraph!.verticalSpacing; } + HorizontalSpacing _getHorizontalSpacingForBlock( + Block node, DefaultStyles? defaultStyles) { + final attrs = node.style.attributes; + if (attrs.containsKey(Attribute.blockQuote.key)) { + return defaultStyles!.quote!.horizontalSpacing; + } else if (attrs.containsKey(Attribute.codeBlock.key)) { + return defaultStyles!.code!.horizontalSpacing; + } else if (attrs.containsKey(Attribute.indent.key)) { + return defaultStyles!.indent!.horizontalSpacing; + } else if (attrs.containsKey(Attribute.list.key)) { + return defaultStyles!.lists!.horizontalSpacing; + } else if (attrs.containsKey(Attribute.align.key)) { + return defaultStyles!.align!.horizontalSpacing; + } + return const HorizontalSpacing(0, 0); + } + VerticalSpacing _getVerticalSpacingForBlock( Block node, DefaultStyles? defaultStyles) { final attrs = node.style.attributes; diff --git a/lib/src/editor/widgets/default_styles.dart b/lib/src/editor/widgets/default_styles.dart index 65af37d69..da6e0f8ac 100644 --- a/lib/src/editor/widgets/default_styles.dart +++ b/lib/src/editor/widgets/default_styles.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../common/structs/horizontal_spacing.dart'; import '../../common/structs/vertical_spacing.dart'; import '../../common/utils/platform.dart'; import '../../document/attribute.dart'; @@ -36,6 +37,7 @@ class QuillStyles extends InheritedWidget { class DefaultTextBlockStyle { const DefaultTextBlockStyle( this.style, + this.horizontalSpacing, this.verticalSpacing, this.lineSpacing, this.decoration, @@ -44,6 +46,9 @@ class DefaultTextBlockStyle { /// Base text style for a text block. final TextStyle style; + /// Horizontal spacing around a text block. + final HorizontalSpacing horizontalSpacing; + /// Vertical spacing around a text block. final VerticalSpacing verticalSpacing; @@ -151,6 +156,7 @@ class InlineCodeStyle { class DefaultListBlockStyle extends DefaultTextBlockStyle { const DefaultListBlockStyle( super.style, + super.horizontalSpacing, super.verticalSpacing, super.lineSpacing, super.decoration, @@ -238,7 +244,8 @@ class DefaultStyles { height: 1.15, decoration: TextDecoration.none, ); - const baseSpacing = VerticalSpacing(6, 0); + const baseHorizontalSpacing = HorizontalSpacing(0, 0); + const baseVerticalSpacing = VerticalSpacing(6, 0); String fontFamily; if (isAppleOS(platform: themeData.platform, supportWeb: true)) { fontFamily = 'Menlo'; @@ -262,6 +269,7 @@ class DefaultStyles { fontWeight: FontWeight.bold, decoration: TextDecoration.none, ), + baseHorizontalSpacing, const VerticalSpacing(16, 0), const VerticalSpacing(0, 0), null), @@ -274,6 +282,7 @@ class DefaultStyles { fontWeight: FontWeight.bold, decoration: TextDecoration.none, ), + baseHorizontalSpacing, const VerticalSpacing(8, 0), const VerticalSpacing(0, 0), null), @@ -286,6 +295,7 @@ class DefaultStyles { fontWeight: FontWeight.bold, decoration: TextDecoration.none, ), + baseHorizontalSpacing, const VerticalSpacing(8, 0), const VerticalSpacing(0, 0), null, @@ -299,6 +309,7 @@ class DefaultStyles { fontWeight: FontWeight.bold, decoration: TextDecoration.none, ), + baseHorizontalSpacing, const VerticalSpacing(6, 0), const VerticalSpacing(0, 0), null, @@ -312,6 +323,7 @@ class DefaultStyles { fontWeight: FontWeight.bold, decoration: TextDecoration.none, ), + baseHorizontalSpacing, const VerticalSpacing(6, 0), const VerticalSpacing(0, 0), null, @@ -325,36 +337,42 @@ class DefaultStyles { fontWeight: FontWeight.bold, decoration: TextDecoration.none, ), + baseHorizontalSpacing, const VerticalSpacing(4, 0), const VerticalSpacing(0, 0), null, ), lineHeightNormal: DefaultTextBlockStyle( baseStyle.copyWith(height: 1.15), + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, ), lineHeightTight: DefaultTextBlockStyle( baseStyle.copyWith(height: 1.30), + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, ), lineHeightOneAndHalf: DefaultTextBlockStyle( baseStyle.copyWith(height: 1.55), + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, ), lineHeightDouble: DefaultTextBlockStyle( baseStyle.copyWith(height: 2), + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, ), paragraph: DefaultTextBlockStyle( baseStyle, + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, @@ -403,19 +421,22 @@ class DefaultStyles { height: 1.5, color: Colors.grey.withOpacity(0.6), ), + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null), lists: DefaultListBlockStyle( baseStyle, - baseSpacing, + baseHorizontalSpacing, + baseVerticalSpacing, const VerticalSpacing(0, 6), null, null, ), quote: DefaultTextBlockStyle( TextStyle(color: baseStyle.color!.withOpacity(0.6)), - baseSpacing, + baseHorizontalSpacing, + baseVerticalSpacing, const VerticalSpacing(6, 2), BoxDecoration( border: Border( @@ -430,7 +451,8 @@ class DefaultStyles { fontSize: 13, height: 1.15, ), - baseSpacing, + baseHorizontalSpacing, + baseVerticalSpacing, const VerticalSpacing(0, 0), BoxDecoration( color: Colors.grey.shade50, @@ -438,18 +460,21 @@ class DefaultStyles { )), indent: DefaultTextBlockStyle( baseStyle, - baseSpacing, + baseHorizontalSpacing, + baseVerticalSpacing, const VerticalSpacing(0, 6), null, ), align: DefaultTextBlockStyle( baseStyle, + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, ), leading: DefaultTextBlockStyle( baseStyle, + baseHorizontalSpacing, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null, diff --git a/lib/src/editor/widgets/text/text_block.dart b/lib/src/editor/widgets/text/text_block.dart index 5ebb361f0..406561a92 100644 --- a/lib/src/editor/widgets/text/text_block.dart +++ b/lib/src/editor/widgets/text/text_block.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import '../../../common/structs/horizontal_spacing.dart'; import '../../../common/structs/vertical_spacing.dart'; import '../../../common/utils/font.dart'; import '../../../controller/quill_controller.dart'; @@ -61,6 +62,7 @@ class EditableTextBlock extends StatelessWidget { required this.controller, required this.textDirection, required this.scrollBottomInset, + required this.horizontalSpacing, required this.verticalSpacing, required this.textSelection, required this.color, @@ -86,6 +88,7 @@ class EditableTextBlock extends StatelessWidget { final QuillController controller; final TextDirection textDirection; final double scrollBottomInset; + final HorizontalSpacing horizontalSpacing; final VerticalSpacing verticalSpacing; final TextSelection textSelection; final Color color; @@ -113,7 +116,8 @@ class EditableTextBlock extends StatelessWidget { return _EditableBlock( block: block, textDirection: textDirection, - padding: verticalSpacing, + horizontalSpacing: horizontalSpacing, + verticalSpacing: verticalSpacing, scrollBottomInset: scrollBottomInset, decoration: _getDecorationForBlock(block, defaultStyles) ?? const BoxDecoration(), @@ -304,7 +308,7 @@ class EditableTextBlock extends StatelessWidget { return null; } - double _getIndentWidth(BuildContext context, int count) { + HorizontalSpacing _getIndentWidth(BuildContext context, int count) { final defaultStyles = QuillStyles.getStyles(context, false)!; final fontSize = defaultStyles.paragraph?.style.fontSize ?? 16; final attrs = block.style.attributes; @@ -316,7 +320,7 @@ class EditableTextBlock extends StatelessWidget { } if (attrs.containsKey(Attribute.blockQuote.key)) { - return fontSize + extraIndent; + return HorizontalSpacing(fontSize + extraIndent, 0); } var baseIndent = 0.0; @@ -330,7 +334,7 @@ class EditableTextBlock extends StatelessWidget { } } - return baseIndent + extraIndent; + return HorizontalSpacing(baseIndent + extraIndent, 0); } VerticalSpacing _getSpacingForLine( @@ -715,7 +719,8 @@ class _EditableBlock extends MultiChildRenderObjectWidget { const _EditableBlock( {required this.block, required this.textDirection, - required this.padding, + required this.horizontalSpacing, + required this.verticalSpacing, required this.scrollBottomInset, required this.decoration, required this.contentPadding, @@ -723,13 +728,17 @@ class _EditableBlock extends MultiChildRenderObjectWidget { final Block block; final TextDirection textDirection; - final VerticalSpacing padding; + final HorizontalSpacing horizontalSpacing; + final VerticalSpacing verticalSpacing; final double scrollBottomInset; final Decoration decoration; final EdgeInsets? contentPadding; - EdgeInsets get _padding => - EdgeInsets.only(top: padding.top, bottom: padding.bottom); + EdgeInsets get _padding => EdgeInsets.only( + left: horizontalSpacing.left, + right: horizontalSpacing.right, + top: verticalSpacing.top, + bottom: verticalSpacing.bottom); EdgeInsets get _contentPadding => contentPadding ?? EdgeInsets.zero; diff --git a/lib/src/editor/widgets/text/text_line.dart b/lib/src/editor/widgets/text/text_line.dart index 7cd8061be..ca3581284 100644 --- a/lib/src/editor/widgets/text/text_line.dart +++ b/lib/src/editor/widgets/text/text_line.dart @@ -602,7 +602,7 @@ class EditableTextLine extends RenderObjectWidget { this.line, this.leading, this.body, - this.indentWidth, + this.horizontalSpacing, this.verticalSpacing, this.textDirection, this.textSelection, @@ -616,7 +616,7 @@ class EditableTextLine extends RenderObjectWidget { final Line line; final Widget? leading; final Widget body; - final double indentWidth; + final HorizontalSpacing horizontalSpacing; final VerticalSpacing verticalSpacing; final TextDirection textDirection; final TextSelection textSelection; @@ -666,7 +666,8 @@ class EditableTextLine extends RenderObjectWidget { EdgeInsetsGeometry _getPadding() { return EdgeInsetsDirectional.only( - start: indentWidth, + start: horizontalSpacing.left, + end: horizontalSpacing.right, top: verticalSpacing.top, bottom: verticalSpacing.bottom); }