| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // TODO(gspencergoog): Remove this tag once this test's state leaks/test |
| // dependencies have been fixed. |
| // https://github.com/flutter/flutter/issues/85160 |
| // Fails with "flutter test --test-randomize-ordering-seed=123" |
| @Tags(<String>['no-shuffle']) |
| |
| import 'package:flutter/gestures.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/semantics.dart'; |
| import 'package:flutter/services.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import 'semantics_tester.dart'; |
| |
| void main() { |
| testWidgets('Drag and drop - control test', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| int dragStartedCount = 0; |
| int moveCount = 0; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragStarted: () { |
| ++dragStartedCount; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onMove: (_) => moveCount++, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(dragStartedCount, 0); |
| expect(moveCount, 0); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(dragStartedCount, 1); |
| expect(moveCount, 0); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(dragStartedCount, 1); |
| expect(moveCount, 1); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(dragStartedCount, 1); |
| expect(moveCount, 1); |
| }); |
| |
| // Regression test for https://github.com/flutter/flutter/issues/76825 |
| testWidgets('Drag and drop - onLeave callback fires correctly with generic parameter', (WidgetTester tester) async { |
| final Map<String,int> leftBehind = <String,int>{ |
| 'Target 1': 0, |
| 'Target 2': 0, |
| }; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 1')); |
| }, |
| onLeave: (int? data) { |
| if (data != null) { |
| leftBehind['Target 1'] = leftBehind['Target 1']! + data; |
| } |
| }, |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 2')); |
| }, |
| onLeave: (int? data) { |
| if (data != null) { |
| leftBehind['Target 2'] = leftBehind['Target 2']! + data; |
| } |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(leftBehind['Target 1'], equals(0)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(0)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target 1')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(0)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| final Offset thirdLocation = tester.getCenter(find.text('Target 2')); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(1)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(1)); |
| expect(leftBehind['Target 2'], equals(1)); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(1)); |
| expect(leftBehind['Target 2'], equals(1)); |
| }); |
| |
| testWidgets('Drag and drop - onLeave callback fires correctly', (WidgetTester tester) async { |
| final Map<String,int> leftBehind = <String,int>{ |
| 'Target 1': 0, |
| 'Target 2': 0, |
| }; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 1')); |
| }, |
| onLeave: (Object? data) { |
| if (data is int) { |
| leftBehind['Target 1'] = leftBehind['Target 1']! + data; |
| } |
| }, |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 2')); |
| }, |
| onLeave: (Object? data) { |
| if (data is int) { |
| leftBehind['Target 2'] = leftBehind['Target 2']! + data; |
| } |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(leftBehind['Target 1'], equals(0)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(0)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target 1')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(0)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| final Offset thirdLocation = tester.getCenter(find.text('Target 2')); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(1)); |
| expect(leftBehind['Target 2'], equals(0)); |
| |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(1)); |
| expect(leftBehind['Target 2'], equals(1)); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(leftBehind['Target 1'], equals(1)); |
| expect(leftBehind['Target 2'], equals(1)); |
| }); |
| |
| // Regression test for https://github.com/flutter/flutter/issues/76825 |
| testWidgets('Drag and drop - onMove callback fires correctly with generic parameter', (WidgetTester tester) async { |
| final Map<String,int> targetMoveCount = <String,int>{ |
| 'Target 1': 0, |
| 'Target 2': 0, |
| }; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 1')); |
| }, |
| onMove: (DragTargetDetails<int> details) { |
| targetMoveCount['Target 1'] = |
| targetMoveCount['Target 1']! + details.data; |
| }, |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 2')); |
| }, |
| onMove: (DragTargetDetails<int> details) { |
| targetMoveCount['Target 2'] = |
| targetMoveCount['Target 2']! + details.data; |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(targetMoveCount['Target 1'], equals(0)); |
| expect(targetMoveCount['Target 2'], equals(0)); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(0)); |
| expect(targetMoveCount['Target 2'], equals(0)); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target 1')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(1)); |
| expect(targetMoveCount['Target 2'], equals(0)); |
| |
| final Offset thirdLocation = tester.getCenter(find.text('Target 2')); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(1)); |
| expect(targetMoveCount['Target 2'], equals(1)); |
| |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(2)); |
| expect(targetMoveCount['Target 2'], equals(1)); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(2)); |
| expect(targetMoveCount['Target 2'], equals(1)); |
| }); |
| |
| testWidgets('Drag and drop - onMove callback fires correctly', (WidgetTester tester) async { |
| final Map<String,int> targetMoveCount = <String,int>{ |
| 'Target 1': 0, |
| 'Target 2': 0, |
| }; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 1')); |
| }, |
| onMove: (DragTargetDetails<dynamic> details) { |
| if (details.data is int) { |
| targetMoveCount['Target 1'] = |
| targetMoveCount['Target 1']! + (details.data as int); |
| } |
| }, |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target 2')); |
| }, |
| onMove: (DragTargetDetails<dynamic> details) { |
| if (details.data is int) { |
| targetMoveCount['Target 2'] = |
| targetMoveCount['Target 2']! + (details.data as int); |
| } |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(targetMoveCount['Target 1'], equals(0)); |
| expect(targetMoveCount['Target 2'], equals(0)); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(0)); |
| expect(targetMoveCount['Target 2'], equals(0)); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target 1')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(1)); |
| expect(targetMoveCount['Target 2'], equals(0)); |
| |
| final Offset thirdLocation = tester.getCenter(find.text('Target 2')); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(1)); |
| expect(targetMoveCount['Target 2'], equals(1)); |
| |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(2)); |
| expect(targetMoveCount['Target 2'], equals(1)); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(targetMoveCount['Target 1'], equals(2)); |
| expect(targetMoveCount['Target 2'], equals(1)); |
| }); |
| |
| testWidgets('Drag and drop - dragging over button', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| Stack( |
| children: <Widget>[ |
| GestureDetector( |
| behavior: HitTestBehavior.opaque, |
| onTap: () { |
| events.add('tap'); |
| }, |
| child: const Text('Button'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const IgnorePointer( |
| child: Text('Target'), |
| ); |
| }, |
| onAccept: (int? data) { |
| events.add('drop'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| ], |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Button'), findsOneWidget); |
| |
| // taps (we check both to make sure the test is consistent) |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Button')); |
| expect(events, equals(<String>['tap'])); |
| events.clear(); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Target'), warnIfMissed: false); // (inside IgnorePointer) |
| expect(events, equals(<String>['tap'])); |
| events.clear(); |
| |
| // drag and drop |
| |
| firstLocation = tester.getCenter(find.text('Source')); |
| TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(events, isEmpty); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop', 'details'])); |
| events.clear(); |
| |
| // drag and tap and drop |
| |
| firstLocation = tester.getCenter(find.text('Source')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Button')); |
| await tester.tap(find.text('Target'), warnIfMissed: false); // (inside IgnorePointer) |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['tap', 'tap', 'drop', 'details'])); |
| events.clear(); |
| }); |
| |
| testWidgets('Drag and drop - tapping button', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| child: GestureDetector( |
| behavior: HitTestBehavior.opaque, |
| onTap: () { |
| events.add('tap'); |
| }, |
| child: const Text('Button'), |
| ), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Button'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Button')); |
| expect(events, equals(<String>['tap'])); |
| events.clear(); |
| |
| firstLocation = tester.getCenter(find.text('Button')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(events, isEmpty); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop', 'details'])); |
| events.clear(); |
| }); |
| |
| testWidgets('Drag and drop - long press draggable, short press', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const LongPressDraggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Source')); |
| expect(events, isEmpty); |
| |
| firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(events, isEmpty); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, isEmpty); |
| }); |
| |
| testWidgets('Drag and drop - long press draggable, long press', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Source')); |
| expect(events, isEmpty); |
| |
| firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| await tester.pump(const Duration(seconds: 20)); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(events, isEmpty); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop', 'details'])); |
| }); |
| |
| testWidgets('Drag and drop - horizontal and vertical draggables in vertical block', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation, thirdLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: ListView( |
| dragStartBehavior: DragStartBehavior.down, |
| children: <Widget>[ |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop $data'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| Container(height: 400.0), |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| affinity: Axis.horizontal, |
| child: Text('H'), |
| ), |
| const Draggable<int>( |
| data: 2, |
| feedback: Text('Dragging'), |
| affinity: Axis.vertical, |
| child: Text('V'), |
| ), |
| Container(height: 500.0), |
| Container(height: 500.0), |
| Container(height: 500.0), |
| Container(height: 500.0), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('H'), findsOneWidget); |
| expect(find.text('V'), findsOneWidget); |
| |
| // vertical draggable drags vertically |
| expect(events, isEmpty); |
| firstLocation = tester.getCenter(find.text('V')); |
| secondLocation = tester.getCenter(find.text('Target')); |
| TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop 2', 'details'])); |
| expect(tester.getCenter(find.text('Target')).dy, greaterThan(0.0)); |
| events.clear(); |
| |
| // horizontal draggable drags horizontally |
| expect(events, isEmpty); |
| firstLocation = tester.getTopLeft(find.text('H')); |
| secondLocation = tester.getTopRight(find.text('H')); |
| thirdLocation = tester.getCenter(find.text('Target')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop 1', 'details'])); |
| expect(tester.getCenter(find.text('Target')).dy, greaterThan(0.0)); |
| events.clear(); |
| |
| // vertical draggable drags horizontally when there's no competition |
| // from other gesture detectors |
| expect(events, isEmpty); |
| firstLocation = tester.getTopLeft(find.text('V')); |
| secondLocation = tester.getTopRight(find.text('V')); |
| thirdLocation = tester.getCenter(find.text('Target')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop 2', 'details'])); |
| expect(tester.getCenter(find.text('Target')).dy, greaterThan(0.0)); |
| events.clear(); |
| |
| // horizontal draggable doesn't drag vertically when there is competition |
| // for vertical gestures |
| expect(events, isEmpty); |
| firstLocation = tester.getCenter(find.text('H')); |
| secondLocation = tester.getCenter(find.text('Target')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); // scrolls off screen! |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>[])); |
| expect(find.text('Target'), findsNothing); |
| events.clear(); |
| }); |
| |
| testWidgets('Drag and drop - horizontal and vertical draggables in horizontal block', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation, thirdLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: ListView( |
| dragStartBehavior: DragStartBehavior.down, |
| scrollDirection: Axis.horizontal, |
| children: <Widget>[ |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop $data'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| Container(width: 400.0), |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| affinity: Axis.horizontal, |
| child: Text('H'), |
| ), |
| const Draggable<int>( |
| data: 2, |
| feedback: Text('Dragging'), |
| affinity: Axis.vertical, |
| child: Text('V'), |
| ), |
| Container(width: 500.0), |
| Container(width: 500.0), |
| Container(width: 500.0), |
| Container(width: 500.0), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('H'), findsOneWidget); |
| expect(find.text('V'), findsOneWidget); |
| |
| // horizontal draggable drags horizontally |
| expect(events, isEmpty); |
| firstLocation = tester.getCenter(find.text('H')); |
| secondLocation = tester.getCenter(find.text('Target')); |
| TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop 1', 'details'])); |
| expect(tester.getCenter(find.text('Target')).dx, greaterThan(0.0)); |
| events.clear(); |
| |
| // vertical draggable drags vertically |
| expect(events, isEmpty); |
| firstLocation = tester.getTopLeft(find.text('V')); |
| secondLocation = tester.getBottomLeft(find.text('V')); |
| thirdLocation = tester.getCenter(find.text('Target')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop 2', 'details'])); |
| expect(tester.getCenter(find.text('Target')).dx, greaterThan(0.0)); |
| events.clear(); |
| |
| // horizontal draggable drags vertically when there's no competition |
| // from other gesture detectors |
| expect(events, isEmpty); |
| firstLocation = tester.getTopLeft(find.text('H')); |
| secondLocation = tester.getBottomLeft(find.text('H')); |
| thirdLocation = tester.getCenter(find.text('Target')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>['drop 1', 'details'])); |
| expect(tester.getCenter(find.text('Target')).dx, greaterThan(0.0)); |
| events.clear(); |
| |
| // vertical draggable doesn't drag horizontally when there is competition |
| // for horizontal gestures |
| expect(events, isEmpty); |
| firstLocation = tester.getCenter(find.text('V')); |
| secondLocation = tester.getCenter(find.text('Target')); |
| gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); // scrolls off screen! |
| await gesture.up(); |
| await tester.pump(); |
| expect(events, equals(<String>[])); |
| expect(find.text('Target'), findsNothing); |
| events.clear(); |
| }); |
| |
| group('Drag and drop - Draggables with a set axis only move along that axis', () { |
| final List<String> events = <String>[]; |
| |
| Widget build() { |
| return MaterialApp( |
| home: ListView( |
| scrollDirection: Axis.horizontal, |
| children: <Widget>[ |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop $data'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| Container(width: 400.0), |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('H'), |
| childWhenDragging: SizedBox(), |
| axis: Axis.horizontal, |
| child: Text('H'), |
| ), |
| const Draggable<int>( |
| data: 2, |
| feedback: Text('V'), |
| childWhenDragging: SizedBox(), |
| axis: Axis.vertical, |
| child: Text('V'), |
| ), |
| const Draggable<int>( |
| data: 3, |
| feedback: Text('N'), |
| childWhenDragging: SizedBox(), |
| child: Text('N'), |
| ), |
| Container(width: 500.0), |
| Container(width: 500.0), |
| Container(width: 500.0), |
| Container(width: 500.0), |
| ], |
| ), |
| ); |
| } |
| testWidgets('Null axis draggable moves along all axes', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| final Offset firstLocation = tester.getTopLeft(find.text('N')); |
| final Offset secondLocation = firstLocation + const Offset(300.0, 300.0); |
| final Offset thirdLocation = firstLocation + const Offset(-300.0, -300.0); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('N')), secondLocation); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('N')), thirdLocation); |
| }); |
| |
| testWidgets('Horizontal axis draggable moves horizontally', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| final Offset firstLocation = tester.getTopLeft(find.text('H')); |
| final Offset secondLocation = firstLocation + const Offset(300.0, 0.0); |
| final Offset thirdLocation = firstLocation + const Offset(-300.0, 0.0); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('H')), secondLocation); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('H')), thirdLocation); |
| }); |
| |
| testWidgets('Horizontal axis draggable does not move vertically', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| final Offset firstLocation = tester.getTopLeft(find.text('H')); |
| final Offset secondDragLocation = firstLocation + const Offset(300.0, 200.0); |
| // The horizontal drag widget won't scroll vertically. |
| final Offset secondWidgetLocation = firstLocation + const Offset(300.0, 0.0); |
| final Offset thirdDragLocation = firstLocation + const Offset(-300.0, -200.0); |
| final Offset thirdWidgetLocation = firstLocation + const Offset(-300.0, 0.0); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondDragLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('H')), secondWidgetLocation); |
| await gesture.moveTo(thirdDragLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('H')), thirdWidgetLocation); |
| }); |
| |
| testWidgets('Vertical axis draggable moves vertically', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| final Offset firstLocation = tester.getTopLeft(find.text('V')); |
| final Offset secondLocation = firstLocation + const Offset(0.0, 300.0); |
| final Offset thirdLocation = firstLocation + const Offset(0.0, -300.0); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('V')), secondLocation); |
| await gesture.moveTo(thirdLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('V')), thirdLocation); |
| }); |
| |
| testWidgets('Vertical axis draggable does not move horizontally', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| final Offset firstLocation = tester.getTopLeft(find.text('V')); |
| final Offset secondDragLocation = firstLocation + const Offset(200.0, 300.0); |
| // The vertical drag widget won't scroll horizontally. |
| final Offset secondWidgetLocation = firstLocation + const Offset(0.0, 300.0); |
| final Offset thirdDragLocation = firstLocation + const Offset(-200.0, -300.0); |
| final Offset thirdWidgetLocation = firstLocation + const Offset(0.0, -300.0); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| await gesture.moveTo(secondDragLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('V')), secondWidgetLocation); |
| await gesture.moveTo(thirdDragLocation); |
| await tester.pump(); |
| expect(tester.getTopLeft(find.text('V')), thirdWidgetLocation); |
| }); |
| }); |
| |
| group('Drag and drop - onDragUpdate called if draggable moves along a set axis', () { |
| int updated = 0; |
| Offset dragDelta = Offset.zero; |
| |
| setUp(() { |
| updated = 0; |
| dragDelta = Offset.zero; |
| }); |
| |
| Widget build() { |
| return MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragUpdate: (DragUpdateDetails details) { |
| dragDelta += details.delta; |
| updated++; |
| }, |
| child: const Text('Source'), |
| ), |
| Draggable<int>( |
| data: 2, |
| feedback: const Text('Vertical Dragging'), |
| onDragUpdate: (DragUpdateDetails details) { |
| dragDelta += details.delta; |
| updated++; |
| }, |
| axis: Axis.vertical, |
| child: const Text('Vertical Source'), |
| ), |
| Draggable<int>( |
| data: 3, |
| feedback: const Text('Horizontal Dragging'), |
| onDragUpdate: (DragUpdateDetails details) { |
| dragDelta += details.delta; |
| updated++; |
| }, |
| axis: Axis.horizontal, |
| child: const Text('Horizontal Source'), |
| ), |
| ], |
| ), |
| ); |
| } |
| |
| testWidgets('Null axis onDragUpdate called only if draggable moves in any direction', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| |
| expect(updated, 0); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(updated, 0); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| |
| await gesture.moveBy(const Offset(10, 10)); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| |
| await gesture.moveBy(Offset.zero); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(dragDelta.dx, 10); |
| expect(dragDelta.dy, 10); |
| }); |
| |
| testWidgets('Vertical axis onDragUpdate only called if draggable moves vertical', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| |
| expect(updated, 0); |
| expect(find.text('Vertical Source'), findsOneWidget); |
| expect(find.text('Vertical Dragging'), findsNothing); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Vertical Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(updated, 0); |
| expect(find.text('Vertical Source'), findsOneWidget); |
| expect(find.text('Vertical Dragging'), findsOneWidget); |
| |
| await gesture.moveBy(const Offset(0, 10)); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| |
| await gesture.moveBy(const Offset(10 , 0)); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| expect(find.text('Vertical Source'), findsOneWidget); |
| expect(find.text('Vertical Dragging'), findsNothing); |
| expect(dragDelta.dx, 0); |
| expect(dragDelta.dy, 10); |
| }); |
| |
| testWidgets('Horizontal axis onDragUpdate only called if draggable moves horizontal', (WidgetTester tester) async { |
| await tester.pumpWidget(build()); |
| |
| expect(updated, 0); |
| expect(find.text('Horizontal Source'), findsOneWidget); |
| expect(find.text('Horizontal Dragging'), findsNothing); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Horizontal Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(updated, 0); |
| expect(find.text('Horizontal Source'), findsOneWidget); |
| expect(find.text('Horizontal Dragging'), findsOneWidget); |
| |
| await gesture.moveBy(const Offset(0, 10)); |
| await tester.pump(); |
| |
| expect(updated, 0); |
| |
| await gesture.moveBy(const Offset(10 , 0)); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(updated, 1); |
| expect(find.text('Horizontal Source'), findsOneWidget); |
| expect(find.text('Horizontal Dragging'), findsNothing); |
| expect(dragDelta.dx, 10); |
| expect(dragDelta.dy, 0); |
| }); |
| }); |
| |
| testWidgets('Drag and drop - onDraggableCanceled not called if dropped on accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDraggableCanceledCalled = false; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDraggableCanceled: (Velocity velocity, Offset offset) { |
| onDraggableCanceledCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| }); |
| |
| testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDraggableCanceledCalled = false; |
| late Velocity onDraggableCanceledVelocity; |
| late Offset onDraggableCanceledOffset; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDraggableCanceled: (Velocity velocity, Offset offset) { |
| onDraggableCanceledCalled = true; |
| onDraggableCanceledVelocity = velocity; |
| onDraggableCanceledOffset = offset; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox( |
| height: 100.0, |
| child: Text('Target'), |
| ); |
| }, |
| onWillAccept: (int? data) => false, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| final Offset firstLocation = tester.getTopLeft(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isTrue); |
| expect(onDraggableCanceledVelocity, equals(Velocity.zero)); |
| expect(onDraggableCanceledOffset, equals(Offset(secondLocation.dx, secondLocation.dy))); |
| }); |
| |
| testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with correct velocity', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDraggableCanceledCalled = false; |
| late Velocity onDraggableCanceledVelocity; |
| late Offset onDraggableCanceledOffset; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column(children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Source'), |
| onDraggableCanceled: (Velocity velocity, Offset offset) { |
| onDraggableCanceledCalled = true; |
| onDraggableCanceledVelocity = velocity; |
| onDraggableCanceledOffset = offset; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onWillAccept: (int? data) => false, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ]), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isFalse); |
| |
| final Offset flingStart = tester.getTopLeft(find.text('Source')); |
| await tester.flingFrom(flingStart, const Offset(0.0, 100.0), 1000.0); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDraggableCanceledCalled, isTrue); |
| expect(onDraggableCanceledVelocity.pixelsPerSecond.dx.abs(), lessThan(0.0000001)); |
| expect((onDraggableCanceledVelocity.pixelsPerSecond.dy - 1000.0).abs(), lessThan(0.0000001)); |
| expect(onDraggableCanceledOffset, equals(Offset(flingStart.dx, flingStart.dy) + const Offset(0.0, 100.0))); |
| }); |
| |
| testWidgets('Drag and drop - onDragEnd not called if dropped on non-accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDragEndCalled = false; |
| late DraggableDetails onDragEndDraggableDetails; |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragEnd: (DraggableDetails details) { |
| onDragEndCalled = true; |
| onDragEndDraggableDetails = details; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onWillAccept: (int? data) => false, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| final Offset firstLocation = tester.getTopLeft(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isTrue); |
| expect(onDragEndDraggableDetails, isNotNull); |
| expect(onDragEndDraggableDetails.wasAccepted, isFalse); |
| expect(onDragEndDraggableDetails.velocity, equals(Velocity.zero)); |
| expect( |
| onDragEndDraggableDetails.offset, |
| equals(Offset(secondLocation.dx, secondLocation.dy - firstLocation.dy)), |
| ); |
| }); |
| |
| testWidgets('Drag and drop - DragTarget rebuilds with and without rejected data when a rejected draggable enters and leaves', (WidgetTester tester) async { |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return SizedBox( |
| height: 100.0, |
| child: rejects.isNotEmpty |
| ? const Text('Rejected') |
| : const Text('Target'), |
| ); |
| }, |
| onWillAccept: (int? data) => false, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| |
| final Offset firstLocation = tester.getTopLeft(find.text('Source')); |
| final TestGesture gesture = |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsNothing); |
| expect(find.text('Rejected'), findsOneWidget); |
| |
| await gesture.moveTo(firstLocation); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| }); |
| |
| |
| testWidgets('Drag and drop - Can drag and drop over a non-accepting target multiple times', (WidgetTester tester) async { |
| int numberOfTimesOnDraggableCanceledCalled = 0; |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDraggableCanceled: (Velocity velocity, Offset offset) { |
| numberOfTimesOnDraggableCanceledCalled++; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return SizedBox( |
| height: 100.0, |
| child: rejects.isNotEmpty |
| ? const Text('Rejected') |
| : const Text('Target'), |
| ); |
| }, |
| onWillAccept: (int? data) => false, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| |
| final Offset firstLocation = tester.getTopLeft(find.text('Source')); |
| final TestGesture gesture = |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsNothing); |
| expect(find.text('Rejected'), findsOneWidget); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| expect(numberOfTimesOnDraggableCanceledCalled, 1); |
| |
| // Drag and drop the Draggable onto the Target a second time. |
| final TestGesture secondGesture = |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| |
| await secondGesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsNothing); |
| expect(find.text('Rejected'), findsOneWidget); |
| |
| await secondGesture.up(); |
| await tester.pump(); |
| |
| expect(numberOfTimesOnDraggableCanceledCalled, 2); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(find.text('Rejected'), findsNothing); |
| }); |
| |
| testWidgets('Drag and drop - onDragCompleted not called if dropped on non-accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDragCompletedCalled = false; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragCompleted: () { |
| onDragCompletedCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox( |
| height: 100.0, |
| child: Text('Target'), |
| ); |
| }, |
| onWillAccept: (int? data) => false, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| final Offset firstLocation = tester.getTopLeft(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| }); |
| |
| testWidgets('Drag and drop - onDragEnd called if dropped on accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDragEndCalled = false; |
| late DraggableDetails onDragEndDraggableDetails; |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragEnd: (DraggableDetails details) { |
| onDragEndCalled = true; |
| onDragEndDraggableDetails = details; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| final Offset droppedLocation = tester.getTopLeft(find.text('Target')); |
| final Offset expectedDropOffset = Offset(droppedLocation.dx, secondLocation.dy - firstLocation.dy); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isTrue); |
| expect(onDragEndDraggableDetails, isNotNull); |
| expect(onDragEndDraggableDetails.wasAccepted, isTrue); |
| expect(onDragEndDraggableDetails.velocity, equals(Velocity.zero)); |
| expect(onDragEndDraggableDetails.offset, equals(expectedDropOffset)); |
| }); |
| |
| testWidgets('DragTarget does not call onDragEnd when remove from the tree', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation; |
| int timesOnDragEndCalled = 0; |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragEnd: (DraggableDetails details) { |
| timesOnDragEndCalled++; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Source')); |
| expect(events, isEmpty); |
| |
| firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| await tester.pump(const Duration(seconds: 20)); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: const <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(timesOnDragEndCalled, equals(1)); |
| await gesture.up(); |
| await tester.pump(); |
| }); |
| |
| testWidgets('Drag and drop - onDragCompleted called if dropped on accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDragCompletedCalled = false; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragCompleted: () { |
| onDragCompletedCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isTrue); |
| }); |
| |
| testWidgets('Drag and drop - allow pass through of unaccepted data test', (WidgetTester tester) async { |
| final List<int> acceptedInts = <int>[]; |
| final List<DragTargetDetails<int>> acceptedIntsDetails = <DragTargetDetails<int>>[]; |
| final List<double> acceptedDoubles = <double>[]; |
| final List<DragTargetDetails<double>> acceptedDoublesDetails = <DragTargetDetails<double>>[]; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('IntDragging'), |
| child: Text('IntSource'), |
| ), |
| const Draggable<double>( |
| data: 1.0, |
| feedback: Text('DoubleDragging'), |
| child: Text('DoubleSource'), |
| ), |
| Stack( |
| children: <Widget>[ |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const IgnorePointer( |
| child: SizedBox( |
| height: 100.0, |
| child: Text('Target1'), |
| ), |
| ); |
| }, |
| onAccept: acceptedInts.add, |
| onAcceptWithDetails: acceptedIntsDetails.add, |
| ), |
| DragTarget<double>( |
| builder: (BuildContext context, List<double?> data, List<dynamic> rejects) { |
| return const IgnorePointer( |
| child: SizedBox( |
| height: 100.0, |
| child: Text('Target2'), |
| ), |
| ); |
| }, |
| onAccept: acceptedDoubles.add, |
| onAcceptWithDetails: acceptedDoublesDetails.add, |
| ), |
| ], |
| ), |
| ], |
| ), |
| )); |
| |
| expect(acceptedInts, isEmpty); |
| expect(acceptedIntsDetails, isEmpty); |
| expect(acceptedDoubles, isEmpty); |
| expect(acceptedDoublesDetails, isEmpty); |
| expect(find.text('IntSource'), findsOneWidget); |
| expect(find.text('IntDragging'), findsNothing); |
| expect(find.text('DoubleSource'), findsOneWidget); |
| expect(find.text('DoubleDragging'), findsNothing); |
| expect(find.text('Target1'), findsOneWidget); |
| expect(find.text('Target2'), findsOneWidget); |
| |
| final Offset intLocation = tester.getCenter(find.text('IntSource')); |
| final Offset doubleLocation = tester.getCenter(find.text('DoubleSource')); |
| final Offset targetLocation = tester.getCenter(find.text('Target1')); |
| |
| // Drag the double draggable. |
| final TestGesture doubleGesture = await tester.startGesture(doubleLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(acceptedInts, isEmpty); |
| expect(acceptedIntsDetails, isEmpty); |
| expect(acceptedDoubles, isEmpty); |
| expect(acceptedDoublesDetails, isEmpty); |
| expect(find.text('IntDragging'), findsNothing); |
| expect(find.text('DoubleDragging'), findsOneWidget); |
| |
| await doubleGesture.moveTo(targetLocation); |
| await tester.pump(); |
| |
| expect(acceptedInts, isEmpty); |
| expect(acceptedIntsDetails, isEmpty); |
| expect(acceptedDoubles, isEmpty); |
| expect(acceptedDoublesDetails, isEmpty); |
| expect(find.text('IntDragging'), findsNothing); |
| expect(find.text('DoubleDragging'), findsOneWidget); |
| |
| await doubleGesture.up(); |
| await tester.pump(); |
| |
| expect(acceptedInts, isEmpty); |
| expect(acceptedIntsDetails, isEmpty); |
| expect(acceptedDoubles, equals(<double>[1.0])); |
| expect(acceptedDoublesDetails, hasLength(1)); |
| expect(acceptedDoublesDetails.first.offset, const Offset(112.0, 122.0)); |
| expect(find.text('IntDragging'), findsNothing); |
| expect(find.text('DoubleDragging'), findsNothing); |
| |
| acceptedDoubles.clear(); |
| acceptedDoublesDetails.clear(); |
| |
| // Drag the int draggable. |
| final TestGesture intGesture = await tester.startGesture(intLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(acceptedInts, isEmpty); |
| expect(acceptedIntsDetails, isEmpty); |
| expect(acceptedDoubles, isEmpty); |
| expect(acceptedDoublesDetails, isEmpty); |
| expect(find.text('IntDragging'), findsOneWidget); |
| expect(find.text('DoubleDragging'), findsNothing); |
| |
| await intGesture.moveTo(targetLocation); |
| await tester.pump(); |
| |
| expect(acceptedInts, isEmpty); |
| expect(acceptedIntsDetails, isEmpty); |
| expect(acceptedDoubles, isEmpty); |
| expect(acceptedDoublesDetails, isEmpty); |
| expect(find.text('IntDragging'), findsOneWidget); |
| expect(find.text('DoubleDragging'), findsNothing); |
| |
| await intGesture.up(); |
| await tester.pump(); |
| |
| expect(acceptedInts, equals(<int>[1])); |
| expect(acceptedIntsDetails, hasLength(1)); |
| expect(acceptedIntsDetails.first.offset, const Offset(184.0, 122.0)); |
| expect(acceptedDoubles, isEmpty); |
| expect(acceptedDoublesDetails, isEmpty); |
| expect(find.text('IntDragging'), findsNothing); |
| expect(find.text('DoubleDragging'), findsNothing); |
| }); |
| |
| testWidgets('Drag and drop - allow pass through of unaccepted data twice test', (WidgetTester tester) async { |
| final List<DragTargetData> acceptedDragTargetDatas = <DragTargetData>[]; |
| final List<DragTargetDetails<DragTargetData>> acceptedDragTargetDataDetails = <DragTargetDetails<DragTargetData>>[]; |
| final List<ExtendedDragTargetData> acceptedExtendedDragTargetDatas = <ExtendedDragTargetData>[]; |
| final List<DragTargetDetails<ExtendedDragTargetData>> acceptedExtendedDragTargetDataDetails = <DragTargetDetails<ExtendedDragTargetData>>[]; |
| final DragTargetData dragTargetData = DragTargetData(); |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<DragTargetData>( |
| data: dragTargetData, |
| feedback: const Text('Dragging'), |
| child: const Text('Source'), |
| ), |
| Stack( |
| children: <Widget>[ |
| DragTarget<DragTargetData>( |
| builder: (BuildContext context, List<DragTargetData?> data, List<dynamic> rejects) { |
| return const IgnorePointer( |
| child: SizedBox( |
| height: 100.0, |
| child: Text('Target1'), |
| ), |
| ); |
| }, onAccept: acceptedDragTargetDatas.add, |
| onAcceptWithDetails: acceptedDragTargetDataDetails.add, |
| ), |
| DragTarget<ExtendedDragTargetData>( |
| builder: (BuildContext context, List<ExtendedDragTargetData?> data, List<dynamic> rejects) { |
| return const IgnorePointer( |
| child: SizedBox( |
| height: 100.0, |
| child: Text('Target2'), |
| ), |
| ); |
| }, |
| onAccept: acceptedExtendedDragTargetDatas.add, |
| onAcceptWithDetails: acceptedExtendedDragTargetDataDetails.add, |
| ), |
| ], |
| ), |
| ], |
| ), |
| )); |
| |
| final Offset dragTargetLocation = tester.getCenter(find.text('Source')); |
| final Offset targetLocation = tester.getCenter(find.text('Target1')); |
| |
| for (int i = 0; i < 2; i += 1) { |
| final TestGesture gesture = await tester.startGesture(dragTargetLocation); |
| await tester.pump(); |
| await gesture.moveTo(targetLocation); |
| await tester.pump(); |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(acceptedDragTargetDatas, equals(<DragTargetData>[dragTargetData])); |
| expect(acceptedDragTargetDataDetails, hasLength(1)); |
| expect(acceptedDragTargetDataDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(acceptedExtendedDragTargetDatas, isEmpty); |
| expect(acceptedExtendedDragTargetDataDetails, isEmpty); |
| |
| acceptedDragTargetDatas.clear(); |
| acceptedDragTargetDataDetails.clear(); |
| await tester.pump(); |
| } |
| }); |
| |
| testWidgets('Drag and drop - maxSimultaneousDrags', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| |
| Widget build(int maxSimultaneousDrags) { |
| return MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| Draggable<int>( |
| data: 1, |
| maxSimultaneousDrags: maxSimultaneousDrags, |
| feedback: const Text('Dragging'), |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| ); |
| } |
| |
| await tester.pumpWidget(build(0)); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await gesture.up(); |
| |
| await tester.pumpWidget(build(2)); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| |
| final TestGesture gesture1 = await tester.startGesture(firstLocation, pointer: 8); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| final TestGesture gesture2 = await tester.startGesture(firstLocation, pointer: 9); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNWidgets(2)); |
| expect(find.text('Target'), findsOneWidget); |
| |
| final TestGesture gesture3 = await tester.startGesture(firstLocation, pointer: 10); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNWidgets(2)); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await gesture1.moveTo(secondLocation); |
| await gesture2.moveTo(secondLocation); |
| await gesture3.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNWidgets(2)); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await gesture1.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await gesture2.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1, 1])); |
| expect(acceptedDetails, hasLength(2)); |
| expect(acceptedDetails[0].offset, const Offset(256.0, 74.0)); |
| expect(acceptedDetails[1].offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await gesture3.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1, 1])); |
| expect(acceptedDetails, hasLength(2)); |
| expect(acceptedDetails[0].offset, const Offset(256.0, 74.0)); |
| expect(acceptedDetails[1].offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| }); |
| |
| testWidgets('Draggable disposes recognizer', (WidgetTester tester) async { |
| bool didTap = false; |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Overlay( |
| initialEntries: <OverlayEntry>[ |
| OverlayEntry( |
| builder: (BuildContext context) => GestureDetector( |
| onTap: () { |
| didTap = true; |
| }, |
| child: Draggable<Object>( |
| feedback: Container( |
| width: 100.0, |
| height: 100.0, |
| color: const Color(0xFFFF0000), |
| ), |
| child: Container( |
| color: const Color(0xFFFFFF00), |
| ), |
| ), |
| ), |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| await tester.startGesture(const Offset(10.0, 10.0)); |
| expect(didTap, isFalse); |
| |
| // This tears down the draggable without terminating the gesture sequence, |
| // which used to trigger asserts in the multi-drag gesture recognizer. |
| await tester.pumpWidget(Container(key: UniqueKey())); |
| expect(didTap, isFalse); |
| }); |
| |
| // Regression test for https://github.com/flutter/flutter/issues/6128. |
| testWidgets('Draggable plays nice with onTap', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Overlay( |
| initialEntries: <OverlayEntry>[ |
| OverlayEntry( |
| builder: (BuildContext context) => GestureDetector( |
| onTap: () { /* registers a tap recognizer */ }, |
| child: Draggable<Object>( |
| feedback: Container( |
| width: 100.0, |
| height: 100.0, |
| color: const Color(0xFFFF0000), |
| ), |
| child: Container( |
| color: const Color(0xFFFFFF00), |
| ), |
| ), |
| ), |
| ), |
| ], |
| ), |
| ), |
| ); |
| |
| final TestGesture firstGesture = await tester.startGesture(const Offset(10.0, 10.0), pointer: 24); |
| final TestGesture secondGesture = await tester.startGesture(const Offset(10.0, 20.0), pointer: 25); |
| |
| await firstGesture.moveBy(const Offset(100.0, 0.0)); |
| await secondGesture.up(); |
| }); |
| |
| testWidgets('DragTarget does not set state when remove from the tree', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| Offset firstLocation, secondLocation; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const Text('Target'); |
| }, |
| onAccept: (int? data) { |
| events.add('drop'); |
| }, |
| onAcceptWithDetails: (DragTargetDetails<int> _) { |
| events.add('details'); |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('Source')); |
| expect(events, isEmpty); |
| |
| firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| await tester.pump(const Duration(seconds: 20)); |
| |
| secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: const <Widget>[ |
| Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| ], |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| await gesture.up(); |
| await tester.pump(); |
| }); |
| |
| testWidgets('Drag and drop - remove draggable', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| child: Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsNothing); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsNothing); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 26.0)); |
| expect(find.text('Source'), findsNothing); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| }); |
| |
| testWidgets('Tap above long-press draggable works', (WidgetTester tester) async { |
| final List<String> events = <String>[]; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Material( |
| child: Center( |
| child: GestureDetector( |
| onTap: () { |
| events.add('tap'); |
| }, |
| child: const LongPressDraggable<int>( |
| feedback: Text('Feedback'), |
| child: Text('X'), |
| ), |
| ), |
| ), |
| ), |
| )); |
| |
| expect(events, isEmpty); |
| await tester.tap(find.text('X')); |
| expect(events, equals(<String>['tap'])); |
| }); |
| |
| testWidgets('long-press draggable calls onDragEnd called if dropped on accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDragEndCalled = false; |
| late DraggableDetails onDragEndDraggableDetails; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| LongPressDraggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragEnd: (DraggableDetails details) { |
| onDragEndCalled = true; |
| onDragEndDraggableDetails = details; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| await tester.pump(kLongPressTimeout); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| final Offset droppedLocation = tester.getTopLeft(find.text('Target')); |
| final Offset expectedDropOffset = Offset(droppedLocation.dx, secondLocation.dy - firstLocation.dy); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails, hasLength(1)); |
| expect(acceptedDetails.first.offset, expectedDropOffset); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragEndCalled, isTrue); |
| expect(onDragEndDraggableDetails, isNotNull); |
| expect(onDragEndDraggableDetails.wasAccepted, isTrue); |
| expect(onDragEndDraggableDetails.velocity, equals(Velocity.zero)); |
| expect(onDragEndDraggableDetails.offset, equals(expectedDropOffset)); |
| }); |
| |
| testWidgets('long-press draggable calls onDragCompleted called if dropped on accepting target', (WidgetTester tester) async { |
| final List<int> accepted = <int>[]; |
| final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; |
| bool onDragCompletedCalled = false; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Column( |
| children: <Widget>[ |
| LongPressDraggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragCompleted: () { |
| onDragCompletedCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox(height: 100.0, child: Text('Target')); |
| }, |
| onAccept: accepted.add, |
| onAcceptWithDetails: acceptedDetails.add, |
| ), |
| ], |
| ), |
| )); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| await tester.pump(kLongPressTimeout); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| expect(accepted, isEmpty); |
| expect(acceptedDetails, isEmpty); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isFalse); |
| |
| await gesture.up(); |
| await tester.pump(); |
| |
| expect(accepted, equals(<int>[1])); |
| expect(acceptedDetails.first.offset, const Offset(256.0, 74.0)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(find.text('Target'), findsOneWidget); |
| expect(onDragCompletedCalled, isTrue); |
| }); |
| |
| testWidgets('long-press draggable calls onDragStartedCalled after long press', (WidgetTester tester) async { |
| bool onDragStartedCalled = false; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: LongPressDraggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragStarted: () { |
| onDragStartedCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| )); |
| |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| |
| await tester.pump(kLongPressTimeout); |
| |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(onDragStartedCalled, isTrue); |
| }); |
| |
| testWidgets('Custom long press delay for LongPressDraggable', (WidgetTester tester) async { |
| bool onDragStartedCalled = false; |
| await tester.pumpWidget(MaterialApp( |
| home: LongPressDraggable<int>( |
| data: 1, |
| delay: const Duration(seconds: 2), |
| feedback: const Text('Dragging'), |
| onDragStarted: () { |
| onDragStartedCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| )); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| // Halfway into the long press duration. |
| await tester.pump(const Duration(seconds: 1)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| // Long press draggable should be showing. |
| await tester.pump(const Duration(seconds: 1)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(onDragStartedCalled, isTrue); |
| }); |
| |
| testWidgets('Default long press delay for LongPressDraggable', (WidgetTester tester) async { |
| bool onDragStartedCalled = false; |
| await tester.pumpWidget(MaterialApp( |
| home: LongPressDraggable<int>( |
| data: 1, |
| feedback: const Text('Dragging'), |
| onDragStarted: () { |
| onDragStartedCalled = true; |
| }, |
| child: const Text('Source'), |
| ), |
| )); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| // Halfway into the long press duration. |
| await tester.pump(const Duration(milliseconds: 250)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsNothing); |
| expect(onDragStartedCalled, isFalse); |
| // Long press draggable should be showing. |
| await tester.pump(const Duration(milliseconds: 250)); |
| expect(find.text('Source'), findsOneWidget); |
| expect(find.text('Dragging'), findsOneWidget); |
| expect(onDragStartedCalled, isTrue); |
| }); |
| |
| testWidgets('long-press draggable calls Haptic Feedback onStart', (WidgetTester tester) async { |
| await _testLongPressDraggableHapticFeedback(tester: tester, hapticFeedbackOnStart: true, expectedHapticFeedbackCount: 1); |
| }); |
| |
| testWidgets('long-press draggable can disable Haptic Feedback', (WidgetTester tester) async { |
| await _testLongPressDraggableHapticFeedback(tester: tester, hapticFeedbackOnStart: false, expectedHapticFeedbackCount: 0); |
| }); |
| |
| testWidgets('Drag feedback with child anchor positions correctly', (WidgetTester tester) async { |
| await _testChildAnchorFeedbackPosition(tester: tester); |
| }); |
| |
| testWidgets('Drag feedback with child anchor within a non-global Overlay positions correctly', (WidgetTester tester) async { |
| await _testChildAnchorFeedbackPosition(tester: tester, left: 100.0, top: 100.0); |
| }); |
| |
| testWidgets('Drag feedback is put on root overlay with [rootOverlay] flag', (WidgetTester tester) async { |
| final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>(); |
| final GlobalKey<NavigatorState> childNavigatorKey = GlobalKey<NavigatorState>(); |
| // Create a [MaterialApp], with a nested [Navigator], which has the |
| // [Draggable]. |
| await tester.pumpWidget(MaterialApp( |
| navigatorKey: rootNavigatorKey, |
| home: Column( |
| children: <Widget>[ |
| SizedBox( |
| height: 200.0, |
| child: Navigator( |
| key: childNavigatorKey, |
| onGenerateRoute: (RouteSettings settings) { |
| if (settings.name == '/') { |
| return MaterialPageRoute<void>( |
| settings: settings, |
| builder: (BuildContext context) => const Draggable<int>( |
| data: 1, |
| feedback: Text('Dragging'), |
| rootOverlay: true, |
| child: Text('Source'), |
| ), |
| ); |
| } |
| throw UnsupportedError('Unsupported route: $settings'); |
| }, |
| ), |
| ), |
| DragTarget<int>( |
| builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { |
| return const SizedBox( |
| height: 300.0, child: Center(child: Text('Target 1')), |
| ); |
| }, |
| ), |
| ], |
| ), |
| )); |
| |
| final Offset firstLocation = tester.getCenter(find.text('Source')); |
| final TestGesture gesture = |
| await tester.startGesture(firstLocation, pointer: 7); |
| await tester.pump(); |
| |
| final Offset secondLocation = tester.getCenter(find.text('Target 1')); |
| await gesture.moveTo(secondLocation); |
| await tester.pump(); |
| |
| // Expect that the feedback widget is a descendant of the root overlay, |
| // but not a descendant of the child overlay. |
| expect( |
| find.descendant( |
| of: find.byType(Overlay).first, |
| matching: find.text('Dragging'), |
| ), |
| findsOneWidget, |
| ); |
| expect( |
| find.descendant( |
| of: find.byType(Overlay).last, |
| matching: find.text('Dragging'), |
| ), |
| findsNothing, |
| ); |
| }); |
| |
| // Regression test for https://github.com/flutter/flutter/issues/72483 |
| testWidgets('Drag and drop - DragTarget<Object> can accept Draggable<int> data', (WidgetTester tester) async { |
| final List<Object> accepted = <Object>[]; |
|