From 917adb2d1feae6bbb0ecb561c50dda572b5eb56b Mon Sep 17 00:00:00 2001 From: jiangchong Date: Sat, 29 Apr 2023 01:45:48 +0800 Subject: [PATCH] add custom recognizer --- lib/src/widgets/delegate.dart | 2 ++ lib/src/widgets/editor.dart | 3 +++ lib/src/widgets/raw_editor.dart | 3 +++ lib/src/widgets/text_line.dart | 42 +++++++++++++++++++++++++-------- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/src/widgets/delegate.dart b/lib/src/widgets/delegate.dart index fa5dbe1f..a5b842a5 100644 --- a/lib/src/widgets/delegate.dart +++ b/lib/src/widgets/delegate.dart @@ -14,6 +14,8 @@ typedef EmbedsBuilder = EmbedBuilder Function(Embed node); typedef CustomStyleBuilder = TextStyle Function(Attribute attribute); +typedef CustomRecognizerBuilder = GestureRecognizer? Function(Attribute attribute); + /// Delegate interface for the [EditorTextSelectionGestureDetectorBuilder]. /// /// The interface is usually implemented by textfield implementations wrapping diff --git a/lib/src/widgets/editor.dart b/lib/src/widgets/editor.dart index 1c360ead..906b67fb 100644 --- a/lib/src/widgets/editor.dart +++ b/lib/src/widgets/editor.dart @@ -176,6 +176,7 @@ class QuillEditor extends StatefulWidget { this.unknownEmbedBuilder, this.linkActionPickerDelegate = defaultLinkActionPickerDelegate, this.customStyleBuilder, + this.customRecognizerBuilder, this.locale, this.floatingCursorDisabled = false, this.textSelectionControls, @@ -372,6 +373,7 @@ class QuillEditor extends StatefulWidget { final Iterable? embedBuilders; final EmbedBuilder? unknownEmbedBuilder; final CustomStyleBuilder? customStyleBuilder; + final CustomRecognizerBuilder? customRecognizerBuilder; /// The locale to use for the editor toolbar, defaults to system locale /// More https://github.com/singerdmx/flutter-quill#translation @@ -518,6 +520,7 @@ class QuillEditorState extends State embedBuilder: _getEmbedBuilder, linkActionPickerDelegate: widget.linkActionPickerDelegate, customStyleBuilder: widget.customStyleBuilder, + customRecognizerBuilder: widget.customRecognizerBuilder, floatingCursorDisabled: widget.floatingCursorDisabled, onImagePaste: widget.onImagePaste, customShortcuts: widget.customShortcuts, diff --git a/lib/src/widgets/raw_editor.dart b/lib/src/widgets/raw_editor.dart index 4cbf4193..89831d96 100644 --- a/lib/src/widgets/raw_editor.dart +++ b/lib/src/widgets/raw_editor.dart @@ -79,6 +79,7 @@ class RawEditor extends StatefulWidget { this.scrollPhysics, this.linkActionPickerDelegate = defaultLinkActionPickerDelegate, this.customStyleBuilder, + this.customRecognizerBuilder, this.floatingCursorDisabled = false, this.onImagePaste, this.customLinkPrefixes = const [], @@ -262,6 +263,7 @@ class RawEditor extends StatefulWidget { final EmbedsBuilder embedBuilder; final LinkActionPickerDelegate linkActionPickerDelegate; final CustomStyleBuilder? customStyleBuilder; + final CustomRecognizerBuilder? customRecognizerBuilder; final bool floatingCursorDisabled; final List customLinkPrefixes; @@ -925,6 +927,7 @@ class RawEditorState extends EditorState textDirection: _textDirection, embedBuilder: widget.embedBuilder, customStyleBuilder: widget.customStyleBuilder, + customRecognizerBuilder: widget.customRecognizerBuilder, styles: _styles!, readOnly: widget.readOnly, controller: controller, diff --git a/lib/src/widgets/text_line.dart b/lib/src/widgets/text_line.dart index 86c35da8..6eb48899 100644 --- a/lib/src/widgets/text_line.dart +++ b/lib/src/widgets/text_line.dart @@ -41,6 +41,7 @@ class TextLine extends StatefulWidget { required this.linkActionPicker, this.textDirection, this.customStyleBuilder, + this.customRecognizerBuilder, this.customLinkPrefixes = const [], Key? key, }) : super(key: key); @@ -52,6 +53,7 @@ class TextLine extends StatefulWidget { final bool readOnly; final QuillController controller; final CustomStyleBuilder? customStyleBuilder; + final CustomRecognizerBuilder? customRecognizerBuilder; final ValueChanged? onLaunchUrl; final LinkActionPicker linkActionPicker; final List customLinkPrefixes; @@ -313,12 +315,14 @@ class _TextLineState extends State { final isLink = nodeStyle.containsKey(Attribute.link.key) && nodeStyle.attributes[Attribute.link.key]!.value != null; + final GestureRecognizer? recognizer = _getRecognizer(node, isLink); + return TextSpan( text: textNode.value, style: _getInlineTextStyle( textNode, defaultStyles, nodeStyle, lineStyle, isLink), - recognizer: isLink && canLaunchLinks ? _getRecognizer(node) : null, - mouseCursor: isLink && canLaunchLinks ? SystemMouseCursors.click : null, + recognizer: recognizer, + mouseCursor: (recognizer != null) ? SystemMouseCursors.click : null, ); } @@ -406,19 +410,37 @@ class _TextLineState extends State { return res; } - GestureRecognizer _getRecognizer(Node segment) { + GestureRecognizer? _getRecognizer(Node segment, bool isLink) { if (_linkRecognizers.containsKey(segment)) { return _linkRecognizers[segment]!; } - if (isDesktop() || widget.readOnly) { - _linkRecognizers[segment] = TapGestureRecognizer() - ..onTap = () => _tapNodeLink(segment); - } else { - _linkRecognizers[segment] = LongPressGestureRecognizer() - ..onLongPress = () => _longPressLink(segment); + if (widget.customRecognizerBuilder != null) { + final textNode = segment as leaf.Text; + final nodeStyle = textNode.style; + + for (String key in nodeStyle.attributes.keys) { + final attr = nodeStyle.attributes[key]; + if (attr != null) { + GestureRecognizer? recognizer = widget.customRecognizerBuilder!.call(attr); + if (recognizer != null) { + _linkRecognizers[segment] = recognizer!; + return recognizer; + } + } + } + } + + if (isLink && canLaunchLinks) { + if (isDesktop() || widget.readOnly) { + _linkRecognizers[segment] = TapGestureRecognizer() + ..onTap = () => _tapNodeLink(segment); + } else { + _linkRecognizers[segment] = LongPressGestureRecognizer() + ..onLongPress = () => _longPressLink(segment); + } } - return _linkRecognizers[segment]!; + return _linkRecognizers[segment]; } Future _launchUrl(String url) async {