Commit 47e52b82 authored by Ankur Kedia's avatar Ankur Kedia Committed by Ian Hickson

adds properties to dismissible widget (#14162)

* adds crossAxisEndOffset and rollbackDuration properties to dismissible widget

* re-added removed license comment

* corrected license comments

* Adds test for rollbackDuration and crossAxisEndOffset

* added tests and comments

* modified tests for dismissible widgets
parent c54fab04
......@@ -12,7 +12,6 @@ import 'gesture_detector.dart';
import 'ticker_provider.dart';
import 'transitions.dart';
const Duration _kDismissDuration = const Duration(milliseconds: 200);
const Curve _kResizeTimeCurve = const Interval(0.4, 1.0, curve: Curves.ease);
const double _kMinFlingVelocity = 700.0;
const double _kMinFlingVelocityDelta = 400.0;
......@@ -83,6 +82,8 @@ class Dismissible extends StatefulWidget {
this.direction: DismissDirection.horizontal,
this.resizeDuration: const Duration(milliseconds: 300),
this.dismissThresholds: const <DismissDirection, double>{},
this.movementDuration: const Duration(milliseconds: 200),
this.crossAxisEndOffset: 0.0,
}) : assert(key != null),
assert(secondaryBackground != null ? background != null : true),
super(key: key);
......@@ -134,6 +135,15 @@ class Dismissible extends StatefulWidget {
/// [direction] property.
final Map<DismissDirection, double> dismissThresholds;
/// Defines the duration for card to dismiss or to come back to original position if not dismissed.
final Duration movementDuration;
/// Defines the end offset across the main axis after the card is dismissed.
///
/// If non-zero value is given then widget moves in cross direction depending on whether
/// it is positive or negative.
final double crossAxisEndOffset;
@override
_DismissibleState createState() => new _DismissibleState();
}
......@@ -183,7 +193,7 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
@override
void initState() {
super.initState();
_moveController = new AnimationController(duration: _kDismissDuration, vsync: this)
_moveController = new AnimationController(duration: widget.movementDuration, vsync: this)
..addStatusListener(_handleDismissStatusChanged);
_updateMoveAnimation();
}
......@@ -317,7 +327,9 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
final double end = _dragExtent.sign;
_moveAnimation = new Tween<Offset>(
begin: Offset.zero,
end: _directionIsXAxis ? new Offset(end, 0.0) : new Offset(0.0, end),
end: _directionIsXAxis
? new Offset(end, widget.crossAxisEndOffset)
: new Offset(widget.crossAxisEndOffset, end),
).animate(_moveController);
}
......@@ -513,3 +525,4 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
);
}
}
......@@ -13,6 +13,7 @@ DismissDirection dismissDirection = DismissDirection.horizontal;
DismissDirection reportedDismissDirection;
List<int> dismissedItems = <int>[];
Widget background;
const double crossAxisEndOffset = 0.5;
Widget buildTest({ double startToEndThreshold, TextDirection textDirection: TextDirection.ltr }) {
return new Directionality(
......@@ -37,6 +38,7 @@ Widget buildTest({ double startToEndThreshold, TextDirection textDirection: Text
dismissThresholds: startToEndThreshold == null
? <DismissDirection, double>{}
: <DismissDirection, double>{DismissDirection.startToEnd: startToEndThreshold},
crossAxisEndOffset: crossAxisEndOffset,
child: new Container(
width: itemExtent,
height: itemExtent,
......@@ -143,6 +145,53 @@ Future<Null> dismissItem(WidgetTester tester, int item, {
await tester.pump(); // rebuild after the callback removes the entry
}
Future<Null> checkFlingItemBeforeMovementEnd(WidgetTester tester, int item, {
@required AxisDirection gestureDirection,
DismissMethod mechanism: rollbackElement
}) async {
assert(gestureDirection != null);
final Finder itemFinder = find.text(item.toString());
expect(itemFinder, findsOneWidget);
await mechanism(tester, itemFinder, gestureDirection: gestureDirection);
await tester.pump(); // start the slide
await tester.pump(const Duration(milliseconds: 100));
}
Future<Null> checkFlingItemAfterMovement(WidgetTester tester, int item, {
@required AxisDirection gestureDirection,
DismissMethod mechanism: rollbackElement
}) async {
assert(gestureDirection != null);
final Finder itemFinder = find.text(item.toString());
expect(itemFinder, findsOneWidget);
await mechanism(tester, itemFinder, gestureDirection: gestureDirection);
await tester.pump(); // start the slide
await tester.pump(const Duration(milliseconds: 300));
}
Future<Null> rollbackElement(WidgetTester tester, Finder finder, { @required AxisDirection gestureDirection, double initialOffsetFactor: 0.0 }) async {
Offset delta;
switch (gestureDirection) {
case AxisDirection.left:
delta = const Offset(-30.0, 0.0);
break;
case AxisDirection.right:
delta = const Offset(30.0, 0.0);
break;
case AxisDirection.up:
delta = const Offset(0.0, -30.0);
break;
case AxisDirection.down:
delta = const Offset(0.0, 30.0);
break;
}
await tester.fling(finder, delta, 1000.0, initialOffset: delta * initialOffsetFactor);
}
class Test1215DismissibleWidget extends StatelessWidget {
const Test1215DismissibleWidget(this.text);
......@@ -558,4 +607,54 @@ void main() {
final RenderBox backgroundBox = tester.firstRenderObject(find.text('background'));
expect(backgroundBox.size.height, equals(100.0));
});
}
testWidgets('Checking fling item before movementDuration completes', (WidgetTester tester) async {
await tester.pumpWidget(buildTest());
expect(dismissedItems, isEmpty);
await checkFlingItemBeforeMovementEnd(tester, 0, gestureDirection: AxisDirection.left, mechanism: flingElement);
expect(find.text('0'), findsOneWidget);
await checkFlingItemBeforeMovementEnd(tester, 1, gestureDirection: AxisDirection.right, mechanism: flingElement);
expect(find.text('1'), findsOneWidget);
});
testWidgets('Checking fling item after movementDuration', (WidgetTester tester) async {
await tester.pumpWidget(buildTest());
expect(dismissedItems, isEmpty);
await checkFlingItemAfterMovement(tester, 1, gestureDirection: AxisDirection.left, mechanism: flingElement);
expect(find.text('1'), findsNothing);
await checkFlingItemAfterMovement(tester, 0, gestureDirection: AxisDirection.right, mechanism: flingElement);
expect(find.text('0'), findsNothing);
});
testWidgets('Horizontal fling less than threshold', (WidgetTester tester) async {
scrollDirection = Axis.horizontal;
await tester.pumpWidget(buildTest());
expect(dismissedItems, isEmpty);
await checkFlingItemAfterMovement(tester, 0, gestureDirection: AxisDirection.left, mechanism: rollbackElement);
expect(find.text('0'), findsOneWidget);
expect(dismissedItems, isEmpty);
await checkFlingItemAfterMovement(tester, 1, gestureDirection: AxisDirection.right, mechanism: rollbackElement);
expect(find.text('1'), findsOneWidget);
expect(dismissedItems, isEmpty);
});
testWidgets('Vertical fling less than threshold', (WidgetTester tester) async {
scrollDirection = Axis.vertical;
await tester.pumpWidget(buildTest());
expect(dismissedItems, isEmpty);
await checkFlingItemAfterMovement(tester, 0, gestureDirection: AxisDirection.left, mechanism: rollbackElement);
expect(find.text('0'), findsOneWidget);
expect(dismissedItems, isEmpty);
await checkFlingItemAfterMovement(tester, 1, gestureDirection: AxisDirection.right, mechanism: rollbackElement);
expect(find.text('1'), findsOneWidget);
expect(dismissedItems, isEmpty);
});
}
\ No newline at end of file
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