From c936decb0c94a6281706249a2498a5a701b50fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20Deniel?= Date: Tue, 22 Feb 2022 15:48:30 +0100 Subject: [PATCH] Added leadingBuilder for improved customization. --- lib/flutter_quill.dart | 1 + lib/src/widgets/delegate.dart | 12 +++ lib/src/widgets/editor.dart | 4 + .../leading/default_leading_builder.dart | 72 ++++++++++++++++++ lib/src/widgets/raw_editor.dart | 6 ++ lib/src/widgets/text_block.dart | 74 +++---------------- 6 files changed, 107 insertions(+), 62 deletions(-) create mode 100644 lib/src/widgets/leading/default_leading_builder.dart diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart index faf55b3e..a53dcc0a 100644 --- a/lib/flutter_quill.dart +++ b/lib/flutter_quill.dart @@ -11,6 +11,7 @@ export 'src/models/themes/quill_icon_theme.dart'; export 'src/widgets/controller.dart'; export 'src/widgets/default_styles.dart'; export 'src/widgets/editor.dart'; +export 'src/widgets/leading/default_leading_builder.dart'; export 'src/widgets/link.dart' show LinkActionPickerDelegate, LinkMenuAction; export 'src/widgets/style_widgets/style_widgets.dart'; export 'src/widgets/toolbar.dart'; diff --git a/lib/src/widgets/delegate.dart b/lib/src/widgets/delegate.dart index 21961871..e33910a0 100644 --- a/lib/src/widgets/delegate.dart +++ b/lib/src/widgets/delegate.dart @@ -3,11 +3,23 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import '../../flutter_quill.dart'; +import '../models/documents/nodes/line.dart'; import 'text_selection.dart'; typedef EmbedBuilder = Widget Function(BuildContext context, QuillController controller, Embed node, bool readOnly); +typedef LeadingBuilder = Widget? Function( + BuildContext context, + Line line, + int index, + Map indentLevelCounts, + int count, + CheckboxTapCallback onCheckboxTap, + bool readOnly); + +typedef CheckboxTapCallback = void Function(int index, bool checked); + typedef CustomStyleBuilder = TextStyle Function(Attribute attribute); /// Delegate interface for the [EditorTextSelectionGestureDetectorBuilder]. diff --git a/lib/src/widgets/editor.dart b/lib/src/widgets/editor.dart index 5cbb6e4c..0af1201e 100644 --- a/lib/src/widgets/editor.dart +++ b/lib/src/widgets/editor.dart @@ -20,6 +20,7 @@ import 'default_styles.dart'; import 'delegate.dart'; import 'embeds/default_embed_builder.dart'; import 'float_cursor.dart'; +import 'leading/default_leading_builder.dart'; import 'link.dart'; import 'raw_editor.dart'; import 'text_selection.dart'; @@ -168,6 +169,7 @@ class QuillEditor extends StatefulWidget { this.onSingleLongTapMoveUpdate, this.onSingleLongTapEnd, this.embedBuilder = defaultEmbedBuilder, + this.leadingBuilder = defaultLeadingBuilder, this.linkActionPickerDelegate = defaultLinkActionPickerDelegate, this.customStyleBuilder, this.locale, @@ -339,6 +341,7 @@ class QuillEditor extends StatefulWidget { onSingleLongTapEnd; final EmbedBuilder embedBuilder; + final LeadingBuilder leadingBuilder; final CustomStyleBuilder? customStyleBuilder; /// The locale to use for the editor toolbar, defaults to system locale @@ -453,6 +456,7 @@ class QuillEditorState extends State enableInteractiveSelection: widget.enableInteractiveSelection, scrollPhysics: widget.scrollPhysics, embedBuilder: widget.embedBuilder, + leadingBuilder: widget.leadingBuilder, linkActionPickerDelegate: widget.linkActionPickerDelegate, customStyleBuilder: widget.customStyleBuilder, floatingCursorDisabled: widget.floatingCursorDisabled, diff --git a/lib/src/widgets/leading/default_leading_builder.dart b/lib/src/widgets/leading/default_leading_builder.dart new file mode 100644 index 00000000..3510d20e --- /dev/null +++ b/lib/src/widgets/leading/default_leading_builder.dart @@ -0,0 +1,72 @@ +import 'package:flutter/widgets.dart'; +import '../../models/documents/attribute.dart'; +import '../../models/documents/nodes/line.dart' as line; +import '../default_styles.dart'; +import '../delegate.dart'; +import '../style_widgets/style_widgets.dart'; + +Widget? defaultLeadingBuilder( + BuildContext context, + line.Line line, + int index, + Map indentLevelCounts, + int count, + CheckboxTapCallback onCheckboxTap, + bool readOnly) { + final defaultStyles = QuillStyles.getStyles(context, false); + final attrs = line.style.attributes; + if (attrs[Attribute.list.key] == Attribute.ol) { + return QuillNumberPoint( + index: index, + indentLevelCounts: indentLevelCounts, + count: count, + style: defaultStyles!.leading!.style, + attrs: attrs, + width: 32, + padding: 8, + ); + } + + if (attrs[Attribute.list.key] == Attribute.ul) { + return QuillBulletPoint( + style: + defaultStyles!.leading!.style.copyWith(fontWeight: FontWeight.bold), + width: 32, + ); + } + + if (attrs[Attribute.list.key] == Attribute.checked) { + return CheckboxPoint( + size: 14, + value: true, + enabled: !readOnly, + onChanged: (checked) => onCheckboxTap(line.documentOffset, checked), + uiBuilder: defaultStyles?.lists?.checkboxUIBuilder, + ); + } + + if (attrs[Attribute.list.key] == Attribute.unchecked) { + return CheckboxPoint( + size: 14, + value: false, + enabled: !readOnly, + onChanged: (checked) => onCheckboxTap(line.documentOffset, checked), + uiBuilder: defaultStyles?.lists?.checkboxUIBuilder, + ); + } + + if (attrs.containsKey(Attribute.codeBlock.key)) { + return QuillNumberPoint( + index: index, + indentLevelCounts: indentLevelCounts, + count: count, + style: defaultStyles!.code!.style + .copyWith(color: defaultStyles.code!.style.color!.withOpacity(0.4)), + width: 32, + attrs: attrs, + padding: 16, + withDot: false, + ); + } + return null; +} diff --git a/lib/src/widgets/raw_editor.dart b/lib/src/widgets/raw_editor.dart index 05cd99ef..05138745 100644 --- a/lib/src/widgets/raw_editor.dart +++ b/lib/src/widgets/raw_editor.dart @@ -29,6 +29,7 @@ import 'editor.dart'; import 'embeds/default_embed_builder.dart'; import 'embeds/image.dart'; import 'keyboard_listener.dart'; +import 'leading/default_leading_builder.dart'; import 'link.dart'; import 'proxy.dart'; import 'quill_single_child_scroll_view.dart'; @@ -72,6 +73,7 @@ class RawEditor extends StatefulWidget { this.enableInteractiveSelection = true, this.scrollPhysics, this.embedBuilder = defaultEmbedBuilder, + this.leadingBuilder = defaultLeadingBuilder, this.linkActionPickerDelegate = defaultLinkActionPickerDelegate, this.customStyleBuilder, this.floatingCursorDisabled = false}) @@ -223,6 +225,9 @@ class RawEditor extends StatefulWidget { /// Builder function for embeddable objects. final EmbedBuilder embedBuilder; + + /// Builder function for leading objects. + final LeadingBuilder leadingBuilder; final LinkActionPickerDelegate linkActionPickerDelegate; final CustomStyleBuilder? customStyleBuilder; final bool floatingCursorDisabled; @@ -456,6 +461,7 @@ class RawEditorState extends EditorState ? const EdgeInsets.all(16) : null, embedBuilder: widget.embedBuilder, + leadingBuilder: widget.leadingBuilder, linkActionPicker: _linkActionPicker, onLaunchUrl: widget.onLaunchUrl, cursorCont: _cursorCont, diff --git a/lib/src/widgets/text_block.dart b/lib/src/widgets/text_block.dart index 26305179..105a0979 100644 --- a/lib/src/widgets/text_block.dart +++ b/lib/src/widgets/text_block.dart @@ -59,6 +59,7 @@ class EditableTextBlock extends StatelessWidget { required this.hasFocus, required this.contentPadding, required this.embedBuilder, + required this.leadingBuilder, required this.linkActionPicker, required this.cursorCont, required this.indentLevelCounts, @@ -80,12 +81,13 @@ class EditableTextBlock extends StatelessWidget { final bool hasFocus; final EdgeInsets? contentPadding; final EmbedBuilder embedBuilder; + final LeadingBuilder leadingBuilder; final LinkActionPicker linkActionPicker; final ValueChanged? onLaunchUrl; final CustomStyleBuilder? customStyleBuilder; final CursorCont cursorCont; final Map indentLevelCounts; - final Function(int, bool) onCheckboxTap; + final CheckboxTapCallback onCheckboxTap; final bool readOnly; @override @@ -126,7 +128,15 @@ class EditableTextBlock extends StatelessWidget { index++; final editableTextLine = EditableTextLine( line, - _buildLeading(context, line, index, indentLevelCounts, count), + leadingBuilder( + context, + line, + index, + indentLevelCounts, + count, + onCheckboxTap, + readOnly, + ), TextLine( line: line, textDirection: textDirection, @@ -154,66 +164,6 @@ class EditableTextBlock extends StatelessWidget { return children.toList(growable: false); } - Widget? _buildLeading(BuildContext context, Line line, int index, - Map indentLevelCounts, int count) { - final defaultStyles = QuillStyles.getStyles(context, false); - final attrs = line.style.attributes; - if (attrs[Attribute.list.key] == Attribute.ol) { - return QuillNumberPoint( - index: index, - indentLevelCounts: indentLevelCounts, - count: count, - style: defaultStyles!.leading!.style, - attrs: attrs, - width: 32, - padding: 8, - ); - } - - if (attrs[Attribute.list.key] == Attribute.ul) { - return QuillBulletPoint( - style: - defaultStyles!.leading!.style.copyWith(fontWeight: FontWeight.bold), - width: 32, - ); - } - - if (attrs[Attribute.list.key] == Attribute.checked) { - return CheckboxPoint( - size: 14, - value: true, - enabled: !readOnly, - onChanged: (checked) => onCheckboxTap(line.documentOffset, checked), - uiBuilder: defaultStyles?.lists?.checkboxUIBuilder, - ); - } - - if (attrs[Attribute.list.key] == Attribute.unchecked) { - return CheckboxPoint( - size: 14, - value: false, - enabled: !readOnly, - onChanged: (checked) => onCheckboxTap(line.documentOffset, checked), - uiBuilder: defaultStyles?.lists?.checkboxUIBuilder, - ); - } - - if (attrs.containsKey(Attribute.codeBlock.key)) { - return QuillNumberPoint( - index: index, - indentLevelCounts: indentLevelCounts, - count: count, - style: defaultStyles!.code!.style - .copyWith(color: defaultStyles.code!.style.color!.withOpacity(0.4)), - width: 32, - attrs: attrs, - padding: 16, - withDot: false, - ); - } - return null; - } - double _getIndentWidth() { final attrs = block.style.attributes;