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
),
cause,
);
if (cause == SelectionChangedCause.toolbar) {
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 {
/// by the user.
void handleSelectAll(TextSelectionDelegate delegate) {
delegate.selectAll(SelectionChangedCause.toolbar);
delegate.bringIntoView(delegate.textEditingValue.selection.extent);
}
}
......@@ -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
/// encloses the given [BuildContext].
......
......@@ -11233,11 +11233,28 @@ void main() {
expect(tester.hasRunningAnimations, isFalse);
});
testWidgets('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async {
final GlobalKey<EditableTextState> key = GlobalKey<EditableTextState>();
group('Selection changed scroll into view', () {
final String text = List<int>.generate(64, (int index) => index).join('\n');
final TextEditingController controller = TextEditingController(text: text);
final ScrollController scrollController = ScrollController();
late double maxScrollExtent;
Future<void> resetSelectionAndScrollOffset(WidgetTester tester, {required bool setMaxScrollExtent}) async {
controller.value = controller.value.copyWith(
text: text,
selection: controller.selection.copyWith(baseOffset: 0, extentOffset: 1),
);
await tester.pump();
final double targetOffset = setMaxScrollExtent ? scrollController.position.maxScrollExtent : 0.0;
scrollController.jumpTo(targetOffset);
await tester.pumpAndSettle();
maxScrollExtent = scrollController.position.maxScrollExtent;
expect(scrollController.offset, targetOffset);
}
Future<TextSelectionDelegate> pumpLongScrollableText(WidgetTester tester) async {
final GlobalKey<EditableTextState> key = GlobalKey<EditableTextState>();
await tester.pumpWidget(
MaterialApp(
......@@ -11261,65 +11278,67 @@ void main() {
),
);
final TextSelectionDelegate textSelectionDelegate = key.currentState!;
// Populate [maxScrollExtent].
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
return key.currentState!;
}
late double maxScrollExtent;
Future<void> resetSelectionAndScrollOffset([bool setMaxScrollExtent = true]) async {
controller.value = controller.value.copyWith(
text: text,
selection: controller.selection.copyWith(baseOffset: 0, extentOffset: 1),
);
testWidgets('SelectAll toolbar action will not set max scroll on designated platforms', (WidgetTester tester) async {
final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.toolbar);
await tester.pump();
final double targetOffset = setMaxScrollExtent ? scrollController.position.maxScrollExtent : 0.0;
scrollController.jumpTo(targetOffset);
await tester.pumpAndSettle();
maxScrollExtent = scrollController.position.maxScrollExtent;
expect(scrollController.offset, targetOffset);
}
expect(scrollController.offset, 0.0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async {
final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester);
// Cut
await resetSelectionAndScrollOffset();
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.cutSelection(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset();
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.cutSelection(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
// Paste
await resetSelectionAndScrollOffset();
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset();
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
// Select all
await resetSelectionAndScrollOffset(false);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, 0.0);
await resetSelectionAndScrollOffset(false);
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), maxScrollExtent);
// Copy
await resetSelectionAndScrollOffset();
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.copySelection(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset();
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 {
......
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