scrollByViewport method

Future<CockpitScrollStepResult> scrollByViewport({
  1. bool reverse = false,
  2. double viewportFraction = 0.8,
  3. String? scrollableKey,
  4. CockpitLocator? targetLocator,
  5. CockpitLocator? scrollableLocator,
  6. Duration duration = const Duration(milliseconds: 220),
  7. CockpitGestureProfile gestureProfile = CockpitGestureProfile.userLike,
  8. bool continuous = false,
  9. bool postScrollEnsureVisible = true,
  10. bool probeDuringScroll = true,
})

Implementation

Future<CockpitScrollStepResult> scrollByViewport({
  bool reverse = false,
  double viewportFraction = 0.8,
  String? scrollableKey,
  CockpitLocator? targetLocator,
  CockpitLocator? scrollableLocator,
  Duration duration = const Duration(milliseconds: 220),
  CockpitGestureProfile gestureProfile = CockpitGestureProfile.userLike,
  bool continuous = false,
  bool postScrollEnsureVisible = true,
  bool probeDuringScroll = true,
}) async {
  final rootContext = _boundaryKey.currentContext;
  if (rootContext == null) {
    return const CockpitScrollStepResult(didScroll: false);
  }

  final scrollables = _discoverScrollables(rootContext as Element)
      .where((candidate) {
        final position = candidate.state.position;
        if (!position.haveDimensions || position.maxScrollExtent <= 0) {
          return false;
        }
        if (scrollableKey == null || scrollableKey.isEmpty) {
          return true;
        }
        return candidate.keyValue == scrollableKey;
      })
      .toList(growable: false);
  if (scrollables.isEmpty) {
    return const CockpitScrollStepResult(didScroll: false);
  }

  final scrollable = _selectScrollableCandidate(
    scrollables,
    targetLocator: targetLocator,
    scrollableLocator: scrollableLocator,
  );
  if (scrollable == null) {
    return const CockpitScrollStepResult(didScroll: false);
  }

  final position = scrollable.state.position;
  final probeSegmentCount = probeDuringScroll
      ? _scrollProbeSegmentCount(
          targetLocator: targetLocator,
          viewportFraction: viewportFraction,
        )
      : 1;
  if (probeSegmentCount > 1) {
    final stepViewportFraction = viewportFraction / probeSegmentCount;
    final stepDuration = duration == Duration.zero
        ? Duration.zero
        : Duration(
            milliseconds: (duration.inMilliseconds / probeSegmentCount)
                .ceil()
                .clamp(1, duration.inMilliseconds),
          );
    final pixelsBeforeProbe = position.pixels;
    var didScroll = false;
    CockpitScrollStepResult? lastStep;

    for (var index = 0; index < probeSegmentCount; index += 1) {
      final stepResult = await _scrollScrollableByViewport(
        scrollable,
        reverse: reverse,
        viewportFraction: stepViewportFraction,
        duration: stepDuration,
        gestureProfile: gestureProfile,
        continuous: continuous,
        postScrollEnsureVisible: postScrollEnsureVisible,
        preferProgrammatic: true,
      );
      lastStep = stepResult;
      didScroll = didScroll || stepResult.didScroll;
      if (_locatorIsVisible(targetLocator)) {
        return _mergeProbeResult(
          base: stepResult,
          pixelsBefore: pixelsBeforeProbe,
          pixelsAfter: position.pixels,
          didScroll: didScroll,
        );
      }
      if (!stepResult.didScroll) {
        break;
      }
    }

    if (lastStep != null) {
      return _mergeProbeResult(
        base: lastStep,
        pixelsBefore: pixelsBeforeProbe,
        pixelsAfter: position.pixels,
        didScroll: didScroll,
      );
    }
  }

  return _scrollScrollableByViewport(
    scrollable,
    reverse: reverse,
    viewportFraction: viewportFraction,
    duration: duration,
    gestureProfile: gestureProfile,
    continuous: continuous,
    postScrollEnsureVisible: postScrollEnsureVisible,
  );
}