Unverified Commit b64d652f authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Add 2 new keyboard types and infer keyboardType from autofill hints (#56641)

parent 70a88c3b
......@@ -591,6 +591,7 @@ class CupertinoTextField extends StatefulWidget {
final GestureTapCallback onTap;
/// {@macro flutter.widgets.editableText.autofillHints}
/// {@macro flutter.services.autofill.autofillHints}
final Iterable<String> autofillHints;
@override
......
......@@ -728,6 +728,7 @@ class TextField extends StatefulWidget {
final ScrollController scrollController;
/// {@macro flutter.widgets.editableText.autofillHints}
/// {@macro flutter.services.autofill.autofillHints}
final Iterable<String> autofillHints;
/// Indicates whether [debugCheckHasMaterialLocalizations] can be called
......
......@@ -7,9 +7,9 @@ import 'text_input.dart';
/// A collection of commonly used autofill hint strings on different platforms.
///
/// Each hint may not be supported on every platform, and may get translated to
/// different strings on different platforms. Please refer to their documentation
/// for what each value corresponds to on different platforms.
/// Each hint is pre-defined on at least one supported platform. See their
/// documentation for their availability on each platform, and the platform
/// values each autofill hint corresponds to.
class AutofillHints {
AutofillHints._();
......@@ -350,7 +350,7 @@ class AutofillHints {
/// * Otherwise, the hint string will be used as-is.
static const String nickname = 'nickname';
/// The input field expects a single-factor SMS login code.
/// The input field expects a SMS one-time code.
///
/// This hint will be translated to the below values on different platforms:
///
......@@ -649,9 +649,9 @@ class AutofillConfiguration {
/// {@template flutter.services.autofill.autofillHints}
/// For the best results, hint strings need to be understood by the platform's
/// autofill service. The common values of hint strings can be found in
/// [AutofillHints], as well as the platforms that understand each of them.
/// [AutofillHints], as well as their availability on different platforms.
///
/// If an autofillable input field needs to use a custom hint that translate to
/// If an autofillable input field needs to use a custom hint that translates to
/// different strings on different platforms, the easiest way to achieve that
/// is to return different hint strings based on the value of
/// [defaultTargetPlatform].
......@@ -668,6 +668,12 @@ class AutofillConfiguration {
/// * On web, only the first hint is accounted for and will be translated to
/// an "autocomplete" string.
///
/// Providing an autofill hint that is predefined on the platform does not
/// automatically grant the input field eligibility for autofill. Ultimately,
/// it comes down to the autofill service currently in charge to determine
/// whether an input field is suitable for autofill and what the autofill
/// candidates are.
///
/// See also:
///
/// * [AutofillHints], a list of autofill hint strings that is predefined on at
......
......@@ -157,14 +157,33 @@ class TextInputType {
/// Requests a keyboard with ready access to both letters and numbers.
static const TextInputType visiblePassword = TextInputType._(7);
/// Optimized for a person's name.
///
/// On iOS, requests the
/// [UIKeyboardType.namePhonePad](https://developer.apple.com/documentation/uikit/uikeyboardtype/namephonepad)
/// keyboard, a keyboard optimized for entering a person’s name or phone number.
/// Does not support auto-capitalization.
///
/// On Android, requests a keyboard optimized for
/// [TYPE_TEXT_VARIATION_PERSON_NAME](https://developer.android.com/reference/android/text/InputType#TYPE_TEXT_VARIATION_PERSON_NAME).
static const TextInputType name = TextInputType._(8);
/// Optimized for postal mailing addresses.
///
/// On iOS, requests the default keyboard.
///
/// On Android, requests a keyboard optimized for
/// [TYPE_TEXT_VARIATION_POSTAL_ADDRESS](https://developer.android.com/reference/android/text/InputType#TYPE_TEXT_VARIATION_POSTAL_ADDRESS).
static const TextInputType streetAddress = TextInputType._(9);
/// All possible enum values.
static const List<TextInputType> values = <TextInputType>[
text, multiline, number, phone, datetime, emailAddress, url, visiblePassword,
text, multiline, number, phone, datetime, emailAddress, url, visiblePassword, name, streetAddress,
];
// Corresponding string name for each of the [values].
static const List<String> _names = <String>[
'text', 'multiline', 'number', 'phone', 'datetime', 'emailAddress', 'url', 'visiblePassword',
'text', 'multiline', 'number', 'phone', 'datetime', 'emailAddress', 'url', 'visiblePassword', 'name', 'address',
];
// Enum value name, this is what enum.toString() would normally return.
......
......@@ -267,6 +267,134 @@ void main() {
);
});
group('Infer keyboardType from autofillHints', () {
testWidgets('infer keyboard types from autofillHints: ios',
(WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
autofillHints: const <String>[AutofillHints.streetAddressLine1],
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('test'));
expect(tester.testTextInput.setClientArgs['inputType']['name'], equals('TextInputType.name'));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('infer keyboard types from autofillHints: non-ios',
(WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
autofillHints: const <String>[AutofillHints.streetAddressLine1],
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('test'));
expect(tester.testTextInput.setClientArgs['inputType']['name'], equals('TextInputType.address'));
});
testWidgets('inferred keyboard types can be overridden: ios',
(WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
keyboardType: TextInputType.text,
autofillHints: const <String>[AutofillHints.streetAddressLine1],
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('test'));
expect(tester.testTextInput.setClientArgs['inputType']['name'], equals('TextInputType.text'));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('inferred keyboard types can be overridden: non-ios',
(WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: FocusScope(
node: focusScopeNode,
autofocus: true,
child: EditableText(
controller: controller,
backgroundCursorColor: Colors.grey,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
keyboardType: TextInputType.text,
autofillHints: const <String>[AutofillHints.streetAddressLine1],
),
),
),
),
);
await tester.tap(find.byType(EditableText));
await tester.showKeyboard(find.byType(EditableText));
controller.text = 'test';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('test'));
expect(tester.testTextInput.setClientArgs['inputType']['name'], equals('TextInputType.text'));
});
});
testWidgets('multiline keyboard is requested when set explicitly', (WidgetTester tester) async {
await tester.pumpWidget(
MediaQuery(
......
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