Unverified Commit 14a406f8 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Show `RefreshIndicator` on top when scroll's axis direction is up (matching...

Show `RefreshIndicator` on top when scroll's axis direction is up (matching native behaviour) (#93779)
parent 9fa42753
......@@ -296,7 +296,8 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
// In this case, we don't want to trigger the refresh indicator.
return ((notification is ScrollStartNotification && notification.dragDetails != null)
|| (notification is ScrollUpdateNotification && notification.dragDetails != null && widget.triggerMode == RefreshIndicatorTriggerMode.anywhere))
&& notification.metrics.extentBefore == 0.0
&& (( notification.metrics.axisDirection == AxisDirection.up && notification.metrics.extentAfter == 0.0)
|| (notification.metrics.axisDirection == AxisDirection.down && notification.metrics.extentBefore == 0.0))
&& _mode == null
&& _start(notification.metrics.axisDirection);
}
......@@ -313,10 +314,8 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
bool? indicatorAtTopNow;
switch (notification.metrics.axisDirection) {
case AxisDirection.down:
indicatorAtTopNow = true;
break;
case AxisDirection.up:
indicatorAtTopNow = false;
indicatorAtTopNow = true;
break;
case AxisDirection.left:
case AxisDirection.right:
......@@ -328,10 +327,15 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
_dismiss(_RefreshIndicatorMode.canceled);
} else if (notification is ScrollUpdateNotification) {
if (_mode == _RefreshIndicatorMode.drag || _mode == _RefreshIndicatorMode.armed) {
if (notification.metrics.extentBefore > 0.0) {
if ((notification.metrics.axisDirection == AxisDirection.down && notification.metrics.extentBefore > 0.0)
|| (notification.metrics.axisDirection == AxisDirection.up && notification.metrics.extentAfter > 0.0)) {
_dismiss(_RefreshIndicatorMode.canceled);
} else {
_dragOffset = _dragOffset! - notification.scrollDelta!;
if (notification.metrics.axisDirection == AxisDirection.down) {
_dragOffset = _dragOffset! - notification.scrollDelta!;
} else if (notification.metrics.axisDirection == AxisDirection.up) {
_dragOffset = _dragOffset! + notification.scrollDelta!;
}
_checkDragOffset(notification.metrics.viewportDimension);
}
}
......@@ -343,7 +347,11 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
}
} else if (notification is OverscrollNotification) {
if (_mode == _RefreshIndicatorMode.drag || _mode == _RefreshIndicatorMode.armed) {
_dragOffset = _dragOffset! - notification.overscroll;
if (notification.metrics.axisDirection == AxisDirection.down) {
_dragOffset = _dragOffset! - notification.overscroll;
} else if (notification.metrics.axisDirection == AxisDirection.up) {
_dragOffset = _dragOffset! + notification.overscroll;
}
_checkDragOffset(notification.metrics.viewportDimension);
}
} else if (notification is ScrollEndNotification) {
......@@ -382,10 +390,8 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS
assert(_dragOffset == null);
switch (direction) {
case AxisDirection.down:
_isIndicatorAtTop = true;
break;
case AxisDirection.up:
_isIndicatorAtTop = false;
_isIndicatorAtTop = true;
break;
case AxisDirection.left:
case AxisDirection.right:
......
......@@ -95,7 +95,7 @@ void main() {
expect(refreshCalled, true);
});
testWidgets('RefreshIndicator - bottom', (WidgetTester tester) async {
testWidgets('RefreshIndicator - reverse', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
MaterialApp(
......@@ -115,7 +115,7 @@ void main() {
),
);
await tester.fling(find.text('X'), const Offset(0.0, -300.0), 1000.0);
await tester.fling(find.text('X'), const Offset(0.0, 600.0), 1000.0);
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
......@@ -149,7 +149,7 @@ void main() {
expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0));
});
testWidgets('RefreshIndicator - bottom - position', (WidgetTester tester) async {
testWidgets('RefreshIndicator - reverse - position', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
MaterialApp(
......@@ -169,11 +169,11 @@ void main() {
),
);
await tester.fling(find.text('X'), const Offset(0.0, -300.0), 1000.0);
await tester.fling(find.text('X'), const Offset(0.0, 600.0), 1000.0);
await tester.pump();
await tester.pump(const Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, greaterThan(300.0));
expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0));
});
testWidgets('RefreshIndicator - no movement', (WidgetTester tester) async {
......@@ -612,7 +612,7 @@ void main() {
expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0));
});
testWidgets('Bottom RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async {
testWidgets('Reverse RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async {
refreshCalled = false;
final ScrollController scrollController = ScrollController();
await tester.pumpWidget(
......@@ -641,11 +641,11 @@ void main() {
scrollController.jumpTo(50.0);
await tester.fling(find.text('X'), const Offset(0.0, -300.0), 1000.0);
await tester.fling(find.text('X'), const Offset(0.0, 600.0), 1000.0);
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, greaterThan(300.0));
expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0));
});
// Regression test for https://github.com/flutter/flutter/issues/71936
......@@ -719,7 +719,7 @@ void main() {
expect(find.byType(RefreshProgressIndicator), findsNothing);
});
testWidgets('Bottom RefreshIndicator(onEdge mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async {
testWidgets('Reverse RefreshIndicator(onEdge mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async {
refreshCalled = false;
final ScrollController scrollController = ScrollController();
await tester.pumpWidget(
......@@ -817,7 +817,7 @@ void main() {
),
);
await tester.fling(find.text('X'), const Offset(0.0, -300.0), 1000.0);
await tester.fling(find.text('X'), const Offset(0.0, 600.0), 1000.0);
await tester.pump();
expect(tester.widget<RefreshProgressIndicator>(find.byType(RefreshProgressIndicator)).valueColor!.value, primaryColor);
});
......@@ -857,7 +857,7 @@ void main() {
),
);
await tester.fling(find.text('X'), const Offset(0.0, -300.0), 1000.0);
await tester.fling(find.text('X'), const Offset(0.0, 600.0), 1000.0);
await tester.pump();
expect(tester.widget<RefreshProgressIndicator>(find.byType(RefreshProgressIndicator)).valueColor!.value, refreshIndicatorColor.withOpacity(1.0));
......@@ -868,4 +868,38 @@ void main() {
await tester.pump();
expect(tester.widget<RefreshProgressIndicator>(find.byType(RefreshProgressIndicator)).valueColor!.value, red.withOpacity(1.0));
});
testWidgets('RefreshIndicator - reverse - BouncingScrollPhysics', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
MaterialApp(
home: RefreshIndicator(
onRefresh: refresh,
child: ListView(
reverse: true,
physics: const BouncingScrollPhysics(),
children: <Widget>[
for (int i = 0; i < 4; i++)
SizedBox(
height: 200.0,
child: Text('X - $i'),
),
],
)
),
),
);
// Scroll to top
await tester.fling(find.text('X - 0'), const Offset(0.0, 800.0), 1000.0);
await tester.pumpAndSettle();
// Fling down to show refresh indicator
await tester.fling(find.text('X - 3'), const Offset(0.0, 250.0), 1000.0);
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // finish the scroll animation
await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation
await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation
expect(refreshCalled, true);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment