show second Dialog if someone does not input text into the first Dialog within a timefrate?

Issue

I have made a dialog appear which can be closed if someone correctly types in a certain word. I wanted to know if it was possible to make a second dialog appear if someone does not type anything into the first text box within a certain timeframe. For example, if the person does not input text within the next 5 minutes, is there any way to trigger a second dialog to show up?

      Future.delayed(Duration(seconds: 5), () {
        showDialog(
            context: context,
            barrierDismissible: false,
            builder: (context) {
              return AlertDialog(
                title: Text('Your time finished'),
                content: Text('Type "OKAY" if you want to go back to the homepage'),
                actions: <Widget>[
                  TextButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: TextFormField(
                        controller: _textEditingController,
                        validator: (String? word){
                          if (word != OKAY){
                            _NoDialog();
                          }
                          else{
                            Navigator.pop(context);
                          }
                        },
                      ),
                  ),
                ],
              );
            });
      });

I called the function NoDialog if the text the person gives is incorrect, but I am not sure how to make an ‘if’ statement if the person does not put anything in the text box for a certain period of time.
I think I could do an ‘if’ statement if the person leaves the text blank and then call a new function with a Future.delayed attached, but I couldnt find a way to make an ‘if’ statement for the case when no text is entered. Also in this case, I believe the person would have to hit the ‘enter’ key, but I want the second dialog to show up because the user has not touched anything on the screen. Is this possible?

Solution

In simple case, you can show nested-overlap dialog with passing same the build-context.

The First dialog will be

_userInputCheckerDialog({
    required BuildContext context,
    required String correctText,
    Duration maxTime = const Duration(seconds: 2),
  }) async {
    bool _noInteraction = true;

    /// apear if user doesnt type anything within
    Future.delayed(maxTime).then((t) async {
      if (_noInteraction) await _showSecondDialog(context);
    });
    await showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) {
        return StatefulBuilder(
          ///may need in future to change variable inside dialog
          builder: (context, setStateSB) {
            return AlertDialog(
              content: TextField(
                onChanged: (value) async {
                  _noInteraction = false;
                  if (value == correctText) {
                    Navigator.of(context)
                        .pop(); // close after getting currect text
                  }
                },
              ),
            );
          },
        );
      },
    );
  }

Then the inner dialog is having the same context

  _showSecondDialog(BuildContext context) async {
    await showDialog(
      context: context,
      builder: (context) => const AlertDialog(
        content: Text("Hey start typing"),
      ),
    );
  }

this is only checking 1st time of user interaction.

If you want to use timeframe, we need to use async package to cancel (not really cancelling) the future.
You might feel it a little more complicated than the 1st one.

Use async


  _showSecondDialog(BuildContext context) async {
    await showDialog(
      context: context,
      builder: (context) => const AlertDialog(
        content: Text("Hey start typing"),
      ),
    );
  }

  CancelableOperation _restartTimer({
    CancelableOperation? cancelableOperation,
    Duration duration = const Duration(seconds: 4),
    required BuildContext context,
  }) {
    if (cancelableOperation != null) {
      cancelableOperation.cancel();
      cancelableOperation = null;
    }
    cancelableOperation = CancelableOperation.fromFuture(
      Future.delayed(
        duration,
      ),
    ).then((p0) async {
      await _showSecondDialog(context);
    });

    return cancelableOperation;
  }

  _userInputCheckerDialog({
    required BuildContext context,
    required String correctText,
    Duration maxTime = const Duration(seconds: 2),
  }) async {
    CancelableOperation? _cancelableOperation;

    ///start timer at startUp
    _cancelableOperation = _restartTimer(
      context: context,
      cancelableOperation: _cancelableOperation,
      duration: maxTime,
    );

    await showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) {
        return StatefulBuilder(
          ///may need in future to change variable inside dialog
          builder: (context, setStateSB) {
            return AlertDialog(
              content: TextField(
                onChanged: (value) async {
                  _cancelableOperation = _restartTimer(
                      context: context,
                      cancelableOperation: _cancelableOperation);
                  if (value == correctText) {
                    _cancelableOperation!.cancel();
                    Navigator.of(context)
                        .pop(); // close after getting currect text
                  }
                },
              ),
            );
          },
        );
      },
    );
  }

Answered By – Yeasin Sheikh

Answer Checked By – Marilyn (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *