previous method

Future<void> previous()

Fetches a previous page of the items.

Implementation

Future<void> previous() async {
  if (_disposed) {
    return Future.value();
  }

  final bool locked = _previousGuard.isLocked;

  return _previousGuard.protect(() async {
    if (locked || _disposed) {
      return;
    }

    await _repeatUntilFulfilled(() async {
      Log.debug('previous()...', '$runtimeType');

      if (hasPrevious.isTrue && previousLoading.isFalse) {
        previousLoading.value = true;

        try {
          if (items.isNotEmpty) {
            try {
              final Page<T, C>? page = await Backoff.run(
                () =>
                    provider.before(onKey(items.first), startCursor, perPage),
                _cancelToken,
              );
              Log.debug(
                'previous()... fetched ${page?.edges.length} items',
                '$runtimeType',
              );

              final int before = items.length;
              for (var e in page?.edges ?? []) {
                items[onKey(e)] = e;
              }

              startCursor = page?.info.startCursor ?? startCursor;
              hasPrevious.value = page?.info.hasPrevious ?? hasPrevious.value;
              Log.debug('previous()... done', '$runtimeType');

              return page?.edges.take(max(0, items.length - before));
            } catch (e) {
              if (e is! OperationCanceledException) {
                rethrow;
              }
            }
          } else {
            Log.debug(
              'previous()... propagated to `around` due to items being empty',
              '$runtimeType',
            );
            await around();
          }
        } finally {
          previousLoading.value = false;
        }
      } else {
        Log.debug(
          'previous()... canceled due to `hasPrevious` being `true` ($hasPrevious) or `previousLoading` being false ($previousLoading)',
          '$runtimeType',
        );
      }

      return null;
    });
  });
}