Repository: flutter
Issue: Autofill update/save password prompt inconsistent behaviour for IOS when multiple textfields on screen
Labels: a: text input,platform-ios,framework,has reproducible steps,P2,team-text-input,triaged-text-input,found in release: 3.22

### Steps to reproduce

So the problem is that if we deviate from the normal structure:

***1
[Email textfield]
[Password textfield]

To something like this:

***2
[Email textfield]
[Password textfield]
[Confirm password textfield]

OR

***3
[Current password textfield]
[Email textfield]
[New password textfield]
[Confirm new password textfield]

The autofill feature in conjunction with AutofillGroup produces very random behaviour for causing the save/update IOS keychain prompt to appear on the screen for passwords. What I mean by random is that the smallest thing can cause the prompt behaviour to either appear on the screen, or most of the time not appear at all! The only time I observed it working 100% of the time was when we had a similar structure to ***1.

Also I am confident that we have the apple site association set-up correctly as well. This was also tested on a real IPhone 15 pro max, IOS version 17.4.1.

1. Copy provided code onto a page.
2. Try inputting textfields and clicking the submit button to see if you can get the IOS keychain save/update password prompt to appear consistently on the screen. The only time I can get it to appear consistently is when I leave my cursor on last textfield and click change password while keyboard is open, or click done on the keyboard when cursor is on the last textfield. 

Including any extra key events or moving cursor is enough to offset this process for me.

### Expected results

What I expect to happen, is the when the change password button is clicked, the save/update password prompt should appear every time. The position of the cursor, or extra key events shouldn't be able to dictate this behaviour

### Actual results

What actually happens is that the IOS keychain prompt to save/update password is very inconsistent. Please refer to the video for examples of what I mean. If I introduce any extra key events than needed, there is a high change this can prevent the actual prompt from showing up at all, when submitting!

### Code sample

<details open><summary>Code sample</summary>

