Unverified Commit 533a5dde authored by Tomasz Gucio's avatar Tomasz Gucio Committed by GitHub

Call bringIntoView after RenderEditable updates on paste (#98604)

parent edc16121
......@@ -1689,7 +1689,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
Clipboard.setData(ClipboardData(text: selection.textInside(text)));
_replaceText(ReplaceTextIntent(textEditingValue, '', selection, cause));
if (cause == SelectionChangedCause.toolbar) {
bringIntoView(textEditingValue.selection.extent);
// Schedule a call to bringIntoView() after renderEditable updates.
SchedulerBinding.instance.addPostFrameCallback((_) {
bringIntoView(textEditingValue.selection.extent);
});
hideToolbar();
}
_clipboardStatus?.update();
......@@ -1715,7 +1718,10 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_replaceText(ReplaceTextIntent(textEditingValue, data.text!, selection, cause));
if (cause == SelectionChangedCause.toolbar) {
bringIntoView(textEditingValue.selection.extent);
// Schedule a call to bringIntoView() after renderEditable updates.
SchedulerBinding.instance.addPostFrameCallback((_) {
bringIntoView(textEditingValue.selection.extent);
});
hideToolbar();
}
}
......@@ -3095,10 +3101,20 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
void _replaceText(ReplaceTextIntent intent) {
userUpdateTextEditingValue(
intent.currentTextEditingValue.replaced(intent.replacementRange, intent.replacementText),
intent.cause,
final TextEditingValue oldValue = _value;
final TextEditingValue newValue = intent.currentTextEditingValue.replaced(
intent.replacementRange,
intent.replacementText,
);
userUpdateTextEditingValue(newValue, intent.cause);
// If there's no change in text and selection (e.g. when selecting and
// pasting identical text), the widget won't be rebuilt on value update.
// Handle this by calling _didChangeTextEditingValue() so caret and scroll
// updates can happen.
if (newValue == oldValue) {
_didChangeTextEditingValue();
}
}
late final Action<ReplaceTextIntent> _replaceTextAction = CallbackAction<ReplaceTextIntent>(onInvoke: _replaceText);
......
......@@ -10948,12 +10948,12 @@ void main() {
// Paste
await resetSelectionAndScrollOffset();
textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
await textSelectionDelegate.pasteText(SelectionChangedCause.keyboard);
await tester.pump();
expect(scrollController.offset, maxScrollExtent);
await resetSelectionAndScrollOffset();
textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
await textSelectionDelegate.pasteText(SelectionChangedCause.toolbar);
await tester.pump();
expect(scrollController.offset.roundToDouble(), 0.0);
......@@ -10980,6 +10980,50 @@ void main() {
expect(scrollController.offset.roundToDouble(), 0.0);
});
testWidgets('Should not scroll on paste if caret already visible', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/96658.
final ScrollController scrollController = ScrollController();
final TextEditingController controller = TextEditingController(
text: 'Lorem ipsum please paste here: \n${".\n" * 50}',
);
final FocusNode focusNode = FocusNode();
await tester.pumpWidget(
MaterialApp(
home: Center(
child: SizedBox(
height: 600.0,
width: 600.0,
child: EditableText(
controller: controller,
scrollController: scrollController,
focusNode: focusNode,
maxLines: null,
style: const TextStyle(fontSize: 36.0),
backgroundCursorColor: Colors.grey,
cursorColor: cursorColor,
),
),
),
)
);
await Clipboard.setData(const ClipboardData(text: 'Fairly long text to be pasted'));
focusNode.requestFocus();
final EditableTextState state =
tester.state<EditableTextState>(find.byType(EditableText));
expect(scrollController.offset, 0.0);
controller.selection = const TextSelection.collapsed(offset: 31);
await state.pasteText(SelectionChangedCause.toolbar);
await tester.pumpAndSettle();
// No scroll should happen as the caret is in the viewport all the time.
expect(scrollController.offset, 0.0);
});
testWidgets('Autofill enabled by default', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
await tester.pumpWidget(
......
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