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 search = _scrollStepSearch(
    rootElement,
    scrollableKey: scrollableKey,
    targetLocator: targetLocator,
    scrollableLocator: scrollableLocator,
  );
  if (search.earlyResult case final CockpitScrollStepResult earlyResult) {
    return earlyResult;
  }
  final targetElement = search.targetElement;
  final selection = search.selection!;
  final scrollable = selection.candidate;
  final position = scrollable.state.position;

  var scrollResult = await _scrollScrollableByViewport(
    scrollable,
    scrollableRegistryTarget: search.registryTarget,
    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,
      scrollableRegistryTarget: search.registryTarget,
      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);
  // The pre-scroll resolution stays authoritative while its element remains
  // mounted; the full-tree re-probe only runs when the scroll actually
  // evicted the resolved element (lazy list rebuild).
  final resolvedTarget = targetLocator == null
      ? targetElement
      : targetElement != null && targetElement.mounted
      ? targetElement
      : _findResolvedElementForLocator(rootElement, targetLocator);
  final targetVisible =
      resolvedTarget != null && _elementIsFullyVisible(resolvedTarget);
  return _withScrollableSelection(
    scrollResult,
    selection,
    targetLocator: targetLocator,
    targetMounted: resolvedTarget != null,
    targetVisible: targetVisible,
  );
}