diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart index acfb7f7e..a2719729 100644 --- a/lib/flutter_quill.dart +++ b/lib/flutter_quill.dart @@ -25,8 +25,7 @@ export 'src/utils/embeds.dart'; export 'src/widgets/editor/editor.dart'; export 'src/widgets/others/cursor.dart'; export 'src/widgets/others/default_styles.dart'; -export 'src/widgets/others/link.dart' - show LinkActionPickerDelegate, LinkMenuAction; +export 'src/widgets/others/link.dart'; export 'src/widgets/quill/embeds.dart'; export 'src/widgets/quill/quill_controller.dart'; export 'src/widgets/raw_editor/raw_editor.dart'; diff --git a/lib/src/widgets/others/link.dart b/lib/src/widgets/others/link.dart index 93d8c685..b94b6993 100644 --- a/lib/src/widgets/others/link.dart +++ b/lib/src/widgets/others/link.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import '../../l10n/extensions/localizations.dart'; import '../../models/documents/attribute.dart'; import '../../models/documents/nodes/node.dart'; +import '../../widgets/quill/quill_controller.dart'; const linkPrefixes = [ 'mailto:', // email @@ -89,6 +90,63 @@ TextRange getLinkRange(Node node) { return TextRange(start: start, end: start + length); } +/// Contains information about link and text. +class QuillTextLink { + QuillTextLink( + this.text, + this.link, + ); + + factory QuillTextLink.prepare(QuillController controller) { + final link = _getLinkAttributeValue(controller); + final index = controller.selection.start; + + String? text; + if (link != null) { + // text should be the link's corresponding text, not selection + final leaf = controller.document.querySegmentLeafNode(index).leaf; + if (leaf != null) { + text = leaf.toPlainText(); + } + } + + final len = controller.selection.end - index; + text ??= len == 0 ? '' : controller.document.getPlainText(index, len); + + return QuillTextLink(text, link); + } + + final String text; + final String? link; + + void submit(QuillController controller) { + var index = controller.selection.start; + var length = controller.selection.end - index; + final linkValue = _getLinkAttributeValue(controller); + + if (linkValue != null) { + // text should be the link's corresponding text, not selection + final leaf = controller.document.querySegmentLeafNode(index).leaf; + if (leaf != null) { + final range = getLinkRange(leaf); + index = range.start; + length = range.end - range.start; + } + } + controller + ..replaceText(index, length, text, null) + ..formatText(index, text.length, LinkAttribute(link)); + } + + static String? _getLinkAttributeValue(QuillController controller) { + return controller.getSelectionStyle().attributes[Attribute.link.key]?.value; + } + + static bool isSelected(QuillController controller) { + return _getLinkAttributeValue(controller) != null; + } +} + Future _showCupertinoLinkMenu( BuildContext context, String link) async { final result = await showCupertinoModalPopup( diff --git a/lib/src/widgets/quill/text_line.dart b/lib/src/widgets/quill/text_line.dart index c3dbb146..e26e5575 100644 --- a/lib/src/widgets/quill/text_line.dart +++ b/lib/src/widgets/quill/text_line.dart @@ -17,7 +17,6 @@ import '../../utils/platform.dart'; import '../others/box.dart'; import '../others/delegate.dart'; import '../others/keyboard_listener.dart'; -import '../others/link.dart'; import '../others/proxy.dart'; import '../others/text_selection.dart'; diff --git a/lib/src/widgets/raw_editor/raw_editor_actions.dart b/lib/src/widgets/raw_editor/raw_editor_actions.dart index eaa14635..82645ac1 100644 --- a/lib/src/widgets/raw_editor/raw_editor_actions.dart +++ b/lib/src/widgets/raw_editor/raw_editor_actions.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import '../../../translations.dart'; import '../../models/documents/attribute.dart'; import '../editor/editor.dart'; +import '../others/link.dart'; import '../toolbar/buttons/link_style2_button.dart'; import '../toolbar/buttons/search/search_dialog.dart'; import 'raw_editor_state.dart'; diff --git a/lib/src/widgets/toolbar/buttons/link_style2_button.dart b/lib/src/widgets/toolbar/buttons/link_style2_button.dart index bdc4388d..42d04cac 100644 --- a/lib/src/widgets/toolbar/buttons/link_style2_button.dart +++ b/lib/src/widgets/toolbar/buttons/link_style2_button.dart @@ -7,7 +7,6 @@ import '../../../../extensions.dart' import '../../../extensions/quill_configurations_ext.dart'; import '../../../l10n/extensions/localizations.dart'; import '../../../l10n/widgets/localizations.dart'; -import '../../../models/documents/attribute.dart'; import '../../../models/themes/quill_dialog_theme.dart'; import '../../../models/themes/quill_icon_theme.dart'; import '../../others/link.dart'; @@ -134,7 +133,7 @@ class _QuillToolbarLinkStyleButton2State ), ); } - final isToggled = _getLinkAttributeValue() != null; + final isToggled = QuillTextLink.isSelected(controller); return QuillToolbarIconButton( tooltip: tooltip, icon: Icon( @@ -179,13 +178,6 @@ class _QuillToolbarLinkStyleButton2State } } - String? _getLinkAttributeValue() { - return widget.controller - .getSelectionStyle() - .attributes[Attribute.link.key] - ?.value; - } - void _didChangeSelection() { setState(() {}); } @@ -428,54 +420,3 @@ class _LinkStyleDialogState extends State { void _removeLink() => Navigator.pop(context, QuillTextLink(_text.trim(), null)); } - -/// Contains information about text URL. -class QuillTextLink { - QuillTextLink( - this.text, - this.link, - ); - - final String text; - final String? link; - - static QuillTextLink prepare(QuillController controller) { - final link = - controller.getSelectionStyle().attributes[Attribute.link.key]?.value; - final index = controller.selection.start; - - String? text; - if (link != null) { - // text should be the link's corresponding text, not selection - final leaf = controller.document.querySegmentLeafNode(index).leaf; - if (leaf != null) { - text = leaf.toPlainText(); - } - } - - final len = controller.selection.end - index; - text ??= len == 0 ? '' : controller.document.getPlainText(index, len); - - return QuillTextLink(text, link); - } - - void submit(QuillController controller) { - var index = controller.selection.start; - var length = controller.selection.end - index; - final linkValue = - controller.getSelectionStyle().attributes[Attribute.link.key]?.value; - - if (linkValue != null) { - // text should be the link's corresponding text, not selection - final leaf = controller.document.querySegmentLeafNode(index).leaf; - if (leaf != null) { - final range = getLinkRange(leaf); - index = range.start; - length = range.end - range.start; - } - } - controller - ..replaceText(index, length, text, null) - ..formatText(index, text.length, LinkAttribute(link)); - } -} diff --git a/lib/src/widgets/toolbar/buttons/link_style_button.dart b/lib/src/widgets/toolbar/buttons/link_style_button.dart index 3831f8b3..5284cb68 100644 --- a/lib/src/widgets/toolbar/buttons/link_style_button.dart +++ b/lib/src/widgets/toolbar/buttons/link_style_button.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import '../../../extensions/quill_configurations_ext.dart'; import '../../../l10n/extensions/localizations.dart'; import '../../../l10n/widgets/localizations.dart'; -import '../../../models/documents/attribute.dart'; import '../../../models/rules/insert.dart'; import '../../../models/structs/link_dialog_action.dart'; import '../../../models/themes/quill_dialog_theme.dart'; @@ -77,7 +76,7 @@ class QuillToolbarLinkStyleButtonState @override Widget build(BuildContext context) { - final isToggled = _getLinkAttributeValue() != null; + final isToggled = QuillTextLink.isSelected(controller); final childBuilder = options.childBuilder ?? baseButtonExtraOptions?.childBuilder; @@ -111,64 +110,26 @@ class QuillToolbarLinkStyleButtonState } Future _openLinkDialog(BuildContext context) async { - final value = await showDialog<_TextLink>( + final initialTextLink = QuillTextLink.prepare(widget.controller); + + final textLink = await showDialog( context: context, barrierColor: dialogBarrierColor, builder: (_) { - final link = _getLinkAttributeValue(); - final index = controller.selection.start; - - String? text; - if (link != null) { - // text should be the link's corresponding text, not selection - final leaf = controller.document.querySegmentLeafNode(index).leaf; - if (leaf != null) { - text = leaf.toPlainText(); - } - } - - final len = controller.selection.end - index; - text ??= len == 0 ? '' : controller.document.getPlainText(index, len); return FlutterQuillLocalizationsWidget( child: _LinkDialog( dialogTheme: options.dialogTheme, - link: link, - text: text, + text: initialTextLink.text, + link: initialTextLink.link, linkRegExp: linkRegExp, action: options.linkDialogAction, ), ); }, ); - if (value == null) { - return; - } - _linkSubmitted(value); - } - - String? _getLinkAttributeValue() { - return controller.getSelectionStyle().attributes[Attribute.link.key]?.value; - } - - void _linkSubmitted(_TextLink value) { - var index = controller.selection.start; - var length = controller.selection.end - index; - if (_getLinkAttributeValue() != null) { - // text should be the link's corresponding text, not selection - final leaf = controller.document.querySegmentLeafNode(index).leaf; - if (leaf != null) { - final range = getLinkRange(leaf); - index = range.start; - length = range.end - range.start; - } + if (textLink != null) { + textLink.submit(widget.controller); } - controller - ..replaceText(index, length, value.text, null) - ..formatText( - index, - value.text.length, - LinkAttribute(value.link), - ); } } @@ -318,16 +279,6 @@ class _LinkDialogState extends State<_LinkDialog> { } void _applyLink() { - Navigator.pop(context, _TextLink(_text.trim(), _link.trim())); + Navigator.pop(context, QuillTextLink(_text.trim(), _link.trim())); } } - -class _TextLink { - _TextLink( - this.text, - this.link, - ); - - final String text; - final String link; -}