```dart
 return Container(
      child: Scaffold(
       // resizeToAvoidBottomInset: false,
        backgroundColor: Colors.transparent,
        body: Padding(
          padding: padding,
          child: Form(
            key: _formKey,
            //autovalidateMode: AutovalidateMode.always,
            child: AutofillGroup(
              child: Column(
                children: [
                  const SizedBox(height: 10),
                  TextFormField(
                    //autofillHints: const [AutofillHints.password],
                    validator: (value) {
                      var valueNonNull = value ?? "";
                      if (valueNonNull.isEmpty) {
                        return "Please enter your current password";
                      } else if (wrongCurrentPass) {
                        return "Current password is incorrect";
                      }
                      return null;
                    },
                    controller: _currentPasswordController,
                    style: TextStyle(color: Theme.of(context).disabledColor),
                    initialValue: null,
                    enabled: true,
                    //   validator: widget.validatorOverride ?? validator,
                    onChanged: (_) {
                      setState(() {
                        wrongCurrentPass = false;
                      });
                    },
                    autocorrect: false,
                    decoration: InputDecoration(
                      labelText: "Current password",
                      prefixIcon: null,
                      prefixIconConstraints: const BoxConstraints(
                        minWidth: 40,
                        maxWidth: 70,
                      ),
                      suffixIcon: IconButton(
                          onPressed: () {
                            obscureTextCurrentPass = !obscureTextCurrentPass;
                            setState(() {});
                          },
                          icon: Icon(obscureTextCurrentPass
                              ? Icons.visibility
                              : Icons.visibility_off)),
                      errorMaxLines: 3,
                      hintText: "Enter your current password",
                    ),
                    maxLength: null,
                    
                    keyboardType: TextInputType.text,
                    obscureText: obscureTextCurrentPass,
                    // onFieldSubmitted: onFieldSubmitted,
                    textAlignVertical: TextAlignVertical.center,
                    // autofillHints: autofillHints,
                  ),
                  const SizedBox(height: 25),
                        
                  //email
                  TextFormField(
                    autofillHints: const [AutofillHints.email],
                    readOnly: true,
                    enabled: false,
                    initialValue: "testing123@gmail.com",
                  ),
                  const SizedBox(height: 25),
                        
                  //New password
                  TextFormField(
                    //autofillHints: const [AutofillHints.newPassword],
                    controller: _newPasswordController,
                    style: TextStyle(color: Theme.of(context).disabledColor),
                    //   initialValue: initialValue,
                    enabled: true,
                    validator: (value) {
                      RegExp regex = RegExp(
                          r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{8,}$');
                      var valueNonNull = value ?? "";
                        
                      if (valueNonNull.isEmpty ||
                          valueNonNull.length < 8 ||
                          !regex.hasMatch(valueNonNull)) {
                        return ("Password should contain a mix of uppercase and lowercase letters, digits, and special characters, and must be more than 8 characters");
                      }
                      return null;
                    },
                    onChanged: (_) {},
                    autocorrect: false,
                    decoration: InputDecoration(
                      labelText: "New password",
                      prefixIcon: null,
                      prefixIconConstraints: const BoxConstraints(
                        minWidth: 40,
                        maxWidth: 70,
                      ),
                      suffixIcon: IconButton(
                          onPressed: () {
                            obscureTextNewPass = !obscureTextNewPass;
                            setState(() {});
                          },
                          icon: Icon(obscureTextNewPass
                              ? Icons.visibility
                              : Icons.visibility_off)),
                      errorMaxLines: 3,
                      hintText: "Enter your new password",
                    ),
                    maxLength: null,
                    keyboardType: TextInputType.text,
                    obscureText: obscureTextNewPass,
                    // onFieldSubmitted: onFieldSubmitted,
                    textAlignVertical: TextAlignVertical.center,
                    // autofillHints: autofillHints,
                  ),
                  const SizedBox(height: 25),
                        
                  // //Confirm password
                  TextFormField(
                    autofillHints: const [AutofillHints.password],
                    controller: _confirmNewPasswordController,
                    style: TextStyle(color: Theme.of(context).disabledColor),
                    //   initialValue: initialValue,
                    enabled: true,
                    validator: (value) {
                      var valueNonNull = value ?? "";
                      if (valueNonNull != _newPasswordController.text) {
                        return "Password must match new password";
                      }
                      return null;
                    },
                    onChanged: (_) {},
                    autocorrect: false,
                    decoration: InputDecoration(
                      labelText: "Confirm new password",
                      prefixIcon: null,
                      prefixIconConstraints: const BoxConstraints(
                        minWidth: 40,
                        maxWidth: 70,
                      ),
                      suffixIcon: IconButton(
                          onPressed: () {
                            obscureTextNewPass = !obscureTextNewPass;
                            setState(() {});
                          },
                          icon: Icon(obscureTextNewPass
                              ? Icons.visibility
                              : Icons.visibility_off)),
                      errorMaxLines: 3,
                      hintText: "Re-enter your new password",
                    ),
                    maxLength: null,
                    keyboardType: TextInputType.text,
                    obscureText: obscureTextNewPass,
                    // onFieldSubmitted: onFieldSubmitted,
                    textAlignVertical: TextAlignVertical.center,
                    // autofillHints: autofillHints,
                  ),
                  const SizedBox(height: 30),
                        
                  SizedBox(
                      width: double.infinity,
                      child: ElevatedButton(
                          onPressed: () async {
                            if (_formKey.currentState!.validate()) {
                             
                              //TextInput.finishAutofillContext()
                              try {
                               // FocusManager.instance.primaryFocus?.unfocus();
                              //  await Amplify.Auth.updatePassword(
                              //          oldPassword:
                              //              _currentPasswordController.text,
                              //          newPassword:
                              //              _newPasswordController.text)
                              //      .then((value) { 
                                      TextInput.finishAutofillContext(shouldSave: true);
                                      
                                                
                                //                });
                              } catch (e) {
                                debugPrint(e.toString());
                                if (context.mounted) {
                                  
                                }
                              }
                            }
                          },
                          child: const Text("Change password"))),
                  const SizedBox(
                    height: 10,
                  ),
                  TextButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: const Text("Exit"))
                ],
              ),
            ),
          ),
        ),
      ),
    );
```

</details>


### Screenshots or Video

<details open>
<summary>Screenshots / Video demonstration</summary>

[Upload media here]

</details>

https://github.com/flutter/flutter/assets/44074596/37b99459-d0cd-4291-b129-deb938cdf16d


https://github.com/flutter/flutter/assets/44074596/6b4aabd6-caca-4d50-a1e4-96abfd26ddc4



### Logs

<details open><summary>Logs</summary>

```console
[Paste your logs here]
```

</details>


### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.19.5, on macOS 14.4.1 23E224 darwin-arm64, locale en-CA)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.2)
[✓] VS Code (version 1.88.1)
[✓] Connected device (3 available)
[✓] Network resources

• No issues found!
```

</details>