Replace `buildToolbar` with `contextMenuBuilder` (#1106)

pull/1108/head
Adil Hanney 2 years ago committed by GitHub
parent 06d62d61bb
commit 967af17a75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      lib/src/widgets/raw_editor.dart
  2. 84
      lib/src/widgets/text_selection.dart

@ -1050,13 +1050,15 @@ class RawEditorState extends EditorState
value: textEditingValue, value: textEditingValue,
context: context, context: context,
debugRequiredFor: widget, debugRequiredFor: widget,
toolbarLayerLink: _toolbarLayerLink,
startHandleLayerLink: _startHandleLayerLink, startHandleLayerLink: _startHandleLayerLink,
endHandleLayerLink: _endHandleLayerLink, endHandleLayerLink: _endHandleLayerLink,
renderObject: renderEditor, renderObject: renderEditor,
selectionCtrls: widget.selectionCtrls, selectionCtrls: widget.selectionCtrls,
selectionDelegate: this, selectionDelegate: this,
clipboardStatus: _clipboardStatus, clipboardStatus: _clipboardStatus,
contextMenuBuilder: widget.contextMenuBuilder == null
? null
: (context) => widget.contextMenuBuilder!(context, this),
); );
_selectionOverlay!.handlesVisible = _shouldShowSelectionHandles(); _selectionOverlay!.handlesVisible = _shouldShowSelectionHandles();
_selectionOverlay!.showHandles(); _selectionOverlay!.showHandles();

