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) {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
bringIntoView(textEditingValue.selection.extent); 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,11 +11233,28 @@ void main() { ...@@ -11233,11 +11233,28 @@ 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();
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( await tester.pumpWidget(
MaterialApp( MaterialApp(
...@@ -11261,65 +11278,67 @@ void main() { ...@@ -11261,65 +11278,67 @@ void main() {
), ),
); );
final TextSelectionDelegate textSelectionDelegate = key.currentState!; // Populate [maxScrollExtent].
await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
return key.currentState!;
}
late double maxScrollExtent; testWidgets('SelectAll toolbar action will not set max scroll on designated platforms', (WidgetTester tester) async {
Future<void> resetSelectionAndScrollOffset([bool setMaxScrollExtent = true]) async { final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester);
controller.value = controller.value.copyWith(
text: text, await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
selection: controller.selection.copyWith(baseOffset: 0, extentOffset: 1), textSelectionDelegate.selectAll(SelectionChangedCause.toolbar);
);
await tester.pump(); await tester.pump();
final double targetOffset = setMaxScrollExtent ? scrollController.position.maxScrollExtent : 0.0; expect(scrollController.offset, 0.0);
scrollController.jumpTo(targetOffset); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
await tester.pumpAndSettle();
maxScrollExtent = scrollController.position.maxScrollExtent; testWidgets('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async {
expect(scrollController.offset, targetOffset); final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester);
}
// Cut // Cut
await resetSelectionAndScrollOffset(); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.cutSelection(SelectionChangedCause.keyboard); textSelectionDelegate.cutSelection(SelectionChangedCause.keyboard);
await tester.pump(); await tester.pump();
expect(scrollController.offset, maxScrollExtent); expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.cutSelection(SelectionChangedCause.toolbar); textSelectionDelegate.cutSelection(SelectionChangedCause.toolbar);
await tester.pump(); await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0); expect(scrollController.offset.roundToDouble(), 0.0);
// Paste // Paste
await resetSelectionAndScrollOffset(); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard); await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
await tester.pump(); await tester.pump();
expect(scrollController.offset, maxScrollExtent); expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar); await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
await tester.pump(); await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0); expect(scrollController.offset.roundToDouble(), 0.0);
// Select all // Select all
await resetSelectionAndScrollOffset(false); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false);
textSelectionDelegate.selectAll(SelectionChangedCause.keyboard); textSelectionDelegate.selectAll(SelectionChangedCause.keyboard);
await tester.pump(); await tester.pump();
expect(scrollController.offset, 0.0); 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.roundToDouble(), maxScrollExtent);
// Copy // Copy
await resetSelectionAndScrollOffset(); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.copySelection(SelectionChangedCause.keyboard); textSelectionDelegate.copySelection(SelectionChangedCause.keyboard);
await tester.pump(); await tester.pump();
expect(scrollController.offset, maxScrollExtent); expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset(); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: true);
textSelectionDelegate.copySelection(SelectionChangedCause.toolbar); textSelectionDelegate.copySelection(SelectionChangedCause.toolbar);
await tester.pump(); await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0); 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