diff --git a/lib/src/editor/editor.dart b/lib/src/editor/editor.dart index 2838a35c9..269eadadb 100644 --- a/lib/src/editor/editor.dart +++ b/lib/src/editor/editor.dart @@ -2,7 +2,7 @@ import 'dart:math' as math; import 'package:flutter/cupertino.dart' show CupertinoTheme, cupertinoTextSelectionControls; -import 'package:flutter/foundation.dart' show ValueListenable, kIsWeb; +import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -16,7 +16,6 @@ import '../document/nodes/container.dart' as container_node; import '../document/nodes/leaf.dart'; import 'config/editor_config.dart'; import 'embed/embed_editor_builder.dart'; -import 'magnifier/magnifier_platform_support.dart'; import 'raw_editor/config/raw_editor_config.dart'; import 'raw_editor/raw_editor.dart'; import 'widgets/box.dart'; @@ -320,7 +319,6 @@ class QuillEditorState extends State onScribbleActivated: configurations.onScribbleActivated, scribbleAreaInsets: configurations.scribbleAreaInsets, readOnlyMouseCursor: configurations.readOnlyMouseCursor, - magnifierConfiguration: configurations.magnifierConfiguration, textInputAction: configurations.textInputAction, onPerformAction: configurations.onPerformAction, ), @@ -448,7 +446,6 @@ class _QuillEditorSelectionGestureDetectorBuilder SelectionChangedCause.longPress, ); } - editor?.updateMagnifier(details.globalPosition); } bool _isPositionSelected(TapDragUpDetails details) { @@ -582,8 +579,6 @@ class _QuillEditorSelectionGestureDetectorBuilder Feedback.forLongPress(_state.context); } } - - _showMagnifierIfSupported(details.globalPosition); } @override @@ -602,21 +597,8 @@ class _QuillEditorSelectionGestureDetectorBuilder } } } - _hideMagnifierIfSupported(); super.onSingleLongTapEnd(details); } - - void _showMagnifierIfSupported(Offset positionToShow) { - if (magnifierSupported) { - editor?.showMagnifier(positionToShow); - } - } - - void _hideMagnifierIfSupported() { - if (magnifierSupported) { - editor?.hideMagnifier(); - } - } } /// Signature for the callback that reports when the user changes the selection diff --git a/lib/src/editor/magnifier/magnifier_platform_support.dart b/lib/src/editor/magnifier/magnifier_platform_support.dart deleted file mode 100644 index 443a9f9c9..000000000 --- a/lib/src/editor/magnifier/magnifier_platform_support.dart +++ /dev/null @@ -1,4 +0,0 @@ -import '../../common/utils/platform.dart'; - -/// Whether the magnifier feature is supported on the current platform. -bool magnifierSupported = isAndroid || isIos; diff --git a/lib/src/editor/magnifier/text_selection_magnifier_ext.dart b/lib/src/editor/magnifier/text_selection_magnifier_ext.dart deleted file mode 100644 index 5132939c2..000000000 --- a/lib/src/editor/magnifier/text_selection_magnifier_ext.dart +++ /dev/null @@ -1,106 +0,0 @@ -part of '../widgets/text/text_selection.dart'; - -extension TextSelectionMagnifierExt on EditorTextSelectionOverlay { - void showMagnifier( - TextPosition position, Offset offset, RenderEditor editor) { - _showMagnifier( - _buildMagnifier( - currentTextPosition: position, - globalGesturePosition: offset, - renderEditable: editor, - ), - ); - } - - void _showMagnifier(MagnifierInfo initialMagnifierInfo) { - // Hide toolbar - if (toolbar != null) { - _restoreToolbarAfterMagnifier = true; - hideToolbar(); - } else { - _restoreToolbarAfterMagnifier = false; - } - - // Update magnifier Info - _magnifierInfo.value = initialMagnifierInfo; - - final builtMagnifier = magnifierConfiguration.magnifierBuilder( - context, - _magnifierController, - _magnifierInfo, - ); - - if (builtMagnifier == null) return; - - _magnifierController.show( - context: context, - below: magnifierConfiguration.shouldDisplayHandlesInMagnifier - ? null - : _handles?.elementAtOrNull(0), - builder: (_) => builtMagnifier, - ); - } - - void updateMagnifier( - TextPosition position, Offset offset, RenderEditor editor) { - _updateMagnifier( - _buildMagnifier( - currentTextPosition: position, - globalGesturePosition: offset, - renderEditable: editor, - ), - ); - } - - void _updateMagnifier(MagnifierInfo magnifierInfo) { - if (_magnifierController.overlayEntry == null) { - return; - } - _magnifierInfo.value = magnifierInfo; - } - - void hideMagnifier() { - if (_magnifierController.overlayEntry == null) { - return; - } - _magnifierController.hide(); - if (_restoreToolbarAfterMagnifier) { - _restoreToolbarAfterMagnifier = false; - showToolbar(); - } - } - -// build magnifier info - MagnifierInfo _buildMagnifier( - {required RenderEditor renderEditable, - required Offset globalGesturePosition, - required TextPosition currentTextPosition}) { - final globalRenderEditableTopLeft = - renderEditable.localToGlobal(Offset.zero); - final localCaretRect = - renderEditable.getLocalRectForCaret(currentTextPosition); - - final lineAtOffset = renderEditable.getLineAtOffset(currentTextPosition); - final positionAtEndOfLine = TextPosition( - offset: lineAtOffset.extentOffset, - affinity: TextAffinity.upstream, - ); - - // Default affinity is downstream. - final positionAtBeginningOfLine = TextPosition( - offset: lineAtOffset.baseOffset, - ); - - final lineBoundaries = Rect.fromPoints( - renderEditable.getLocalRectForCaret(positionAtBeginningOfLine).topCenter, - renderEditable.getLocalRectForCaret(positionAtEndOfLine).bottomCenter, - ); - - return MagnifierInfo( - fieldBounds: globalRenderEditableTopLeft & renderEditable.size, - globalGesturePosition: globalGesturePosition, - caretRect: localCaretRect.shift(globalRenderEditableTopLeft), - currentLineBoundaries: lineBoundaries.shift(globalRenderEditableTopLeft), - ); - } -} diff --git a/lib/src/editor/raw_editor/config/raw_editor_config.dart b/lib/src/editor/raw_editor/config/raw_editor_config.dart index daa7d49d7..16a5a4549 100644 --- a/lib/src/editor/raw_editor/config/raw_editor_config.dart +++ b/lib/src/editor/raw_editor/config/raw_editor_config.dart @@ -66,7 +66,6 @@ class QuillRawEditorConfig { this.onScribbleActivated, this.scribbleAreaInsets, this.readOnlyMouseCursor = SystemMouseCursors.text, - @experimental this.magnifierConfiguration, this.onPerformAction, @experimental this.customLeadingBuilder, }); @@ -402,11 +401,6 @@ class QuillRawEditorConfig { /// Optional insets for the scribble area. final EdgeInsets? scribbleAreaInsets; - /// This feature is currently experimental and only supported - /// on **Android** and **iOS**. - @experimental - final TextMagnifierConfiguration? magnifierConfiguration; - /// Called when a text input action is performed. final void Function(TextInputAction action)? onPerformAction; } diff --git a/lib/src/editor/raw_editor/raw_editor.dart b/lib/src/editor/raw_editor/raw_editor.dart index af8b8e43d..4cc9543f3 100644 --- a/lib/src/editor/raw_editor/raw_editor.dart +++ b/lib/src/editor/raw_editor/raw_editor.dart @@ -1,5 +1,4 @@ import 'package:flutter/widgets.dart'; -import 'package:meta/meta.dart'; import '../../common/structs/offset_value.dart'; import '../../controller/quill_controller.dart'; @@ -77,15 +76,4 @@ abstract class EditorState extends State bool showToolbar(); void requestKeyboard(); - - @experimental - void showMagnifier(Offset positionToShow); - - @experimental - void updateMagnifier(Offset positionToShow); - - @experimental - void hideMagnifier(); - - void toggleToolbar([bool hideHandles = true]); } diff --git a/lib/src/editor/raw_editor/raw_editor_state.dart b/lib/src/editor/raw_editor/raw_editor_state.dart index e5e7888eb..fae7a3ab7 100644 --- a/lib/src/editor/raw_editor/raw_editor_state.dart +++ b/lib/src/editor/raw_editor/raw_editor_state.dart @@ -8,8 +8,7 @@ import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart' show RenderAbstractViewport; import 'package:flutter/scheduler.dart' show SchedulerBinding; -import 'package:flutter/services.dart' - show Clipboard, HardwareKeyboard, SystemChannels, TextInputControl; +import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility_temp_fork/flutter_keyboard_visibility_temp_fork.dart' show KeyboardVisibilityController; @@ -509,13 +508,7 @@ class QuillRawEditorState extends EditorState final oldSelection = controller.selection; controller.updateSelection(selection, ChangeSource.local); - if (_selectionOverlay == null) { - _selectionOverlay = _createSelectionOverlay(); - } else { - _selectionOverlay!.update(textEditingValue); - } _selectionOverlay?.handlesVisible = _shouldShowSelectionHandles(); - _selectionOverlay?.showHandles(); if (!_hasFocus) { // This will show the keyboard for all selection changes on the @@ -938,7 +931,6 @@ class QuillRawEditorState extends EditorState @override void dispose() { - hideMagnifier(); closeConnectionIfNeeded(); _keyboardVisibilitySubscription?.cancel(); HardwareKeyboard.instance.removeHandler(_hardwareKeyboardEvent); @@ -1039,38 +1031,32 @@ class QuillRawEditorState extends EditorState void _updateOrDisposeSelectionOverlayIfNeeded() { if (_selectionOverlay != null) { - if (_hasFocus) { - _selectionOverlay!.update(textEditingValue); - } else { + if (!_hasFocus || textEditingValue.selection.isCollapsed) { _selectionOverlay!.dispose(); _selectionOverlay = null; + } else { + _selectionOverlay!.update(textEditingValue); } } else if (_hasFocus) { - _selectionOverlay = _createSelectionOverlay(); + _selectionOverlay = EditorTextSelectionOverlay( + value: textEditingValue, + context: context, + debugRequiredFor: widget, + startHandleLayerLink: _startHandleLayerLink, + endHandleLayerLink: _endHandleLayerLink, + renderObject: renderEditor, + selectionCtrls: widget.config.selectionCtrls, + selectionDelegate: this, + clipboardStatus: _clipboardStatus, + contextMenuBuilder: widget.config.contextMenuBuilder == null + ? null + : (context) => widget.config.contextMenuBuilder!(context, this), + ); _selectionOverlay!.handlesVisible = _shouldShowSelectionHandles(); _selectionOverlay!.showHandles(); } } - EditorTextSelectionOverlay _createSelectionOverlay() { - return EditorTextSelectionOverlay( - value: textEditingValue, - context: context, - debugRequiredFor: widget, - startHandleLayerLink: _startHandleLayerLink, - endHandleLayerLink: _endHandleLayerLink, - renderObject: renderEditor, - selectionCtrls: widget.config.selectionCtrls, - selectionDelegate: this, - clipboardStatus: _clipboardStatus, - contextMenuBuilder: widget.config.contextMenuBuilder == null - ? null - : (context) => widget.config.contextMenuBuilder!(context, this), - magnifierConfiguration: widget.config.magnifierConfiguration ?? - TextMagnifier.adaptiveMagnifierConfiguration, - ); - } - void _handleFocusChanged() { if (dirty) { requestKeyboard(); @@ -1288,28 +1274,4 @@ class QuillRawEditorState extends EditorState @override bool get shareEnabled => false; - - @override - void hideMagnifier() { - if (_selectionOverlay == null) return; - _selectionOverlay?.hideMagnifier(); - } - - @override - void showMagnifier(ui.Offset positionToShow) { - if (_hasFocus == false) return; - if (_selectionOverlay == null) return; - final position = renderEditor.getPositionForOffset(positionToShow); - if (_selectionOverlay!.isMagnifierVisible) { - _selectionOverlay! - .updateMagnifier(position, positionToShow, renderEditor); - } else { - _selectionOverlay!.showMagnifier(position, positionToShow, renderEditor); - } - } - - @override - void updateMagnifier(ui.Offset positionToShow) { - showMagnifier(positionToShow); - } } diff --git a/lib/src/editor/widgets/text/text_line.dart b/lib/src/editor/widgets/text/text_line.dart index 0de0ad641..fc33ae58f 100644 --- a/lib/src/editor/widgets/text/text_line.dart +++ b/lib/src/editor/widgets/text/text_line.dart @@ -984,10 +984,6 @@ class RenderEditableTextLine extends RenderEditableBox { _getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1)) .where((element) => element.top < lineDy && element.bottom > lineDy) .toList(growable: false); - if (lineBoxes.isEmpty) { - // Empty line, line box is empty - return TextRange.collapsed(position.offset); - } return TextRange( start: getPositionForOffset( Offset(lineBoxes.first.left, lineDy), diff --git a/lib/src/editor/widgets/text/text_selection.dart b/lib/src/editor/widgets/text/text_selection.dart index 66fee30cd..ec8f8670c 100644 --- a/lib/src/editor/widgets/text/text_selection.dart +++ b/lib/src/editor/widgets/text/text_selection.dart @@ -4,13 +4,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; -import 'package:meta/meta.dart'; import '../../../document/nodes/node.dart'; import '../../editor.dart'; -import '../../magnifier/magnifier_platform_support.dart'; - -part '../../magnifier/text_selection_magnifier_ext.dart'; TextSelection localSelection(Node node, TextSelection selection, fromParent) { final base = fromParent ? node.offset : node.documentOffset; @@ -78,8 +74,6 @@ class EditorTextSelectionOverlay { this.onSelectionHandleTapped, this.dragStartBehavior = DragStartBehavior.start, this.handlesVisible = false, - @experimental - this.magnifierConfiguration = TextMagnifierConfiguration.disabled, }) { // Clipboard status is only checked on first instance of // ClipboardStatusNotifier @@ -186,23 +180,8 @@ class EditorTextSelectionOverlay { /// A copy/paste toolbar. OverlayEntry? toolbar; - /// Restore the selection context menu after the magnifier is dismissed. - /// Fix: https://github.com/singerdmx/flutter-quill/issues/2046 - bool _restoreToolbarAfterMagnifier = false; - TextSelection get _selection => value.selection; - final MagnifierController _magnifierController = MagnifierController(); - - @experimental - bool get isMagnifierVisible => _magnifierController.shown; - - @experimental - final TextMagnifierConfiguration magnifierConfiguration; - - final ValueNotifier _magnifierInfo = - ValueNotifier(MagnifierInfo.empty); - void setHandlesVisible(bool visible) { if (handlesVisible == visible) { return; @@ -272,9 +251,6 @@ class EditorTextSelectionOverlay { selection: _selection, selectionControls: selectionCtrls, position: position, - onHandleDragStart: _onHandleDragStart, - onHandleDragUpdate: _onHandleDragUpdate, - onHandleDragEnd: _onHandleDragEnd, dragStartBehavior: dragStartBehavior, )); } @@ -362,16 +338,11 @@ class EditorTextSelectionOverlay { /// Final cleanup. void dispose() { hide(); - _magnifierInfo.dispose(); } /// Builds the handles by inserting them into the [context]'s overlay. void showHandles() { - // TODO: Restore the assert and fix the issue or see why this change was made - // in https://github.com/singerdmx/flutter-quill/pull/2026/files#diff-ec5ab6cd2618a243ea6c82b62054455ec22ab981353b1cb50cac90b654430227L348 - // Previously it was using assertation and now it returns without any error if _handles - // is not null - if (_handles != null) return; + assert(_handles == null); _handles = [ OverlayEntry( builder: (context) => @@ -392,28 +363,8 @@ class EditorTextSelectionOverlay { void updateForScroll() { markNeedsBuild(); } - - void _onHandleDragStart(DragStartDetails details, TextPosition position) { - if (magnifierConfiguration == TextMagnifierConfiguration.disabled) return; - if (!magnifierSupported) return; - showMagnifier(position, details.globalPosition, renderObject); - } - - void _onHandleDragUpdate(DragUpdateDetails details, TextPosition position) { - if (magnifierConfiguration == TextMagnifierConfiguration.disabled) return; - if (!magnifierSupported) return; - updateMagnifier(position, details.globalPosition, renderObject); - } - - void _onHandleDragEnd(DragEndDetails details) { - if (magnifierConfiguration == TextMagnifierConfiguration.disabled) return; - if (!magnifierSupported) return; - hideMagnifier(); - } } -typedef DargHandleCallback = void Function(T details, TextPosition position); - /// This widget represents a single draggable text selection handle. class _TextSelectionHandleOverlay extends StatefulWidget { const _TextSelectionHandleOverlay({ @@ -425,9 +376,6 @@ class _TextSelectionHandleOverlay extends StatefulWidget { required this.onSelectionHandleChanged, required this.onSelectionHandleTapped, required this.selectionControls, - required this.onHandleDragStart, - required this.onHandleDragUpdate, - required this.onHandleDragEnd, this.dragStartBehavior = DragStartBehavior.start, }); @@ -437,9 +385,6 @@ class _TextSelectionHandleOverlay extends StatefulWidget { final LayerLink endHandleLayerLink; final RenderEditor renderObject; final ValueChanged onSelectionHandleChanged; - final DargHandleCallback? onHandleDragStart; - final DargHandleCallback? onHandleDragUpdate; - final ValueChanged onHandleDragEnd; final VoidCallback? onSelectionHandleTapped; final TextSelectionControls selectionControls; final DragStartBehavior dragStartBehavior; @@ -503,18 +448,15 @@ class _TextSelectionHandleOverlayState } void _handleDragStart(DragStartDetails details) { - if (!widget.renderObject.attached) return; final textPosition = widget.position == _TextSelectionHandlePosition.start ? widget.selection.base : widget.selection.extent; final lineHeight = widget.renderObject.preferredLineHeight(textPosition); final handleSize = widget.selectionControls.getHandleSize(lineHeight); _dragPosition = details.globalPosition + Offset(0, -handleSize.height); - widget.onHandleDragStart?.call(details, textPosition); } void _handleDragUpdate(DragUpdateDetails details) { - if (!widget.renderObject.attached) return; _dragPosition += details.delta; final position = widget.renderObject.getPositionForOffset(details.globalPosition); @@ -548,17 +490,8 @@ class _TextSelectionHandleOverlayState if (newSelection.baseOffset >= newSelection.extentOffset) { return; // don't allow order swapping. } - widget.onSelectionHandleChanged(newSelection); - if (widget.position == _TextSelectionHandlePosition.start) { - widget.onHandleDragUpdate?.call(details, newSelection.base); - } else if (widget.position == _TextSelectionHandlePosition.end) { - widget.onHandleDragUpdate?.call(details, newSelection.extent); - } - } - void _handleDragEnd(DragEndDetails details) { - if (!widget.renderObject.attached) return; - widget.onHandleDragEnd.call(details); + widget.onSelectionHandleChanged(newSelection); } void _handleTap() { @@ -639,7 +572,6 @@ class _TextSelectionHandleOverlayState dragStartBehavior: widget.dragStartBehavior, onPanStart: _handleDragStart, onPanUpdate: _handleDragUpdate, - onPanEnd: _handleDragEnd, onTap: _handleTap, child: Padding( padding: EdgeInsets.only(