@ -69,7 +69,6 @@ class EditorTextSelectionOverlay {
EditorTextSelectionOverlay({ EditorTextSelectionOverlay({
required this.value, required this.value,
required this.context, required this.context,
required this.toolbarLayerLink,
required this.startHandleLayerLink, required this.startHandleLayerLink,
required this.endHandleLayerLink, required this.endHandleLayerLink,
required this.renderObject, required this.renderObject,
@ -77,12 +76,11 @@ class EditorTextSelectionOverlay {
required this.selectionCtrls, required this.selectionCtrls,
required this.selectionDelegate, required this.selectionDelegate,
required this.clipboardStatus, required this.clipboardStatus,
required this.contextMenuBuilder,
this.onSelectionHandleTapped, this.onSelectionHandleTapped,
this.dragStartBehavior = DragStartBehavior.start, this.dragStartBehavior = DragStartBehavior.start,
this.handlesVisible = false, this.handlesVisible = false,
}) { }) {
final overlay = Overlay.of(context, rootOverlay: true);
// Clipboard status is only checked on first instance of // Clipboard status is only checked on first instance of
// ClipboardStatusNotifier // ClipboardStatusNotifier
// if state has changed after creation, but prior to // if state has changed after creation, but prior to
@ -90,9 +88,6 @@ class EditorTextSelectionOverlay {
// we won't know the status unless there is forced update // we won't know the status unless there is forced update
// i.e. occasionally no paste // i.e. occasionally no paste
clipboardStatus.update(); clipboardStatus.update();
_toolbarController = AnimationController(
duration: const Duration(milliseconds: 150), vsync: overlay);
} }
TextEditingValue value; TextEditingValue value;
@ -122,10 +117,6 @@ class EditorTextSelectionOverlay {
/// Debugging information for explaining why the [Overlay] is required. /// Debugging information for explaining why the [Overlay] is required.
final Widget debugRequiredFor; final Widget debugRequiredFor;
/// The object supplied to the [CompositedTransformTarget] that wraps the text
/// field.
final LayerLink toolbarLayerLink;
/// The objects supplied to the [CompositedTransformTarget] that wraps the /// The objects supplied to the [CompositedTransformTarget] that wraps the
/// location of start selection handle. /// location of start selection handle.
final LayerLink startHandleLayerLink; final LayerLink startHandleLayerLink;
@ -144,6 +135,11 @@ class EditorTextSelectionOverlay {
/// text field. /// text field.
final TextSelectionDelegate selectionDelegate; final TextSelectionDelegate selectionDelegate;
/// {@macro flutter.widgets.EditableText.contextMenuBuilder}
///
/// If not provided, no context menu will be built.
final WidgetBuilder? contextMenuBuilder;
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
/// If set to [DragStartBehavior.start], handle drag behavior will /// If set to [DragStartBehavior.start], handle drag behavior will
@ -177,7 +173,6 @@ class EditorTextSelectionOverlay {
/// Useful because the actual value of the clipboard can only be checked /// Useful because the actual value of the clipboard can only be checked
/// asynchronously (see [Clipboard.getData]). /// asynchronously (see [Clipboard.getData]).
final ClipboardStatusNotifier clipboardStatus; final ClipboardStatusNotifier clipboardStatus;
late AnimationController _toolbarController;
/// A pair of handles. If this is non-null, there are always 2, though the /// A pair of handles. If this is non-null, there are always 2, though the
/// second is hidden when the selection is collapsed. /// second is hidden when the selection is collapsed.
@ -188,8 +183,6 @@ class EditorTextSelectionOverlay {
TextSelection get _selection => value.selection; TextSelection get _selection => value.selection;
Animation<double> get _toolbarOpacity => _toolbarController.view;
void setHandlesVisible(bool visible) { void setHandlesVisible(bool visible) {
if (handlesVisible == visible) { if (handlesVisible == visible) {
return; return;
@ -220,7 +213,6 @@ class EditorTextSelectionOverlay {
/// To hide the whole overlay, see [hide]. /// To hide the whole overlay, see [hide].
void hideToolbar() { void hideToolbar() {
assert(toolbar != null); assert(toolbar != null);
_toolbarController.stop();
toolbar!.remove(); toolbar!.remove();
toolbar = null; toolbar = null;
} }
@ -228,10 +220,12 @@ class EditorTextSelectionOverlay {
/// Shows the toolbar by inserting it into the [context]'s overlay. /// Shows the toolbar by inserting it into the [context]'s overlay.
void showToolbar() { void showToolbar() {
assert(toolbar == null); assert(toolbar == null);
toolbar = OverlayEntry(builder: _buildToolbar); if (contextMenuBuilder == null) return;
toolbar = OverlayEntry(builder: (context) {
return contextMenuBuilder!(context);
});
Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor) Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)
.insert(toolbar!); .insert(toolbar!);
_toolbarController.forward(from: 0);
// make sure handles are visible as well // make sure handles are visible as well
if (_handles == null) { if (_handles == null) {
@ -319,63 +313,6 @@ class EditorTextSelectionOverlay {
..bringIntoView(textPosition); ..bringIntoView(textPosition);
} }
Widget _buildToolbar(BuildContext context) {
// Find the horizontal midpoint, just above the selected text.
List<TextSelectionPoint> endpoints;
try {
// building with an invalid selection with throw an exception
// This happens where the selection has changed, but the toolbar
// hasn't been dismissed yet.
endpoints = renderObject.getEndpointsForSelection(_selection);
} catch (_) {
return Container();
}
final editingRegion = Rect.fromPoints(
renderObject.localToGlobal(Offset.zero),
renderObject.localToGlobal(renderObject.size.bottomRight(Offset.zero)),
);
final baseLineHeight = renderObject.preferredLineHeight(_selection.base);
final extentLineHeight =
renderObject.preferredLineHeight(_selection.extent);
final smallestLineHeight = math.min(baseLineHeight, extentLineHeight);
final isMultiline = endpoints.last.point.dy - endpoints.first.point.dy >
smallestLineHeight / 2;
// If the selected text spans more than 1 line,
// horizontally center the toolbar.
// Derived from both iOS and Android.
final midX = isMultiline
? editingRegion.width / 2
: (endpoints.first.point.dx + endpoints.last.point.dx) / 2;
final midpoint = Offset(
midX,
// The y-coordinate won't be made use of most likely.
endpoints[0].point.dy - baseLineHeight,
);
return FadeTransition(
opacity: _toolbarOpacity,
child: CompositedTransformFollower(
link: toolbarLayerLink,
showWhenUnlinked: false,
offset: -editingRegion.topLeft,
child: selectionCtrls.buildToolbar(
context,
editingRegion,
baseLineHeight,
midpoint,
endpoints,
selectionDelegate,
clipboardStatus,
null),
),
);
}
void markNeedsBuild([Duration? duration]) { void markNeedsBuild([Duration? duration]) {
if (_handles != null) { if (_handles != null) {
_handles![0].markNeedsBuild(); _handles![0].markNeedsBuild();
@ -399,7 +336,6 @@ class EditorTextSelectionOverlay {
/// Final cleanup. /// Final cleanup.
void dispose() { void dispose() {
hide(); hide();
_toolbarController.dispose();
} }
/// Builds the handles by inserting them into the [context]'s overlay. /// Builds the handles by inserting them into the [context]'s overlay.

Loading…
Cancel
Save