feat: Add velocity to DragTargetDetails

This commit adds a velocity parameter to the DragTargetDetails class, and where this class is used, supplies the velocity to this new parameter.

Fixes https://github.com/flutter/flutter/issues/165878
diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart
index 21fd3aa..bcabe27 100644
--- a/packages/flutter/lib/src/widgets/drag_target.dart
+++ b/packages/flutter/lib/src/widgets/drag_target.dart
@@ -594,7 +594,7 @@
 /// Represents the details when a pointer event occurred on the [DragTarget].
 class DragTargetDetails<T> {
   /// Creates details for a [DragTarget] callback.
-  DragTargetDetails({required this.data, required this.offset});
+  DragTargetDetails({required this.data, required this.offset, required this.velocity});
 
   /// The data that was dropped onto this [DragTarget].
   final T data;
@@ -602,6 +602,10 @@
   /// The global position when the specific pointer event occurred on
   /// the draggable.
   final Offset offset;
+
+  /// The velocity at which the pointer was moving when the specific pointer
+  /// event occurred on the draggable.
+  final Velocity velocity;
 }
 
 /// A widget that receives data when a [Draggable] widget is dropped.
@@ -757,9 +761,11 @@
         (widget.onWillAccept != null && widget.onWillAccept!(avatar.data as T?)) ||
         (widget.onWillAcceptWithDetails != null &&
             avatar.data != null &&
-            widget.onWillAcceptWithDetails!(
-              DragTargetDetails<T>(data: avatar.data! as T, offset: avatar._lastOffset!),
-            ));
+            widget.onWillAcceptWithDetails!(DragTargetDetails<T>(
+              data: avatar.data! as T,
+              offset: avatar._lastOffset!,
+              velocity: avatar.velocity,
+            )));
     if (resolvedWillAccept) {
       setState(() {
         _candidateAvatars.add(avatar);
@@ -795,9 +801,11 @@
     });
     if (avatar.data != null) {
       widget.onAccept?.call(avatar.data! as T);
-      widget.onAcceptWithDetails?.call(
-        DragTargetDetails<T>(data: avatar.data! as T, offset: avatar._lastOffset!),
-      );
+      widget.onAcceptWithDetails?.call(DragTargetDetails<T>(
+        data: avatar.data! as T,
+        offset: avatar._lastOffset!,
+        velocity: avatar.velocity,
+      ));
     }
   }
 
@@ -805,7 +813,11 @@
     if (!mounted || avatar.data == null) {
       return;
     }
-    widget.onMove?.call(DragTargetDetails<T>(data: avatar.data! as T, offset: avatar._lastOffset!));
+    widget.onMove?.call(DragTargetDetails<T>(
+      data: avatar.data! as T,
+      offset: avatar._lastOffset!,
+      velocity: avatar.velocity,
+    ));
   }
 
   @override
@@ -868,11 +880,13 @@
   Offset? _lastOffset;
   late Offset _overlayOffset;
   OverlayEntry? _entry;
+  Velocity velocity = Velocity.zero;
 
   @override
   void update(DragUpdateDetails details) {
     final Offset oldPosition = _position;
     _position += _restrictAxis(details.delta);
+    velocity = Velocity(pixelsPerSecond: _position);
     updateDrag(_position);
     if (onDragUpdate != null && _position != oldPosition) {
       onDragUpdate!(details);
diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart
index 110491c..da01bc1 100644
--- a/packages/flutter/test/widgets/draggable_test.dart
+++ b/packages/flutter/test/widgets/draggable_test.dart
@@ -87,6 +87,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -1253,6 +1254,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -1990,6 +1992,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -2134,6 +2137,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -2229,6 +2233,7 @@
     expect(acceptedDoubles, equals(<double>[1.0]));
     expect(acceptedDoublesDetails, hasLength(1));
     expect(acceptedDoublesDetails.first.offset, const Offset(112.0, 122.0));
+    expect(acceptedDoublesDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('IntDragging'), findsNothing);
     expect(find.text('DoubleDragging'), findsNothing);
 
@@ -2262,6 +2267,7 @@
     expect(acceptedInts, equals(<int>[1]));
     expect(acceptedIntsDetails, hasLength(1));
     expect(acceptedIntsDetails.first.offset, const Offset(184.0, 122.0));
+    expect(acceptedIntsDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(acceptedDoubles, isEmpty);
     expect(acceptedDoublesDetails, isEmpty);
     expect(find.text('IntDragging'), findsNothing);
@@ -2334,6 +2340,7 @@
       expect(acceptedDragTargetDatas, equals(<DragTargetData>[dragTargetData]));
       expect(acceptedDragTargetDataDetails, hasLength(1));
       expect(acceptedDragTargetDataDetails.first.offset, const Offset(256.0, 74.0));
+      expect(acceptedDragTargetDataDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
       expect(acceptedExtendedDragTargetDatas, isEmpty);
       expect(acceptedExtendedDragTargetDataDetails, isEmpty);
 
@@ -2443,6 +2450,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(256.0, 74.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsOneWidget);
     expect(find.text('Target'), findsOneWidget);
@@ -2453,7 +2461,9 @@
     expect(accepted, equals(<int>[1, 1]));
     expect(acceptedDetails, hasLength(2));
     expect(acceptedDetails[0].offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails[0].velocity, const Velocity(pixelsPerSecond: Offset(256.0, 74.0)));
     expect(acceptedDetails[1].offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails[1].velocity, const Velocity(pixelsPerSecond: Offset(256.0, 74.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -2464,7 +2474,9 @@
     expect(accepted, equals(<int>[1, 1]));
     expect(acceptedDetails, hasLength(2));
     expect(acceptedDetails[0].offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails[0].velocity, const Velocity(pixelsPerSecond: Offset(256.0, 74.0)));
     expect(acceptedDetails[1].offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails[1].velocity, const Velocity(pixelsPerSecond: Offset(256.0, 74.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -2759,6 +2771,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, const Offset(256.0, 26.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('Source'), findsNothing);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -2870,6 +2883,7 @@
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails, hasLength(1));
     expect(acceptedDetails.first.offset, expectedDropOffset);
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(256.0, 74.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);
@@ -2954,6 +2968,7 @@
 
     expect(accepted, equals(<int>[1]));
     expect(acceptedDetails.first.offset, const Offset(256.0, 74.0));
+    expect(acceptedDetails.first.velocity, const Velocity(pixelsPerSecond: Offset(400.0, 150.0)));
     expect(find.text('Source'), findsOneWidget);
     expect(find.text('Dragging'), findsNothing);
     expect(find.text('Target'), findsOneWidget);