[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();
}