waitFor method

Future<Context?> waitFor({
  1. required ID chatId,
  2. Duration? timeout,
  3. bool clearUnfulfilled = true,
  4. required bool filter(
    1. Update update
    ),
  5. String? handlerName,
})

Wait for any message from the user.

Possibly returns null if the listener has been cancelled before it completes. Otherwise, returns a Context object with the incoming update.

Implementation

Future<Context?> waitFor({
  required ID chatId,
  Duration? timeout,
  bool clearUnfulfilled = true,
  required bool Function(Update update) filter,
  String? handlerName,
}) async {
  final scopeName =
      handlerName == null ? "$name+${_getRandomID()}" : "$name+$handlerName";

  if (clearUnfulfilled) {
    await clear(chatId);
  }

  // Check if there's a listener already with the same name.
  if (_bot._handlerScopes.any((scope) {
    return scope.name == scopeName && scope.chatId == chatId;
  })) {
    // Cancel the previous listener.
    final prev = _subscriptionsList.firstWhere(
      (sub) => sub.scope == scopeName,
    );
    await prev.cancel();
    _subscriptionsList.remove(prev);
    _bot._handlerScopes.removeWhere((scope) => scope.name == scopeName);
    print('[Televerse] Warning: Conversation listener with the same name '
        'already exists. It has been removed.');
  }

  final completer = Completer<Context?>();
  StreamSubscription<Update>? subscription;

  subscription = _bot.updatesStream.listen((update) {
    final sameChat = _isSameChat(update, chatId);
    if (sameChat && filter(update)) {
      completer.complete(Context(_bot, update: update));
    }
  });

  _subscriptionsList.add(
    _ISubHelper(subscription, scopeName, completer),
  );

  _bot._handlerScopes.add(
    HandlerScope(
      isConversation: true,
      options: ScopeOptions(name: scopeName),
      predicate: (ctx) =>
          _isSameChat(ctx.update, chatId) && filter(ctx.update),
      types: UpdateType.values,
      chatId: chatId,
    ),
  );

  if (timeout != null) {
    Future.delayed(timeout, () {
      if (!completer.isCompleted) {
        completer.completeError(
          ConversationException(
            "Conversation request timed out.",
            ConversationExceptionType.timeout,
          ),
        );

        subscription?.cancel();
        _bot._handlerScopes.removeWhere((scope) => scope.name == scopeName);
      }
    });
  }

  final ctx = await completer.future;

  final s = _subscriptionsList.firstWhere(
    (sub) => sub.scope == scopeName,
  );
  _subscriptionsList.remove(s);
  subscription.cancel();
  _bot._handlerScopes.removeWhere((scope) => scope.name == scopeName);

  return ctx;
}