diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index d99544c466..5c5e31d820 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -4683,6 +4683,9 @@ class EditableTextState extends State with AutomaticKeepAliveClien if (_selectionOverlay == null) { return false; } + if (_selectionOverlay!.toolbarIsVisible) { + return false; + } _liveTextInputStatus?.update(); clipboardStatus.update(); _selectionOverlay!.showToolbar(); diff --git a/packages/flutter/test/widgets/editable_text_scribble_test.dart b/packages/flutter/test/widgets/editable_text_scribble_test.dart index 384790c8eb..873db79300 100644 --- a/packages/flutter/test/widgets/editable_text_scribble_test.dart +++ b/packages/flutter/test/widgets/editable_text_scribble_test.dart @@ -683,4 +683,61 @@ void main() { // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects. }, skip: kIsWeb, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); // [intended] + + // Regression test for https://github.com/flutter/flutter/issues/159259. + testWidgets('showToolbar does nothing and returns false when already shown during Scribble selection', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; + final GlobalKey editableTextKey = GlobalKey(); + + await tester.pumpWidget( + MaterialApp( + home: EditableText( + key: editableTextKey, + controller: controller, + backgroundCursorColor: Colors.grey, + focusNode: focusNode, + style: textStyle, + cursorColor: cursorColor, + selectionControls: materialTextSelectionHandleControls, + contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) { + return AdaptiveTextSelectionToolbar.editableText( + editableTextState: editableTextState, + ); + }, + ), + ), + ); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); + + await tester.showKeyboard(find.byType(EditableText)); + + await tester.testTextInput.startScribbleInteraction(); + tester.testTextInput.updateEditingValue(TextEditingValue( + text: controller.text, + selection: const TextSelection(baseOffset: 3, extentOffset: 4), + )); + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); + + expect(editableTextKey.currentState!.showToolbar(), isTrue); + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + + expect(editableTextKey.currentState!.showToolbar(), isFalse); + await tester.pump(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + + await tester.testTextInput.finishScribbleInteraction(); + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS }), + skip: kIsWeb, // [intended] + ); } diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 9a4dcc467b..8376dd17cb 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -17212,6 +17212,51 @@ void main() { expect(tester.takeException(), isNull); }); + + // Regression test for https://github.com/flutter/flutter/issues/159259. + testWidgets('showToolbar does nothing and returns false when already shown', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; + final GlobalKey editableTextKey = GlobalKey(); + + await tester.pumpWidget( + MaterialApp( + home: EditableText( + key: editableTextKey, + autofocus: true, + controller: controller, + backgroundCursorColor: Colors.grey, + focusNode: focusNode, + style: textStyle, + cursorColor: cursorColor, + selectionControls: materialTextSelectionHandleControls, + contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) { + return AdaptiveTextSelectionToolbar.editableText( + editableTextState: editableTextState, + ); + }, + ), + ), + ); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); + + expect(editableTextKey.currentState!.showToolbar(), isTrue); + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + + expect(editableTextKey.currentState!.showToolbar(), isFalse); + await tester.pump(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS }), + skip: kIsWeb, // [intended] + ); } class UnsettableController extends TextEditingController {