Flutter: FutureBuilder for progress indicator in a dialog

55 Views Asked by At

I'm struggling with Flutter's FutureBuilder. What I would like to achieve is the following:

  • open up a login dialog upon pressing button (works)
  • after entering credentials and pressing "Ok", show the progress indicator while the web service is called
  • upon retrieving a response from the web service, close the dialog in case of success, otherwise show an error message

I have configured the web service with a delay of 3 seconds, so I can watch the progress indicator.

What happens at the moment is:

  • after pressing the login button, the progress indicator shows for the 3 seconds delay, only then the logon dialog appears
  • when entering user name and password, after each single character entered the login dialog (and the keypad) disappears and the progress indicator shows for 3 seconds instead, then the login dialog shows again and the next character can be entered
  • finally, login procedure is working, but no progress indicator is shown while the web service is called

After reading all kinds of documentation, I'm under the impression that the FutureBuilder can only handle a future that is called once in the initState method. In my case, the peculiar thing is that I'm calling the future method upon pressing the Ok-button, and I'm specifying this future in the FutureBuilder's "future" parameter as well. Is this even valid or possible?

Unfortunately, I couldn't find any example for what I'm intending to do. I would be very grateful for some hints. Thanks a lot in advance!

The login dialog is called from the appbar like so:

IconButton(
    icon: const Icon(Icons.login_rounded),
    onPressed: () async {
        showDialog(
            context: context,
            builder: (_) => const LoginDialog()).then((tokenResponse) async {
                          // further actions tbd...
            });
    },
)

The login dialog:

class LoginDialog extends StatefulWidget {
  const LoginDialog({Key? key}) : super(key: key);

  @override
  LoginDialogState createState() {
    return LoginDialogState();
  }
}

class LoginDialogState extends State<LoginDialog> {
  final _formKey = GlobalKey<FormState>();

  final TextEditingController _userNameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  String userName = "";
  String password = "";

  var logger = Logger();

  final WebServiceUtil _webServiceUtil = WebServiceUtil();

  Future login(String userName, String password) async {
    dynamic responseObject;
    try {
      responseObject = await _webServiceUtil.login(userName, password);
    } on Exception catch (e) {
      // exception handling tbd...
    }
    return responseObject;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: login(userName, password),
        builder: (_, dataSnapshot) {
          if (dataSnapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else {
            return AlertDialog(
              titlePadding: AppConstants.dialogTitlePadding,
              contentPadding: AppConstants.dialogContentPadding,
              elevation: AppConstants.dialogElevation,
              insetPadding: AppConstants.dialogInsetPadding,
              title: Text(AppLocalizations.of(context)!.login),
              content: SingleChildScrollView(
                  child: Form(
                      key: _formKey,
                      child:
                          ListBody(mainAxis: Axis.vertical, children: <Widget>[
                        Text(AppLocalizations.of(context)!.loginText),
                        // the following methods called are simply creating 
                        // text form fields with validators:
                        _buildUserNameTextField(),
                        _buildPasswordTextField()
                      ]))),
              actions: <Widget>[
                TextButton(
                  child: Text(AppLocalizations.of(context)!.cancel),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
                TextButton(
                    child: Text(AppLocalizations.of(context)!.ok),
                    onPressed: () async {
                      if (_formKey.currentState!.validate()) {
                        dynamic responseObject = await login(userName, password);
                        // further actions...
                      }
                    }),
              ],
            );
          }
        });
  }

}
0

There are 0 best solutions below