[Property Editor] Can use "tab" key to submit text field inputs (#8841)
diff --git a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_inputs.dart b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_inputs.dart index c9dcc6a..6bc2a30 100644 --- a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_inputs.dart +++ b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_inputs.dart
@@ -2,7 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. +import 'dart:async'; + import 'package:devtools_app_shared/ui.dart'; +import 'package:devtools_app_shared/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -152,15 +155,29 @@ } class _TextInputState<T> extends State<_TextInput<T>> - with _PropertyInputMixin<_TextInput<T>, T> { + with _PropertyInputMixin<_TextInput<T>, T>, AutoDisposeMixin { String currentValue = ''; double paddingDiffComparedToDropdown = 1.0; + late FocusNode _focusNode; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(debugLabel: 'text-input-${widget.property.name}'); + + addAutoDisposeListener(_focusNode, () async { + if (_focusNode.hasFocus) return; + // Edit property when clicking or tabbing away from input. + await _editProperty(); + }); + } @override Widget build(BuildContext context) { final theme = Theme.of(context); return TextFormField( + focusNode: _focusNode, initialValue: widget.property.valueDisplay, enabled: widget.property.isEditable, autovalidateMode: AutovalidateMode.onUserInteraction, @@ -182,9 +199,6 @@ }); }, onEditingComplete: _editProperty, - onTapOutside: (_) async { - await _editProperty(); - }, ); }
diff --git a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart index 9bc2941..f4ada65 100644 --- a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart +++ b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart
@@ -13,6 +13,7 @@ import 'package:devtools_test/devtools_test.dart'; import 'package:devtools_test/helpers.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; @@ -369,6 +370,31 @@ }); }); + testWidgets('submitting a string input with TAB (title)', (tester) async { + return await tester.runAsync(() async { + // Load the property editor. + controller.initForTestsOnly(editableArgs: result1.args); + await tester.pumpWidget(wrap(propertyEditor)); + + // Edit the title. + final titleInput = _findTextFormField('title*'); + expect(titleInput, findsOneWidget); + await _inputText( + titleInput, + text: 'Enter with TAB!', + tester: tester, + inputDoneKey: LogicalKeyboardKey.tab, + ); + + // Verify the edit is expected. + final nextEdit = await nextEditCompleter.future; + expect( + nextEdit, + equals('title: Enter with TAB! (TYPE: String, SUCCESS: true)'), + ); + }); + }); + testWidgets('editing a numeric input (height)', (tester) async { return await tester.runAsync(() async { // Load the property editor. @@ -401,6 +427,27 @@ }); }); + testWidgets('submitting a numeric input with TAB (height)', (tester) async { + return await tester.runAsync(() async { + // Load the property editor. + controller.initForTestsOnly(editableArgs: result1.args); + await tester.pumpWidget(wrap(propertyEditor)); + + // Edit the height. + final heightInput = _findTextFormField('height'); + await _inputText( + heightInput, + text: '63.5', + tester: tester, + inputDoneKey: LogicalKeyboardKey.tab, + ); + + // Verify the edit is expected. + final nextEdit = await nextEditCompleter.future; + expect(nextEdit, equals('height: 63.5 (TYPE: double, SUCCESS: true)')); + }); + }); + testWidgets('editing an enum input (align)', (tester) async { return await tester.runAsync(() async { // Load the property editor. @@ -562,9 +609,14 @@ Finder textFormField, { required String text, required WidgetTester tester, + LogicalKeyboardKey? inputDoneKey, }) async { await tester.enterText(textFormField, text); - await tester.testTextInput.receiveAction(TextInputAction.done); + if (inputDoneKey != null) { + await tester.sendKeyDownEvent(inputDoneKey); + } else { + await tester.testTextInput.receiveAction(TextInputAction.done); + } await tester.pump(); }