-
Notifications
You must be signed in to change notification settings - Fork 6k
[TextInput] enroll in autofill by default #28333
[TextInput] enroll in autofill by default #28333
Conversation
7f47689
to
a39c769
Compare
a39c769
to
1d23024
Compare
…ong/engine into autofill-enabled-by-default
1153f5f
to
4b8e30d
Compare
…ong/engine into autofill-enabled-by-default
…ong/engine into autofill-enabled-by-default
dc94599
to
6b37ca5
Compare
@@ -462,6 +479,11 @@ void testMain() { | |||
const MethodCall show = MethodCall('TextInput.show'); | |||
sendFrameworkMessage(codec.encodeMethodCall(show)); | |||
|
|||
final MethodCall setSizeAndTransform = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "setSizeAndTransform" message has to be there since on some platforms (e.g. Desktop Safari) we don't put the input element on DOM until we get its correct dimensions from the framework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put this in a comment in the code so people later can easily see why setSizeAndTransform
is necessary.
6b37ca5
to
87e1927
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only reviewed the web part and it looks good overall with a couple comments.
@@ -462,6 +479,11 @@ void testMain() { | |||
const MethodCall show = MethodCall('TextInput.show'); | |||
sendFrameworkMessage(codec.encodeMethodCall(show)); | |||
|
|||
final MethodCall setSizeAndTransform = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put this in a comment in the code so people later can easily see why setSizeAndTransform
is necessary.
element.name = autofillHint; | ||
if (placeholder != null) { | ||
element.placeholder = placeholder; | ||
} | ||
element.autocomplete = autofillHint ?? 'on'; | ||
if (autofillHint == null) { | ||
return; | ||
} | ||
element.id = autofillHint; | ||
if (autofillHint.contains('password')) { | ||
element.type = 'password'; | ||
} else { | ||
element.type = 'text'; | ||
} | ||
} else if (domElement is html.TextAreaElement) { | ||
final html.TextAreaElement element = domElement; | ||
element.name = hint; | ||
element.id = hint; | ||
element.setAttribute('autocomplete', hint); | ||
if (placeholder != null) { | ||
domElement.placeholder = placeholder; | ||
} | ||
if (autofillHint != null) { | ||
domElement.name = autofillHint; | ||
domElement.id = autofillHint; | ||
} | ||
domElement.setAttribute('autocomplete', autofillHint ?? 'on'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason these two are different? The implementation for input
and textarea
should remain mostly identical.
87e1927
to
ea2b425
Compare
ea2b425
to
040581d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
/// The `fields` argument corresponds to the "fields" field in a | ||
/// `TextInputConfiguration`. | ||
/// | ||
/// Returns null if the input field is not within an autofill group. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate the added docs here. We need an analyzer rule to require this like in the framework.
} else if (domElement is html.TextAreaElement) { | ||
final html.TextAreaElement element = domElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this variable was created in the first place, good idea to remove it.
|
||
late TextEditingChannel channel; | ||
late final TextEditingChannel channel = TextEditingChannel(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this still need late
?
I feel like I'm wrong and I got tripped up by this recently...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think late
is still required because the right-hand-side expression refers to this
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This needs lazy initialization because this
has to be initialized first, to be passed to the TextEditingChannel
constructor, otherwise we'll have a circular dependency.
@@ -462,6 +479,15 @@ void testMain() { | |||
const MethodCall show = MethodCall('TextInput.show'); | |||
sendFrameworkMessage(codec.encodeMethodCall(show)); | |||
|
|||
// The "setSizeAndTransform" message has to be here before we call | |||
// checkInputEditingState, since on some platforms (e.g. Desktop Safari) | |||
// we don't put the input element on DOM until we get its correct |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "on DOM" => "into the DOM"
If that's correct and I'm not misunderstanding, I think it's more explicit this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for the duplicate comments below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if LGT @mdebbar
@@ -129,8 +129,9 @@ void _hideAutofillElements(html.HtmlElement domElement, | |||
|
|||
/// Form that contains all the fields in the same AutofillGroup. | |||
/// | |||
/// These values are to be used when autofill is enabled and there is a group of | |||
/// text fields with more than one text field. | |||
/// These values are to be used when autofill is enabled (the default) on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does "These values" refer to? Is there a better way to phrase it?
@@ -153,12 +154,23 @@ class EngineAutofillForm { | |||
/// See [formsOnTheDom]. | |||
final String formIdentifier; | |||
|
|||
/// Creates an [EngineAutofillFrom] from the JSON representation of a flutter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: s/flutter/Flutter/
@@ -287,7 +299,7 @@ class EngineAutofillForm { | |||
element.onInput.listen((html.Event e) { | |||
if (items![key] == null) { | |||
throw StateError( | |||
'Autofill would not work withuot Autofill value set'); | |||
'Autofill would not work without Autofill value set'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an error that could happen due to a framework-side bug? If so, can the error message be more specific? For example, would it help if it mentioned the key
that was missing and why it was expected?
required this.textCapitalization}); | ||
required this.autofillHint, | ||
required this.textCapitalization, | ||
this.placeholder}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: code style could be improved here, e.g.:
AutofillInfo({
required this.editingState,
required this.uniqueIdentifier,
required this.hint,
required this.textCapitalization});
required this.autofillHint,
required this.textCapitalization,
this.placeholder,
});
@@ -364,42 +377,64 @@ class AutofillInfo { | |||
/// Used as a guidance to the browser as to the type of information expected | |||
/// in the field. | |||
/// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete | |||
final String hint; | |||
final String? autofillHint; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: is the first sentence in the dartdoc still useful? Seems obvious now that this is used for autofill.
|
||
late TextEditingChannel channel; | ||
late final TextEditingChannel channel = TextEditingChannel(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this still need to be late
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think late
is still required because the right-hand-side expression refers to this
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes: #28333 (comment)
element.type = 'text'; | ||
} | ||
} | ||
element.autocomplete = autofillHint ?? 'on'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to enable autocomplete when autofill hint is null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's what the pull request trying to do: flutter/flutter#85554. If we want to do it on Android then the default behavior should probably be consistent across platforms (or does it make sense on the web?).
https://github.com/flutter/flutter/pull/86312/files tries to make so that even if the developer leaves the hint list empty (the default), EditableTextState
will still generate an autofill JSON object for the text field when it's focused, and the autofill service can try to determine the type of the text field (or whether the field should be autofilled at all) using heuristics.
if the developer explicitly sets EditableText.autofillHints
to null
, then autofill will be disabled.
final String? autofillHint = this.autofillHint; | ||
final String? placeholder = this.placeholder; | ||
if (autofillHint != null) { | ||
domElement.id = autofillHint; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are setting the id again below. Is this still necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
f85e4d3
to
a2c62b4
Compare
Related: flutter/flutter#85554
Framework PR: https://github.com/flutter/flutter/pull/86312/files
The framework will be setting the
autofill
field to null to indicate that autofill is explicitly disabled on the text field (flutter/flutter#86312).This PR allows the platform to make autofill attempts using heuristics when the framework sends a
TextInputConfiguration
that has 0 autofill hints.@yjbanov I'll try to wrap each input field in a Form (and potentially make the autofill implementation a mixin) in a separate PR.
Pre-launch Checklist
writing and running engine tests.
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.