Unverified Commit db3b1411 authored by Anthony Oleinik's avatar Anthony Oleinik Committed by GitHub

SelectAll on iOS does not scroll to end of editable text anymore (#105799)

Co-authored-by: 's avatarAnthony Oleinik <oleina@google.com>
parent f5e4d2b4
...@@ -1929,8 +1929,19 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -1929,8 +1929,19 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
), ),
cause, cause,
); );
if (cause == SelectionChangedCause.toolbar) { if (cause == SelectionChangedCause.toolbar) {
bringIntoView(textEditingValue.selection.extent); switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
bringIntoView(textEditingValue.selection.extent);
break;
case TargetPlatform.macOS:
case TargetPlatform.iOS:
break;
}
} }
} }
......
...@@ -208,7 +208,6 @@ abstract class TextSelectionControls { ...@@ -208,7 +208,6 @@ abstract class TextSelectionControls {
/// by the user. /// by the user.
void handleSelectAll(TextSelectionDelegate delegate) { void handleSelectAll(TextSelectionDelegate delegate) {
delegate.selectAll(SelectionChangedCause.toolbar); delegate.selectAll(SelectionChangedCause.toolbar);
delegate.bringIntoView(delegate.textEditingValue.selection.extent);
} }
} }
...@@ -578,7 +577,7 @@ class TextSelectionOverlay { ...@@ -578,7 +577,7 @@ class TextSelectionOverlay {
} }
} }
/// An object that manages a pair of selection handles. /// An object that manages a pair of selection handles and a toolbar.
/// ///
/// The selection handles are displayed in the [Overlay] that most closely /// The selection handles are displayed in the [Overlay] that most closely
/// encloses the given [BuildContext]. /// encloses the given [BuildContext].
......
...@@ -11233,38 +11233,13 @@ void main() { ...@@ -11233,38 +11233,13 @@ void main() {
expect(tester.hasRunningAnimations, isFalse); expect(tester.hasRunningAnimations, isFalse);
}); });
testWidgets('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async { group('Selection changed scroll into view', () {
final GlobalKey<EditableTextState> key = GlobalKey<EditableTextState>();
final String text = List<int>.generate(64, (int index) => index).join('\n'); final String text = List<int>.generate(64, (int index) => index).join('\n');
final TextEditingController controller = TextEditingController(text: text); final TextEditingController controller = TextEditingController(text: text);
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
height: 32,
child: EditableText(
key: key,
focusNode: focusNode,
style: Typography.material2018().black.subtitle1!,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
controller: controller,
scrollController: scrollController,
maxLines: 2,
),
),
),
),
),
);
final TextSelectionDelegate textSelectionDelegate = key.currentState!;
late double maxScrollExtent; late double maxScrollExtent;
Future<void> resetSelectionAndScrollOffset([bool setMaxScrollExtent = true]) async {
Future<void> resetSelectionAndScrollOffset(WidgetTester tester, {required bool setMaxScrollExtent}) async {
controller.value = controller.value.copyWith( controller.value = controller.value.copyWith(
text: text, text: text,
selection: controller.selection.copyWith(baseOffset: 0, extentOffset: 1), selection: controller.selection.copyWith(baseOffset: 0, extentOffset: 1),
...@@ -11277,49 +11252,93 @@ void main() { ...@@ -11277,49 +11252,93 @@ void main() {
expect(scrollController.offset, targetOffset); expect(scrollController.offset, targetOffset);
} }
// Cut
await resetSelectionAndScrollOffset();
textSelectionDelegate.cutSelection(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(); Future<TextSelectionDelegate> pumpLongScrollableText(WidgetTester tester) async {
textSelectionDelegate.cutSelection(SelectionChangedCause.toolbar); final GlobalKey<EditableTextState> key = GlobalKey<EditableTextState>();
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
// Paste await tester.pumpWidget(
await resetSelectionAndScrollOffset(); MaterialApp(
await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard); home: Scaffold(
await tester.pump(); body: Center(
expect(scrollController.offset, maxScrollExtent); child: SizedBox(
height: 32,
child: EditableText(
key: key,
focusNode: focusNode,
style: Typography.material2018().black.subtitle1!,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
controller: controller,
scrollController: scrollController,
maxLines: 2,
),
),
),
),
),
);
await resetSelectionAndScrollOffset(); // Populate [maxScrollExtent].
await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
await tester.pump(); return key.currentState!;
expect(scrollController.offset.roundToDouble(), 0.0); }
// Select all testWidgets('SelectAll toolbar action will not set max scroll on designated platforms', (WidgetTester tester) async {
await resetSelectionAndScrollOffset(false); final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester);
textSelectionDelegate.selectAll(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, 0.0);
await resetSelectionAndScrollOffset(false); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.toolbar); textSelectionDelegate.selectAll(SelectionChangedCause.toolbar);
await tester.pump(); await tester.pump();
expect(scrollController.offset.roundToDouble(), maxScrollExtent); expect(scrollController.offset, 0.0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
// Copy testWidgets('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async {
await resetSelectionAndScrollOffset(); final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester);
textSelectionDelegate.copySelection(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(); // Cut
textSelectionDelegate.copySelection(SelectionChangedCause.toolbar); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await tester.pump(); textSelectionDelegate.cutSelection(SelectionChangedCause.keyboard);
expect(scrollController.offset.roundToDouble(), 0.0); await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.cutSelection(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
// Paste
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
// Select all
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, 0.0);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), maxScrollExtent);
// Copy
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.copySelection(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.copySelection(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
}, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
}); });
testWidgets('Should not scroll on paste if caret already visible', (WidgetTester tester) async { testWidgets('Should not scroll on paste if caret already visible', (WidgetTester tester) async {
......
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