Unverified Commit a7af92db authored by Ian Wilkinson's avatar Ian Wilkinson Committed by GitHub

Declare DragTarget onMove event as taking a generic parameter (#76842)

parent b0d4d448
...@@ -59,12 +59,12 @@ typedef DragEndCallback = void Function(DraggableDetails details); ...@@ -59,12 +59,12 @@ typedef DragEndCallback = void Function(DraggableDetails details);
/// Signature for when a [Draggable] leaves a [DragTarget]. /// Signature for when a [Draggable] leaves a [DragTarget].
/// ///
/// Used by [DragTarget.onLeave]. /// Used by [DragTarget.onLeave].
typedef DragTargetLeave = void Function(Object? data); typedef DragTargetLeave<T> = void Function(T? data);
/// Signature for when a [Draggable] moves within a [DragTarget]. /// Signature for when a [Draggable] moves within a [DragTarget].
/// ///
/// Used by [DragTarget.onMove]. /// Used by [DragTarget.onMove].
typedef DragTargetMove = void Function(DragTargetDetails<dynamic> details); typedef DragTargetMove<T> = void Function(DragTargetDetails<T> details);
/// Where the [Draggable] should be anchored during a drag. /// Where the [Draggable] should be anchored during a drag.
enum DragAnchor { enum DragAnchor {
...@@ -653,12 +653,12 @@ class DragTarget<T extends Object> extends StatefulWidget { ...@@ -653,12 +653,12 @@ class DragTarget<T extends Object> extends StatefulWidget {
/// Called when a given piece of data being dragged over this target leaves /// Called when a given piece of data being dragged over this target leaves
/// the target. /// the target.
final DragTargetLeave? onLeave; final DragTargetLeave<T>? onLeave;
/// Called when a [Draggable] moves within this [DragTarget]. /// Called when a [Draggable] moves within this [DragTarget].
/// ///
/// Note that this includes entering and leaving the target. /// Note that this includes entering and leaving the target.
final DragTargetMove? onMove; final DragTargetMove<T>? onMove;
/// How to behave during hit testing. /// How to behave during hit testing.
/// ///
...@@ -712,7 +712,7 @@ class _DragTargetState<T extends Object> extends State<DragTarget<T>> { ...@@ -712,7 +712,7 @@ class _DragTargetState<T extends Object> extends State<DragTarget<T>> {
_rejectedAvatars.remove(avatar); _rejectedAvatars.remove(avatar);
}); });
if (widget.onLeave != null) if (widget.onLeave != null)
widget.onLeave!(avatar.data); widget.onLeave!(avatar.data as T?);
} }
void didDrop(_DragAvatar<Object> avatar) { void didDrop(_DragAvatar<Object> avatar) {
...@@ -732,7 +732,7 @@ class _DragTargetState<T extends Object> extends State<DragTarget<T>> { ...@@ -732,7 +732,7 @@ class _DragTargetState<T extends Object> extends State<DragTarget<T>> {
if (!mounted) if (!mounted)
return; return;
if (widget.onMove != null) if (widget.onMove != null)
widget.onMove!(DragTargetDetails<dynamic>(data: avatar.data, offset: avatar._lastOffset!)); widget.onMove!(DragTargetDetails<T>(data: avatar.data! as T, offset: avatar._lastOffset!));
} }
@override @override
......
...@@ -85,6 +85,83 @@ void main() { ...@@ -85,6 +85,83 @@ void main() {
expect(moveCount, 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,
child: Text('Source'),
feedback: Text('Dragging'),
),
DragTarget<int>(
builder: (BuildContext context, List<int?> data, List<dynamic> rejects) {
return Container(height: 100.0, child: const 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 Container(height: 100.0, child: const 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 { testWidgets('Drag and drop - onLeave callback fires correctly', (WidgetTester tester) async {
final Map<String,int> leftBehind = <String,int>{ final Map<String,int> leftBehind = <String,int>{
'Target 1': 0, 'Target 1': 0,
...@@ -160,6 +237,81 @@ void main() { ...@@ -160,6 +237,81 @@ void main() {
expect(leftBehind['Target 2'], 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,
child: Text('Source'),
feedback: Text('Dragging'),
),
DragTarget<int>(
builder: (BuildContext context, List<int?> data, List<dynamic> rejects) {
return Container(height: 100.0, child: const 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 Container(height: 100.0, child: const 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 { testWidgets('Drag and drop - onMove callback fires correctly', (WidgetTester tester) async {
final Map<String,int> targetMoveCount = <String,int>{ final Map<String,int> targetMoveCount = <String,int>{
'Target 1': 0, 'Target 1': 0,
......
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