chore: linting

This commit is contained in:
Gordon Hayes
2021-10-18 10:51:06 +02:00
parent 3a7343904d
commit 51e0b90f94
12 changed files with 333 additions and 358 deletions
@@ -46,12 +46,12 @@ class _RegistryWidgetState extends State<RegistryWidget> {
}
class _InheritedRegistryWidget extends InheritedWidget {
final _RegistryWidgetState state;
const _InheritedRegistryWidget(
{Key? key, required this.state, required Widget child})
: super(key: key, child: child);
final _RegistryWidgetState state;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
}
@@ -2,10 +2,13 @@ import 'dart:ui' show hashValues;
import 'package:flutter/foundation.dart';
/// {@template indexed_key}
/// Creates an indexed key that delegates its [operator==] to the given key.
///
/// It contains an index used in [ScrollablePositionedList].
/// {@endtemplate}
class IndexedKey extends LocalKey {
/// Creates an indexed key that delegates its [operator==] to the given key.
///
/// It contains an index used in [ScrollablePositionedList].
/// {@macro indexed_key}
const IndexedKey(this.key, this.index);
/// The key to which this this delegates its [operator==].
@@ -24,7 +27,5 @@ class IndexedKey extends LocalKey {
int get hashCode => hashValues(runtimeType, key);
@override
String toString() {
return '(IndexedKey) index: $index, key: $key';
}
String toString() => '(IndexedKey) index: $index, key: $key';
}
@@ -4,8 +4,8 @@
import 'package:flutter/foundation.dart';
import 'item_positions_notifier.dart';
import 'scrollable_positioned_list.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/item_positions_notifier.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/scrollable_positioned_list.dart';
/// Provides a listenable iterable of [itemPositions] of items that are on
/// screen and their locations.
@@ -57,5 +57,5 @@ class ItemPosition {
@override
String toString() =>
'ItemPosition(index: $index, itemLeadingEdge: $itemLeadingEdge, itemTrailingEdge: $itemTrailingEdge)';
'''ItemPosition(index: $index, itemLeadingEdge: $itemLeadingEdge, itemTrailingEdge: $itemTrailingEdge)''';
}
@@ -4,7 +4,7 @@
import 'package:flutter/foundation.dart';
import 'item_positions_listener.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/item_positions_listener.dart';
/// Internal implementation of [ItemPositionsListener].
class ItemPositionsNotifier implements ItemPositionsListener {
@@ -8,11 +8,11 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'element_registry.dart';
import 'indexed_key.dart';
import 'item_positions_listener.dart';
import 'item_positions_notifier.dart';
import 'scroll_view.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/element_registry.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/indexed_key.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/item_positions_listener.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/item_positions_notifier.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/scroll_view.dart';
/// A list of widgets similar to [ListView], except scroll control
/// and position reporting is based on index rather than pixel offset.
@@ -27,6 +27,7 @@ import 'scroll_view.dart';
class PositionedList extends StatefulWidget {
/// Create a [PositionedList].
const PositionedList({
Key? key,
required this.itemCount,
required this.itemBuilder,
this.separatorBuilder,
@@ -44,11 +45,12 @@ class PositionedList extends StatefulWidget {
this.addSemanticIndexes = true,
this.addRepaintBoundaries = true,
this.addAutomaticKeepAlives = true,
}) : assert(itemCount != null),
assert(itemBuilder != null),
assert((positionedIndex == 0) || (positionedIndex < itemCount));
}) : assert((positionedIndex == 0) || (positionedIndex < itemCount),
'positionedIndex cannot be 0 and must be smaller than itemCount'),
super(key: key);
/// Called to find the new index of a child based on its key in case of reordering.
/// Called to find the new index of a child based on its key in case of
/// reordering.
///
/// If not provided, a child widget may not map to its existing [RenderObject]
/// when the order in which children are returned from [builder] changes.
@@ -263,7 +265,7 @@ class _PositionedListState extends State<PositionedList> {
: widget.reverse
? widget.padding?.copyWith(left: 0)
: widget.padding?.copyWith(right: 0)) ??
EdgeInsets.all(0);
const EdgeInsets.all(0);
EdgeInsets get _centerSliverPadding => widget.scrollDirection == Axis.vertical
? widget.reverse
@@ -274,13 +276,13 @@ class _PositionedListState extends State<PositionedList> {
bottom: widget.positionedIndex == 0
? widget.padding!.bottom
: 0) ??
EdgeInsets.all(0)
const EdgeInsets.all(0)
: widget.padding?.copyWith(
top: widget.positionedIndex == 0 ? widget.padding!.top : 0,
bottom: widget.positionedIndex == widget.itemCount - 1
? widget.padding!.bottom
: 0) ??
EdgeInsets.all(0)
const EdgeInsets.all(0)
: widget.reverse
? widget.padding?.copyWith(
left: widget.positionedIndex == widget.itemCount - 1
@@ -289,23 +291,23 @@ class _PositionedListState extends State<PositionedList> {
right: widget.positionedIndex == 0
? widget.padding!.right
: 0) ??
EdgeInsets.all(0)
const EdgeInsets.all(0)
: widget.padding?.copyWith(
left: widget.positionedIndex == 0 ? widget.padding!.left : 0,
right: widget.positionedIndex == widget.itemCount - 1
? widget.padding!.right
: 0,
) ??
EdgeInsets.all(0);
const EdgeInsets.all(0);
EdgeInsets get _trailingSliverPadding =>
widget.scrollDirection == Axis.vertical
? widget.reverse
? widget.padding?.copyWith(bottom: 0) ?? EdgeInsets.all(0)
: widget.padding?.copyWith(top: 0) ?? EdgeInsets.all(0)
? widget.padding?.copyWith(bottom: 0) ?? const EdgeInsets.all(0)
: widget.padding?.copyWith(top: 0) ?? const EdgeInsets.all(0)
: widget.reverse
? widget.padding?.copyWith(right: 0) ?? EdgeInsets.all(0)
: widget.padding?.copyWith(left: 0) ?? EdgeInsets.all(0);
? widget.padding?.copyWith(right: 0) ?? const EdgeInsets.all(0)
: widget.padding?.copyWith(left: 0) ?? const EdgeInsets.all(0);
void _schedulePositionNotificationUpdate() {
if (!updateScheduled) {
@@ -317,10 +319,10 @@ class _PositionedListState extends State<PositionedList> {
}
final positions = <ItemPosition>[];
RenderViewport? viewport;
for (var element in registeredElements.value!) {
final RenderBox box = element.renderObject as RenderBox;
for (final element in registeredElements.value!) {
final box = element.renderObject as RenderBox;
viewport ??= RenderAbstractViewport.of(box) as RenderViewport?;
final IndexedKey key = element.widget.key as IndexedKey;
final key = element.widget.key as IndexedKey;
if (widget.scrollDirection == Axis.vertical) {
final reveal = viewport!.getOffsetToReveal(box, 0).offset;
final itemOffset = reveal -
@@ -29,7 +29,7 @@ class _PostMountCallbackElement extends StatelessElement {
@override
void mount(Element? parent, dynamic newSlot) {
super.mount(parent, newSlot);
final PostMountCallback postMountCallback = widget as PostMountCallback;
final postMountCallback = widget as PostMountCallback;
postMountCallback.callback?.call();
}
}
@@ -6,11 +6,14 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'viewport.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/viewport.dart';
/// A version of [CustomScrollView] that allows does not constrict the extents
/// {@template custom_scroll_view}
/// A version of [CustomScrollView] that does not constrict the extents
/// to be within 0 and 1. See [CustomScrollView] for more information.
/// {@endtemplate}
class UnboundedCustomScrollView extends CustomScrollView {
/// {@macro custom_scroll_view}
const UnboundedCustomScrollView({
Key? key,
Axis scrollDirection = Axis.vertical,
@@ -10,10 +10,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'item_positions_listener.dart';
import 'item_positions_notifier.dart';
import 'positioned_list.dart';
import 'post_mount_callback.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/item_positions_listener.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/item_positions_notifier.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/positioned_list.dart';
import 'package:stream_chat_flutter/src/scrollable_positioned_list/src/post_mount_callback.dart';
/// Number of screens to scroll when scrolling a long distance.
const int _screenScrollCount = 2;
@@ -52,9 +52,7 @@ class ScrollablePositionedList extends StatefulWidget {
this.addRepaintBoundaries = true,
this.minCacheExtent,
this.findChildIndexCallback,
}) : assert(itemCount != null),
assert(itemBuilder != null),
itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?,
}) : itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?,
separatorBuilder = null,
super(key: key);
@@ -79,13 +77,12 @@ class ScrollablePositionedList extends StatefulWidget {
this.addRepaintBoundaries = true,
this.minCacheExtent,
this.findChildIndexCallback,
}) : assert(itemCount != null),
assert(itemBuilder != null),
assert(separatorBuilder != null),
}) : assert(separatorBuilder != null, 'seperatorBuilder cannot be null'),
itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?,
super(key: key);
/// Called to find the new index of a child based on its key in case of reordering.
/// Called to find the new index of a child based on its key in case of
/// reordering.
///
/// If not provided, a child widget may not map to its existing [RenderObject]
/// when the order in which children are returned from [builder] changes.
@@ -235,9 +232,11 @@ class ItemScrollController {
Curve curve = Curves.linear,
List<double> opacityAnimationWeights = const [40, 20, 40],
}) {
assert(_scrollableListState != null);
assert(opacityAnimationWeights.length == 3);
assert(duration > Duration.zero);
assert(_scrollableListState != null, '_scrollableListState cannot be null');
assert(opacityAnimationWeights.length == 3,
'opacityAnimationWeights.length is not equal to 3');
assert(duration > Duration.zero,
'duration needs to be bigger than Duration.zero');
return _scrollableListState!._scrollTo(
index: index,
alignment: alignment,
@@ -248,7 +247,8 @@ class ItemScrollController {
}
void _attach(_ScrollablePositionedListState scrollableListState) {
assert(_scrollableListState == null);
assert(
_scrollableListState == null, '_scrollableListState needs to be null');
_scrollableListState = scrollableListState;
}
@@ -260,11 +260,11 @@ class ItemScrollController {
class _ScrollablePositionedListState extends State<ScrollablePositionedList>
with TickerProviderStateMixin {
/// Details for the primary (active) [ListView].
var primary = _ListDisplayDetails(const ValueKey('Ping'));
_ListDisplayDetails primary = _ListDisplayDetails(const ValueKey('Ping'));
/// Details for the secondary (transitional) [ListView] that is temporarily
/// shown when scrolling a long distance.
var secondary = _ListDisplayDetails(const ValueKey('Pong'));
_ListDisplayDetails secondary = _ListDisplayDetails(const ValueKey('Pong'));
final opacity = ProxyAnimation(const AlwaysStoppedAnimation<double>(0));
@@ -275,10 +275,11 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
@override
void initState() {
super.initState();
ItemPosition? initialPosition = PageStorage.of(context)!.readState(context);
primary.target = initialPosition?.index ?? widget.initialScrollIndex;
primary.alignment =
initialPosition?.itemLeadingEdge ?? widget.initialAlignment;
final ItemPosition? initialPosition =
PageStorage.of(context)!.readState(context);
primary
..target = initialPosition?.index ?? widget.initialScrollIndex
..alignment = initialPosition?.itemLeadingEdge ?? widget.initialAlignment;
if (widget.itemCount > 0 && primary.target > widget.itemCount - 1) {
primary.target = widget.itemCount - 1;
}
@@ -333,79 +334,78 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final cacheExtent = _cacheExtent(constraints);
return GestureDetector(
onPanDown: (_) => _stopScroll(canceled: true),
excludeFromSemantics: true,
child: Stack(
children: <Widget>[
PostMountCallback(
key: primary.key,
callback: startAnimationCallback,
child: FadeTransition(
opacity: ReverseAnimation(opacity),
child: NotificationListener<ScrollNotification>(
onNotification: (_) => _isTransitioning,
child: PositionedList(
itemBuilder: widget.itemBuilder,
separatorBuilder: widget.separatorBuilder,
itemCount: widget.itemCount,
positionedIndex: primary.target,
controller: primary.scrollController,
itemPositionsNotifier: primary.itemPositionsNotifier,
scrollDirection: widget.scrollDirection,
reverse: widget.reverse,
cacheExtent: cacheExtent,
alignment: primary.alignment,
physics: widget.physics,
addSemanticIndexes: widget.addSemanticIndexes,
semanticChildCount: widget.semanticChildCount,
padding: widget.padding,
addAutomaticKeepAlives: widget.addAutomaticKeepAlives,
addRepaintBoundaries: widget.addRepaintBoundaries,
findChildIndexCallback: widget.findChildIndexCallback,
),
),
),
),
if (_isTransitioning)
Widget build(BuildContext context) => LayoutBuilder(
builder: (context, constraints) {
final cacheExtent = _cacheExtent(constraints);
return GestureDetector(
onPanDown: (_) => _stopScroll(canceled: true),
excludeFromSemantics: true,
child: Stack(
children: <Widget>[
PostMountCallback(
key: secondary.key,
key: primary.key,
callback: startAnimationCallback,
child: FadeTransition(
opacity: opacity,
opacity: ReverseAnimation(opacity),
child: NotificationListener<ScrollNotification>(
onNotification: (_) => false,
onNotification: (_) => _isTransitioning,
child: PositionedList(
itemBuilder: widget.itemBuilder,
separatorBuilder: widget.separatorBuilder,
itemCount: widget.itemCount,
itemPositionsNotifier: secondary.itemPositionsNotifier,
positionedIndex: secondary.target,
controller: secondary.scrollController,
positionedIndex: primary.target,
controller: primary.scrollController,
itemPositionsNotifier: primary.itemPositionsNotifier,
scrollDirection: widget.scrollDirection,
reverse: widget.reverse,
cacheExtent: cacheExtent,
alignment: secondary.alignment,
alignment: primary.alignment,
physics: widget.physics,
addSemanticIndexes: widget.addSemanticIndexes,
semanticChildCount: widget.semanticChildCount,
padding: widget.padding,
addAutomaticKeepAlives: widget.addAutomaticKeepAlives,
addRepaintBoundaries: widget.addRepaintBoundaries,
findChildIndexCallback: widget.findChildIndexCallback,
),
),
),
),
],
),
);
},
);
}
if (_isTransitioning)
PostMountCallback(
key: secondary.key,
callback: startAnimationCallback,
child: FadeTransition(
opacity: opacity,
child: NotificationListener<ScrollNotification>(
onNotification: (_) => false,
child: PositionedList(
itemBuilder: widget.itemBuilder,
separatorBuilder: widget.separatorBuilder,
itemCount: widget.itemCount,
itemPositionsNotifier:
secondary.itemPositionsNotifier,
positionedIndex: secondary.target,
controller: secondary.scrollController,
scrollDirection: widget.scrollDirection,
reverse: widget.reverse,
cacheExtent: cacheExtent,
alignment: secondary.alignment,
physics: widget.physics,
addSemanticIndexes: widget.addSemanticIndexes,
semanticChildCount: widget.semanticChildCount,
padding: widget.padding,
addAutomaticKeepAlives: widget.addAutomaticKeepAlives,
addRepaintBoundaries: widget.addRepaintBoundaries,
),
),
),
),
],
),
);
},
);
double _cacheExtent(BoxConstraints constraints) => max(
constraints.maxHeight * _screenScrollCount,
@@ -419,8 +419,9 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
}
setState(() {
primary.scrollController.jumpTo(0);
primary.target = index;
primary.alignment = alignment;
primary
..target = index
..alignment = alignment;
});
}
@@ -505,8 +506,9 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
setState(() {
// TODO: _startScroll can be re-entrant, which invalidates this assert.
// assert(!_isTransitioning);
secondary.target = index;
secondary.alignment = alignment;
secondary
..target = index
..alignment = alignment;
_isTransitioning = true;
});
await Future.wait<void>([startCompleter.future, endCompleter.future]);
@@ -532,7 +534,7 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
if (opacity.value >= 0.5) {
// Secondary [ListView] is more visible than the primary; make it the
// new primary.
var temp = primary;
final temp = primary;
primary = secondary;
secondary = temp;
}
@@ -542,8 +544,8 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
}
Animatable<double> _opacityAnimation(List<double> opacityAnimationWeights) {
final startOpacity = 0.0;
final endOpacity = 1.0;
const startOpacity = 0.0;
const endOpacity = 1.0;
return TweenSequence<double>(<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: ConstantTween<double>(startOpacity),
@@ -2,17 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: lines_longer_than_80_chars
import 'dart:math' as math;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
/// {@template unbounded_viewport}
/// A render object that is bigger on the inside.
///
/// Version of [Viewport] with some modifications to how extents are
/// computed to allow scroll extents outside 0 to 1. See [Viewport]
/// for more information.
/// description
class UnboundedViewport extends Viewport {
/// {@macro unbounded_viewport}
UnboundedViewport({
Key? key,
AxisDirection axisDirection = AxisDirection.down,
@@ -40,16 +45,15 @@ class UnboundedViewport extends Viewport {
double get anchor => _anchor;
@override
RenderViewport createRenderObject(BuildContext context) {
return UnboundedRenderViewport(
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection ??
Viewport.getDefaultCrossAxisDirection(context, axisDirection),
anchor: anchor,
offset: offset,
cacheExtent: cacheExtent,
);
}
RenderViewport createRenderObject(BuildContext context) =>
UnboundedRenderViewport(
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection ??
Viewport.getDefaultCrossAxisDirection(context, axisDirection),
anchor: anchor,
offset: offset,
cacheExtent: cacheExtent,
);
}
/// A render object that is bigger on the inside.
@@ -100,7 +104,6 @@ class UnboundedRenderViewport extends RenderViewport {
@override
set anchor(double value) {
assert(value != null);
if (value == _anchor) return;
_anchor = value;
markNeedsLayout();
@@ -124,8 +127,6 @@ class UnboundedRenderViewport extends RenderViewport {
@override
Rect describeSemanticsClip(RenderSliver? child) {
assert(axis != null);
if (_calculatedCacheExtent == null) {
return semanticBounds;
}
@@ -151,14 +152,14 @@ class UnboundedRenderViewport extends RenderViewport {
@override
void performLayout() {
if (center == null) {
assert(firstChild == null);
assert(firstChild == null, 'firstChild cannot be null');
_minScrollExtent = 0.0;
_maxScrollExtent = 0.0;
_hasVisualOverflow = false;
offset.applyContentDimensions(0.0, 0.0);
offset.applyContentDimensions(0, 0);
return;
}
assert(center!.parent == this);
assert(center!.parent == this, 'center.parent cannot be equal to this');
late double mainAxisExtent;
late double crossAxisExtent;
@@ -178,7 +179,6 @@ class UnboundedRenderViewport extends RenderViewport {
double correction;
var count = 0;
do {
assert(offset.pixels != null);
correction = _attemptLayout(mainAxisExtent, crossAxisExtent,
offset.pixels + centerOffsetAdjustment);
if (correction != 0.0) {
@@ -187,17 +187,18 @@ class UnboundedRenderViewport extends RenderViewport {
// *** Difference from [RenderViewport].
final top = _minScrollExtent + mainAxisExtent * anchor;
final bottom = _maxScrollExtent - mainAxisExtent * (1.0 - anchor);
final maxScrollOffset = math.max(math.min(0.0, top), bottom);
final minScrollOffset = math.min(top, maxScrollOffset);
if (offset.applyContentDimensions(minScrollOffset, maxScrollOffset))
final maxScrollOffset = math.max<double>(math.min(0, top), bottom);
final minScrollOffset = math.min<double>(top, maxScrollOffset);
if (offset.applyContentDimensions(minScrollOffset, maxScrollOffset)) {
break;
}
// *** End of difference from [RenderViewport].
}
count += 1;
} while (count < _maxLayoutCycles);
assert(() {
if (count >= _maxLayoutCycles) {
assert(count != 1);
assert(count != 1, 'count not equal to 1');
throw FlutterError(
'A RenderViewport exceeded its maximum number of layout cycles.\n'
'RenderViewport render objects, during layout, can retry if either their '
@@ -217,16 +218,16 @@ class UnboundedRenderViewport extends RenderViewport {
' layout passes.');
}
return true;
}());
}(), 'count needs to be bigger than _maxLayoutCycles');
}
double _attemptLayout(
double mainAxisExtent, double crossAxisExtent, double correctedOffset) {
assert(!mainAxisExtent.isNaN);
assert(mainAxisExtent >= 0.0);
assert(crossAxisExtent.isFinite);
assert(crossAxisExtent >= 0.0);
assert(correctedOffset.isFinite);
assert(!mainAxisExtent.isNaN, 'assert mainAxisExtent.isNaN');
assert(mainAxisExtent >= 0.0, 'assert mainAxisExtent >= 0.0');
assert(crossAxisExtent.isFinite, 'assert crossAxisExtent.isFinite');
assert(crossAxisExtent >= 0.0, 'assert crossAxisExtent >= 0.0');
assert(correctedOffset.isFinite, 'assert correctedOffset.isFinite');
_minScrollExtent = 0.0;
_maxScrollExtent = 0.0;
_hasVisualOverflow = false;
@@ -234,10 +235,10 @@ class UnboundedRenderViewport extends RenderViewport {
// centerOffset is the offset from the leading edge of the RenderViewport
// to the zero scroll offset (the line between the forward slivers and the
// reverse slivers).
final double centerOffset = mainAxisExtent * anchor - correctedOffset;
final double reverseDirectionRemainingPaintExtent =
final centerOffset = mainAxisExtent * anchor - correctedOffset;
final reverseDirectionRemainingPaintExtent =
centerOffset.clamp(0.0, mainAxisExtent);
final double forwardDirectionRemainingPaintExtent =
final forwardDirectionRemainingPaintExtent =
(mainAxisExtent - centerOffset).clamp(0.0, mainAxisExtent);
switch (cacheExtentStyle) {
@@ -249,21 +250,21 @@ class UnboundedRenderViewport extends RenderViewport {
break;
}
final double fullCacheExtent = mainAxisExtent + 2 * _calculatedCacheExtent!;
final double centerCacheOffset = centerOffset + _calculatedCacheExtent!;
final double reverseDirectionRemainingCacheExtent =
final fullCacheExtent = mainAxisExtent + 2 * _calculatedCacheExtent!;
final centerCacheOffset = centerOffset + _calculatedCacheExtent!;
final reverseDirectionRemainingCacheExtent =
centerCacheOffset.clamp(0.0, fullCacheExtent);
final double forwardDirectionRemainingCacheExtent =
final forwardDirectionRemainingCacheExtent =
(fullCacheExtent - centerCacheOffset).clamp(0.0, fullCacheExtent);
final RenderSliver? leadingNegativeChild = childBefore(center!);
final leadingNegativeChild = childBefore(center!);
if (leadingNegativeChild != null) {
// negative scroll offsets
final double result = layoutChildSequence(
final result = layoutChildSequence(
child: leadingNegativeChild,
scrollOffset: math.max(mainAxisExtent, centerOffset) - mainAxisExtent,
overlap: 0.0,
overlap: 0,
layoutOffset: forwardDirectionRemainingPaintExtent,
remainingPaintExtent: reverseDirectionRemainingPaintExtent,
mainAxisExtent: mainAxisExtent,
@@ -280,9 +281,8 @@ class UnboundedRenderViewport extends RenderViewport {
// positive scroll offsets
return layoutChildSequence(
child: center,
scrollOffset: math.max(0.0, -centerOffset),
overlap:
leadingNegativeChild == null ? math.min(0.0, -centerOffset) : 0.0,
scrollOffset: math.max(0, -centerOffset),
overlap: leadingNegativeChild == null ? math.min(0, -centerOffset) : 0.0,
layoutOffset: centerOffset >= mainAxisExtent
? centerOffset
: reverseDirectionRemainingPaintExtent,