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 rootElement = rootContext as Element;
  final targetElement = targetLocator == null
      ? null
      : _findResolvedElementForLocator(rootElement, targetLocator);
  final scrollables =
      _scrollableCandidatesForSearch(
            rootElement,
            targetLocator: targetLocator,
            targetElement: targetElement,
          )
          .where((candidate) {
            final position = candidate.state.position;
            if (!position.haveDimensions || position.maxScrollExtent <= 0) {
              return false;
            }
            if (targetLocator != null &&
                !position.physics.allowUserScrolling) {
              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 selection = _selectScrollableCandidate(
    scrollables,
    targetLocator: targetLocator,
    targetElement: targetElement,
    scrollableLocator: scrollableLocator,
  );
  if (selection == null) {
    final targetMounted = targetElement != null;
    return CockpitScrollStepResult(
      didScroll: false,
      scrollableCandidateCount: scrollables.length,
      targetVisibilityObserved: targetLocator != null,
      targetMounted: targetMounted,
      targetVisible: targetMounted && _locatorIsVisible(targetLocator),
    );
  }
  final scrollable = selection.candidate;
  final position = scrollable.state.position;
  final targetAlreadyVisible = targetLocator?.kind == CockpitLocatorKind.route
      ? widget.routeName == targetLocator?.value
      : targetElement != null && _elementIsFullyVisible(targetElement);
  if (targetAlreadyVisible) {
    return _withScrollableSelection(
      CockpitScrollStepResult(
        didScroll: false,
        strategy: 'alreadyVisible',
        scrollableKey: scrollable.keyValue,
        scrollablePath: scrollable.path,
        scrollableTypeName: scrollable.typeName,
        pixelsBefore: position.pixels,
        pixelsAfter: position.pixels,
        nextPixels: position.pixels,
        minScrollExtent: position.minScrollExtent,
        maxScrollExtent: position.maxScrollExtent,
        viewportDimension: position.viewportDimension,
        acceptsUserOffset: position.physics.shouldAcceptUserOffset(position),
        allowsProgrammaticScroll: position.physics.allowUserScrolling,
        targetMounted: true,
        targetVisible: true,
      ),
      selection,
      targetLocator: targetLocator,
      targetMounted: targetElement != null,
    );
  }

  var scrollResult = await _scrollScrollableByViewport(
    scrollable,
    reverse: reverse,
    viewportFraction: viewportFraction,
    duration: duration,
    gestureProfile: gestureProfile,
    continuous: continuous,
    postScrollEnsureVisible: postScrollEnsureVisible,
    preferProgrammatic: probeDuringScroll && targetLocator != null,
  );
  if (probeDuringScroll && targetLocator != null) {
    await _settleAtomicRevealFrame();
  }
  if (!scrollResult.didScroll &&
      _scrollExtentExpanded(scrollResult, position, reverse: reverse)) {
    final expandedResult = await _scrollScrollableByViewport(
      scrollable,
      reverse: reverse,
      viewportFraction: viewportFraction,
      duration: duration,
      gestureProfile: gestureProfile,
      continuous: continuous,
      postScrollEnsureVisible: postScrollEnsureVisible,
      preferProgrammatic: probeDuringScroll && targetLocator != null,
    );
    scrollResult = _mergeExpandedScrollStep(scrollResult, expandedResult);
    if (probeDuringScroll && targetLocator != null) {
      await _settleAtomicRevealFrame();
    }
  }
  scrollResult = _refreshScrollExtents(scrollResult, position);
  final resolvedTarget = targetLocator == null
      ? targetElement
      : _findResolvedElementForLocator(rootElement, targetLocator);
  final targetVisible =
      resolvedTarget != null && _elementIsFullyVisible(resolvedTarget);
  return _withScrollableSelection(
    scrollResult,
    selection,
    targetLocator: targetLocator,
    targetMounted: resolvedTarget != null,
    targetVisible: targetVisible,
  );
}