Unverified Commit 1794e81f authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Keep the selection after 'Copy' pressed on iOS. (#76327)

parent df25cfe2
......@@ -6,6 +6,7 @@ import 'dart:math' as math;
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'localizations.dart';
import 'text_selection_toolbar.dart';
......
......@@ -774,7 +774,11 @@ abstract class TextSelectionDelegate {
set textEditingValue(TextEditingValue value);
/// Hides the text selection toolbar.
void hideToolbar();
///
/// By default, hideHandles is true, and the toolbar is hidden along with its
/// handles. If hideHandles is set to false, then the toolbar will be hidden
/// but the handles will remain.
void hideToolbar([bool hideHandles = true]);
/// Brings the provided [TextPosition] into the visible area of the text
/// input.
......
......@@ -2505,8 +2505,14 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
@override
void hideToolbar() {
_selectionOverlay?.hide();
void hideToolbar([bool hideHandles = true]) {
if (hideHandles) {
// Hide the handles and the toolbar.
_selectionOverlay?.hide();
} else {
// Hide only the toolbar but not the handles.
_selectionOverlay?.hideToolbar();
}
}
/// Toggles the visibility of the toolbar.
......
......@@ -228,12 +228,26 @@ abstract class TextSelectionControls {
text: value.selection.textInside(value.text),
));
clipboardStatus?.update();
delegate.textEditingValue = TextEditingValue(
text: value.text,
selection: TextSelection.collapsed(offset: value.selection.end),
);
delegate.bringIntoView(delegate.textEditingValue.selection.extent);
delegate.hideToolbar();
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
// Hide the toolbar, but keep the selection and keep the handles.
delegate.hideToolbar(false);
return;
case TargetPlatform.macOS:
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
// Collapse the selection and hide the toolbar and handles.
delegate.textEditingValue = TextEditingValue(
text: value.text,
selection: TextSelection.collapsed(offset: value.selection.end),
);
delegate.hideToolbar();
return;
}
}
/// Paste the current clipboard selection (obtained from [Clipboard]) into
......
......@@ -197,17 +197,34 @@ void main() {
await tester.pump(const Duration(milliseconds: 50));
await tester.tapAt(textOffsetToPosition(tester, index));
await tester.pumpAndSettle();
expect(controller.selection.isCollapsed, isFalse);
expect(controller.selection.baseOffset, 0);
expect(controller.selection.extentOffset, 7);
// Paste is showing even though clipboard is empty.
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsOneWidget);
expect(find.descendant(
of: find.byType(Overlay),
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionHandleOverlay'),
), findsNWidgets(2));
// Tap copy to add something to the clipboard and close the menu.
await tester.tapAt(tester.getCenter(find.text('Copy')));
await tester.pumpAndSettle();
// The menu is gone, but the handles are visible on the existing selection.
expect(find.text('Copy'), findsNothing);
expect(find.text('Cut'), findsNothing);
expect(find.text('Paste'), findsNothing);
expect(controller.selection.isCollapsed, isFalse);
expect(controller.selection.baseOffset, 0);
expect(controller.selection.extentOffset, 7);
expect(find.descendant(
of: find.byType(Overlay),
matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionHandleOverlay'),
), findsNWidgets(2));
// Double tap to show the menu again.
await tester.tapAt(textOffsetToPosition(tester, index));
......
......@@ -19,7 +19,7 @@ class FakeEditableTextState with TextSelectionDelegate {
TextEditingValue textEditingValue = TextEditingValue.empty;
@override
void hideToolbar() { }
void hideToolbar([bool hideHandles = true]) { }
@override
void bringIntoView(TextPosition position) { }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment