From 3ac8b26bc4503cbd2574ea52cc6e32a90b2a42bc Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 22 Apr 2025 10:45:01 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Introduces=20`PositionedGestureDeta?= =?UTF-8?q?ils`=20(#160714)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #101530 `PositionedGestureDetails` is an abstract interface that is meant to contain positions for pointer events. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- packages/flutter/lib/gestures.dart | 1 + .../lib/src/gestures/drag_details.dart | 141 ++++++----- .../flutter/lib/src/gestures/force_press.dart | 19 +- .../lib/src/gestures/gesture_details.dart | 43 ++++ .../flutter/lib/src/gestures/long_press.dart | 69 ++++-- .../flutter/lib/src/gestures/multitap.dart | 46 +++- packages/flutter/lib/src/gestures/scale.dart | 48 ++-- packages/flutter/lib/src/gestures/tap.dart | 39 +++- .../lib/src/gestures/tap_and_drag.dart | 131 +++++------ .../flutter/test/gestures/debug_test.dart | 220 ++++++++++++++++++ 10 files changed, 559 insertions(+), 198 deletions(-) create mode 100644 packages/flutter/lib/src/gestures/gesture_details.dart diff --git a/packages/flutter/lib/gestures.dart b/packages/flutter/lib/gestures.dart index 8a126894494..35851083943 100644 --- a/packages/flutter/lib/gestures.dart +++ b/packages/flutter/lib/gestures.dart @@ -17,6 +17,7 @@ export 'src/gestures/drag_details.dart'; export 'src/gestures/eager.dart'; export 'src/gestures/events.dart'; export 'src/gestures/force_press.dart'; +export 'src/gestures/gesture_details.dart'; export 'src/gestures/gesture_settings.dart'; export 'src/gestures/hit_test.dart'; export 'src/gestures/long_press.dart'; diff --git a/packages/flutter/lib/src/gestures/drag_details.dart b/packages/flutter/lib/src/gestures/drag_details.dart index ba32449979e..f672314f1bf 100644 --- a/packages/flutter/lib/src/gestures/drag_details.dart +++ b/packages/flutter/lib/src/gestures/drag_details.dart @@ -7,6 +7,7 @@ library; import 'package:flutter/foundation.dart'; +import 'gesture_details.dart'; import 'velocity_tracker.dart'; export 'dart:ui' show Offset, PointerDeviceKind; @@ -21,29 +22,25 @@ export 'velocity_tracker.dart' show Velocity; /// * [DragStartDetails], the details for [GestureDragStartCallback]. /// * [DragUpdateDetails], the details for [GestureDragUpdateCallback]. /// * [DragEndDetails], the details for [GestureDragEndCallback]. -class DragDownDetails { +class DragDownDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureDragDownCallback]. DragDownDetails({this.globalPosition = Offset.zero, Offset? localPosition}) : localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer contacted the screen. - /// - /// Defaults to the origin if not specified in the constructor. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position in the coordinate system of the event receiver at - /// which the pointer contacted the screen. - /// - /// Defaults to [globalPosition] if not specified in the constructor. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; @override - String toString() => '${objectRuntimeType(this, 'DragDownDetails')}($globalPosition)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + } } /// Signature for when a pointer has contacted the screen and might begin to @@ -62,46 +59,40 @@ typedef GestureDragDownCallback = void Function(DragDownDetails details); /// * [DragDownDetails], the details for [GestureDragDownCallback]. /// * [DragUpdateDetails], the details for [GestureDragUpdateCallback]. /// * [DragEndDetails], the details for [GestureDragEndCallback]. -class DragStartDetails { +class DragStartDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureDragStartCallback]. DragStartDetails({ - this.sourceTimeStamp, this.globalPosition = Offset.zero, Offset? localPosition, + this.sourceTimeStamp, this.kind, }) : localPosition = localPosition ?? globalPosition; + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override + final Offset globalPosition; + + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// Recorded timestamp of the source pointer event that triggered the drag /// event. /// /// Could be null if triggered from proxied events such as accessibility. final Duration? sourceTimeStamp; - /// The global position at which the pointer contacted the screen. - /// - /// Defaults to the origin if not specified in the constructor. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. - final Offset globalPosition; - - /// The local position in the coordinate system of the event receiver at - /// which the pointer contacted the screen. - /// - /// Defaults to [globalPosition] if not specified in the constructor. - final Offset localPosition; - /// The kind of the device that initiated the event. final PointerDeviceKind? kind; - // TODO(ianh): Expose the current position, so that you can have a no-jump - // drag even when disambiguating (though of course it would lag the finger - // instead). - @override - String toString() => '${objectRuntimeType(this, 'DragStartDetails')}($globalPosition)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); + properties.add(EnumProperty('kind', kind)); + } } /// {@template flutter.gestures.dragdetails.GestureDragStartCallback} @@ -122,17 +113,17 @@ typedef GestureDragStartCallback = void Function(DragStartDetails details); /// * [DragDownDetails], the details for [GestureDragDownCallback]. /// * [DragStartDetails], the details for [GestureDragStartCallback]. /// * [DragEndDetails], the details for [GestureDragEndCallback]. -class DragUpdateDetails { +class DragUpdateDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureDragUpdateCallback]. /// /// If [primaryDelta] is non-null, then its value must match one of the /// coordinates of [delta] and the other coordinate must be zero. DragUpdateDetails({ + required this.globalPosition, + Offset? localPosition, this.sourceTimeStamp, this.delta = Offset.zero, this.primaryDelta, - required this.globalPosition, - Offset? localPosition, }) : assert( primaryDelta == null || (primaryDelta == delta.dx && delta.dy == 0.0) || @@ -140,6 +131,14 @@ class DragUpdateDetails { ), localPosition = localPosition ?? globalPosition; + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override + final Offset globalPosition; + + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// Recorded timestamp of the source pointer event that triggered the drag /// event. /// @@ -169,22 +168,15 @@ class DragUpdateDetails { /// Defaults to null if not specified in the constructor. final double? primaryDelta; - /// The pointer's global position when it triggered this update. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. - final Offset globalPosition; - - /// The local position in the coordinate system of the event receiver at - /// which the pointer contacted the screen. - /// - /// Defaults to [globalPosition] if not specified in the constructor. - final Offset localPosition; - @override - String toString() => '${objectRuntimeType(this, 'DragUpdateDetails')}($delta)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); + properties.add(DiagnosticsProperty('delta', delta)); + properties.add(DoubleProperty('primaryDelta', primaryDelta)); + } } /// {@template flutter.gestures.dragdetails.GestureDragUpdateCallback} @@ -206,17 +198,17 @@ typedef GestureDragUpdateCallback = void Function(DragUpdateDetails details); /// * [DragDownDetails], the details for [GestureDragDownCallback]. /// * [DragStartDetails], the details for [GestureDragStartCallback]. /// * [DragUpdateDetails], the details for [GestureDragUpdateCallback]. -class DragEndDetails { +class DragEndDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureDragEndCallback]. /// /// If [primaryVelocity] is non-null, its value must match one of the /// coordinates of `velocity.pixelsPerSecond` and the other coordinate /// must be zero. DragEndDetails({ - this.velocity = Velocity.zero, - this.primaryVelocity, this.globalPosition = Offset.zero, Offset? localPosition, + this.velocity = Velocity.zero, + this.primaryVelocity, }) : assert( primaryVelocity == null || (primaryVelocity == velocity.pixelsPerSecond.dx && velocity.pixelsPerSecond.dy == 0) || @@ -224,6 +216,14 @@ class DragEndDetails { ), localPosition = localPosition ?? globalPosition; + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override + final Offset globalPosition; + + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// The velocity the pointer was moving when it stopped contacting the screen. /// /// Defaults to zero if not specified in the constructor. @@ -241,23 +241,12 @@ class DragEndDetails { /// Defaults to null if not specified in the constructor. final double? primaryVelocity; - /// The global position the pointer is located at when the drag - /// gesture has been completed. - /// - /// Defaults to the origin if not specified in the constructor. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. - final Offset globalPosition; - - /// The local position in the coordinate system of the event receiver when - /// the drag gesture has been completed. - /// - /// Defaults to [globalPosition] if not specified in the constructor. - final Offset localPosition; - @override - String toString() => '${objectRuntimeType(this, 'DragEndDetails')}($velocity)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DiagnosticsProperty('velocity', velocity)); + properties.add(DoubleProperty('primaryVelocity', primaryVelocity)); + } } diff --git a/packages/flutter/lib/src/gestures/force_press.dart b/packages/flutter/lib/src/gestures/force_press.dart index b90755e3265..e026e8b5ad7 100644 --- a/packages/flutter/lib/src/gestures/force_press.dart +++ b/packages/flutter/lib/src/gestures/force_press.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart' show clampDouble; +import 'package:flutter/foundation.dart'; import 'events.dart'; +import 'gesture_details.dart'; import 'recognizer.dart'; export 'dart:ui' show Offset, PointerDeviceKind; @@ -43,20 +44,30 @@ enum _ForceState { /// * [ForcePressGestureRecognizer.onStart], [ForcePressGestureRecognizer.onPeak], /// [ForcePressGestureRecognizer.onEnd], and [ForcePressGestureRecognizer.onUpdate] /// which use [ForcePressDetails]. -class ForcePressDetails { +class ForcePressDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureForcePressStartCallback], /// [GestureForcePressPeakCallback] or [GestureForcePressEndCallback]. ForcePressDetails({required this.globalPosition, Offset? localPosition, required this.pressure}) : localPosition = localPosition ?? globalPosition; - /// The global position at which the function was called. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the function was called. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The pressure of the pointer on the screen. final double pressure; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DoubleProperty('pressure', pressure)); + } } /// Signature used by a [ForcePressGestureRecognizer] for when a pointer has diff --git a/packages/flutter/lib/src/gestures/gesture_details.dart b/packages/flutter/lib/src/gestures/gesture_details.dart new file mode 100644 index 00000000000..8b9efa36046 --- /dev/null +++ b/packages/flutter/lib/src/gestures/gesture_details.dart @@ -0,0 +1,43 @@ +// 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. + +import 'dart:ui' show Offset; + +/// An abstract interface representing gesture details that include positional information. +/// +/// This class serve as a common interface for gesture details that involve positional data, +/// such as dragging and tapping. It simplifies gesture handling by enabling the use of shared logic +/// across multiple gesture types, users can create a method to handle a single gesture details +/// with this position information. For example: +/// +/// ```dart +/// void handlePositionedGestures(PositionedGestureDetails details) { +/// // Handle the positional information of the gesture details. +/// } +/// ``` +abstract interface class PositionedGestureDetails { + /// Creates details with positions. + const PositionedGestureDetails({required this.globalPosition, required this.localPosition}); + + /// {@template flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + /// The global position at which the pointer interacts with the screen. + /// + /// See also: + /// + /// * [localPosition], which is the [globalPosition] transformed to the + /// coordinate space of the event receiver. + /// {@endtemplate} + final Offset globalPosition; + + /// {@template flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + /// The local position in the coordinate system of the event receiver at + /// which the pointer interacts with the screen. + /// + /// See also: + /// + /// * [globalPosition], which is the global position at which the pointer + /// interacts with the screen. + /// {@endtemplate} + final Offset localPosition; +} diff --git a/packages/flutter/lib/src/gestures/long_press.dart b/packages/flutter/lib/src/gestures/long_press.dart index 5e5cfdca855..f4459a9cebe 100644 --- a/packages/flutter/lib/src/gestures/long_press.dart +++ b/packages/flutter/lib/src/gestures/long_press.dart @@ -5,8 +5,11 @@ /// @docImport 'package:flutter/widgets.dart'; library; +import 'package:flutter/foundation.dart'; + import 'constants.dart'; import 'events.dart'; +import 'gesture_details.dart'; import 'recognizer.dart'; import 'velocity_tracker.dart'; @@ -107,7 +110,7 @@ typedef GestureLongPressEndCallback = void Function(LongPressEndDetails details) /// passes these details. /// * [LongPressGestureRecognizer.onTertiaryLongPressDown], whose callback /// passes these details. -class LongPressDownDetails { +class LongPressDownDetails with Diagnosticable implements PositionedGestureDetails { /// Creates the details for a [GestureLongPressDownCallback]. /// /// If the `localPosition` argument is not specified, it will default to the @@ -115,14 +118,24 @@ class LongPressDownDetails { const LongPressDownDetails({this.globalPosition = Offset.zero, Offset? localPosition, this.kind}) : localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// The kind of the device that initiated the event. final PointerDeviceKind? kind; - /// The local position at which the pointer contacted the screen. - final Offset localPosition; + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(EnumProperty('kind', kind)); + } } /// Details for callbacks that use [GestureLongPressStartCallback]. @@ -132,16 +145,25 @@ class LongPressDownDetails { /// * [LongPressGestureRecognizer.onLongPressStart], which uses [GestureLongPressStartCallback]. /// * [LongPressMoveUpdateDetails], the details for [GestureLongPressMoveUpdateCallback] /// * [LongPressEndDetails], the details for [GestureLongPressEndCallback]. -class LongPressStartDetails { +class LongPressStartDetails with Diagnosticable implements PositionedGestureDetails { /// Creates the details for a [GestureLongPressStartCallback]. const LongPressStartDetails({this.globalPosition = Offset.zero, Offset? localPosition}) : localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer initially contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer initially contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + } } /// Details for callbacks that use [GestureLongPressMoveUpdateCallback]. @@ -151,7 +173,7 @@ class LongPressStartDetails { /// * [LongPressGestureRecognizer.onLongPressMoveUpdate], which uses [GestureLongPressMoveUpdateCallback]. /// * [LongPressEndDetails], the details for [GestureLongPressEndCallback] /// * [LongPressStartDetails], the details for [GestureLongPressStartCallback]. -class LongPressMoveUpdateDetails { +class LongPressMoveUpdateDetails with Diagnosticable implements PositionedGestureDetails { /// Creates the details for a [GestureLongPressMoveUpdateCallback]. const LongPressMoveUpdateDetails({ this.globalPosition = Offset.zero, @@ -161,10 +183,12 @@ class LongPressMoveUpdateDetails { }) : localPosition = localPosition ?? globalPosition, localOffsetFromOrigin = localOffsetFromOrigin ?? offsetFromOrigin; - /// The global position of the pointer when it triggered this update. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position of the pointer when it triggered this update. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// A delta offset from the point where the long press drag initially contacted @@ -176,6 +200,15 @@ class LongPressMoveUpdateDetails { /// the screen to the point where the pointer is currently located (the /// present [localPosition]) when this callback is triggered. final Offset localOffsetFromOrigin; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DiagnosticsProperty('offsetFromOrigin', offsetFromOrigin)); + properties.add(DiagnosticsProperty('localOffsetFromOrigin', localOffsetFromOrigin)); + } } /// Details for callbacks that use [GestureLongPressEndCallback]. @@ -185,7 +218,7 @@ class LongPressMoveUpdateDetails { /// * [LongPressGestureRecognizer.onLongPressEnd], which uses [GestureLongPressEndCallback]. /// * [LongPressMoveUpdateDetails], the details for [GestureLongPressMoveUpdateCallback]. /// * [LongPressStartDetails], the details for [GestureLongPressStartCallback]. -class LongPressEndDetails { +class LongPressEndDetails with Diagnosticable implements PositionedGestureDetails { /// Creates the details for a [GestureLongPressEndCallback]. const LongPressEndDetails({ this.globalPosition = Offset.zero, @@ -193,16 +226,26 @@ class LongPressEndDetails { this.velocity = Velocity.zero, }) : localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer lifted from the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The pointer's velocity when it stopped contacting the screen. /// /// Defaults to zero if not specified in the constructor. final Velocity velocity; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DiagnosticsProperty('velocity', velocity)); + } } /// Recognizes when the user has pressed down at the same location for a long diff --git a/packages/flutter/lib/src/gestures/multitap.dart b/packages/flutter/lib/src/gestures/multitap.dart index 15df0dedcf2..7a2075c4e4a 100644 --- a/packages/flutter/lib/src/gestures/multitap.dart +++ b/packages/flutter/lib/src/gestures/multitap.dart @@ -7,10 +7,13 @@ library; import 'dart:async'; +import 'package:flutter/foundation.dart'; + import 'arena.dart'; import 'binding.dart'; import 'constants.dart'; import 'events.dart'; +import 'gesture_details.dart'; import 'pointer_router.dart'; import 'recognizer.dart'; import 'tap.dart'; @@ -615,7 +618,7 @@ typedef GestureSerialTapDownCallback = void Function(SerialTapDownDetails detail /// /// * [SerialTapGestureRecognizer], which passes this information to its /// [SerialTapGestureRecognizer.onSerialTapDown] callback. -class SerialTapDownDetails { +class SerialTapDownDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureSerialTapDownCallback]. /// /// The `count` argument must be greater than zero. @@ -628,10 +631,12 @@ class SerialTapDownDetails { }) : assert(count > 0), localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The kind of the device that initiated the event. @@ -655,6 +660,16 @@ class SerialTapDownDetails { /// the two taps had too much distance between them), then this count will /// reset back to `1`, and a new series will have begun. final int count; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(EnumProperty('kind', kind)); + properties.add(IntProperty('buttons', buttons)); + properties.add(IntProperty('count', count)); + } } /// Signature used by [SerialTapGestureRecognizer.onSerialTapCancel] for when a @@ -669,7 +684,7 @@ typedef GestureSerialTapCancelCallback = void Function(SerialTapCancelDetails de /// /// * [SerialTapGestureRecognizer], which passes this information to its /// [SerialTapGestureRecognizer.onSerialTapCancel] callback. -class SerialTapCancelDetails { +class SerialTapCancelDetails with Diagnosticable { /// Creates details for a [GestureSerialTapCancelCallback]. /// /// The `count` argument must be greater than zero. @@ -682,6 +697,12 @@ class SerialTapCancelDetails { /// [SerialTapDownDetails.count] for the tap that is being canceled. See /// that field for more information on how this count is reported. final int count; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(IntProperty('count', count)); + } } /// Signature used by [SerialTapGestureRecognizer.onSerialTapUp] for when a @@ -695,7 +716,7 @@ typedef GestureSerialTapUpCallback = void Function(SerialTapUpDetails details); /// /// * [SerialTapGestureRecognizer], which passes this information to its /// [SerialTapGestureRecognizer.onSerialTapUp] callback. -class SerialTapUpDetails { +class SerialTapUpDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureSerialTapUpCallback]. /// /// The `count` argument must be greater than zero. @@ -707,10 +728,12 @@ class SerialTapUpDetails { }) : assert(count > 0), localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The kind of the device that initiated the event. @@ -727,6 +750,15 @@ class SerialTapUpDetails { /// the two taps had too much distance between them), then this count will /// reset back to `1`, and a new series will have begun. final int count; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(EnumProperty('kind', kind)); + properties.add(IntProperty('count', count)); + } } /// Recognizes serial taps (taps in a series). diff --git a/packages/flutter/lib/src/gestures/scale.dart b/packages/flutter/lib/src/gestures/scale.dart index 17452d6c65a..f869dbd7ec9 100644 --- a/packages/flutter/lib/src/gestures/scale.dart +++ b/packages/flutter/lib/src/gestures/scale.dart @@ -4,6 +4,8 @@ import 'dart:math' as math; +import 'package:flutter/foundation.dart'; + import 'constants.dart'; import 'events.dart'; import 'recognizer.dart'; @@ -92,7 +94,7 @@ class _PointerPanZoomData { } /// Details for [GestureScaleStartCallback]. -class ScaleStartDetails { +class ScaleStartDetails with Diagnosticable { /// Creates details for [GestureScaleStartCallback]. ScaleStartDetails({ this.focalPoint = Offset.zero, @@ -142,12 +144,17 @@ class ScaleStartDetails { final PointerDeviceKind? kind; @override - String toString() => - 'ScaleStartDetails(focalPoint: $focalPoint, localFocalPoint: $localFocalPoint, pointersCount: $pointerCount)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('focalPoint', focalPoint)); + properties.add(DiagnosticsProperty('localFocalPoint', localFocalPoint)); + properties.add(IntProperty('pointerCount', pointerCount)); + properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); + } } /// Details for [GestureScaleUpdateCallback]. -class ScaleUpdateDetails { +class ScaleUpdateDetails with Diagnosticable { /// Creates details for [GestureScaleUpdateCallback]. /// /// The [scale], [horizontalScale], and [verticalScale] arguments must be @@ -247,21 +254,22 @@ class ScaleUpdateDetails { final Duration? sourceTimeStamp; @override - String toString() => - 'ScaleUpdateDetails(' - 'focalPoint: $focalPoint,' - ' localFocalPoint: $localFocalPoint,' - ' scale: $scale,' - ' horizontalScale: $horizontalScale,' - ' verticalScale: $verticalScale,' - ' rotation: $rotation,' - ' pointerCount: $pointerCount,' - ' focalPointDelta: $focalPointDelta,' - ' sourceTimeStamp: $sourceTimeStamp)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('focalPointDelta', focalPointDelta)); + properties.add(DiagnosticsProperty('focalPoint', focalPoint)); + properties.add(DiagnosticsProperty('localFocalPoint', localFocalPoint)); + properties.add(DoubleProperty('scale', scale)); + properties.add(DoubleProperty('horizontalScale', horizontalScale)); + properties.add(DoubleProperty('verticalScale', verticalScale)); + properties.add(DoubleProperty('rotation', rotation)); + properties.add(IntProperty('pointerCount', pointerCount)); + properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); + } } /// Details for [GestureScaleEndCallback]. -class ScaleEndDetails { +class ScaleEndDetails with Diagnosticable { /// Creates details for [GestureScaleEndCallback]. ScaleEndDetails({this.velocity = Velocity.zero, this.scaleVelocity = 0, this.pointerCount = 0}); @@ -278,8 +286,12 @@ class ScaleEndDetails { final int pointerCount; @override - String toString() => - 'ScaleEndDetails(velocity: $velocity, scaleVelocity: $scaleVelocity, pointerCount: $pointerCount)'; + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('velocity', velocity)); + properties.add(DoubleProperty('scaleVelocity', scaleVelocity)); + properties.add(IntProperty('pointerCount', pointerCount)); + } } /// Signature for when the pointers in contact with the screen have established diff --git a/packages/flutter/lib/src/gestures/tap.dart b/packages/flutter/lib/src/gestures/tap.dart index aab4a8f0ac7..61f62fd193d 100644 --- a/packages/flutter/lib/src/gestures/tap.dart +++ b/packages/flutter/lib/src/gestures/tap.dart @@ -12,6 +12,7 @@ import 'package:flutter/foundation.dart'; import 'arena.dart'; import 'constants.dart'; import 'events.dart'; +import 'gesture_details.dart'; import 'recognizer.dart'; export 'dart:ui' show Offset, PointerDeviceKind; @@ -28,19 +29,29 @@ export 'events.dart' show PointerCancelEvent, PointerDownEvent, PointerEvent, Po /// /// * [GestureDetector.onTapDown], which receives this information. /// * [TapGestureRecognizer], which passes this information to one of its callbacks. -class TapDownDetails { +class TapDownDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureTapDownCallback]. TapDownDetails({this.globalPosition = Offset.zero, Offset? localPosition, this.kind}) : localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// The kind of the device that initiated the event. final PointerDeviceKind? kind; - /// The local position at which the pointer contacted the screen. - final Offset localPosition; + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(EnumProperty('kind', kind)); + } } /// {@template flutter.gestures.tap.GestureTapDownCallback} @@ -63,19 +74,29 @@ typedef GestureTapDownCallback = void Function(TapDownDetails details); /// /// * [GestureDetector.onTapUp], which receives this information. /// * [TapGestureRecognizer], which passes this information to one of its callbacks. -class TapUpDetails { +class TapUpDetails with Diagnosticable implements PositionedGestureDetails { /// Creates a [TapUpDetails] data object. - TapUpDetails({required this.kind, this.globalPosition = Offset.zero, Offset? localPosition}) + TapUpDetails({this.globalPosition = Offset.zero, Offset? localPosition, required this.kind}) : localPosition = localPosition ?? globalPosition; - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The kind of the device that initiated the event. final PointerDeviceKind kind; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('globalPosition', globalPosition)); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(EnumProperty('kind', kind)); + } } /// Details object for callbacks that use [GestureTapMoveCallback]. @@ -400,7 +421,7 @@ abstract class BaseTapGestureRecognizer extends PrimaryPointerGestureRecognizer defaultValue: _up?.position, ), ); - properties.add(DiagnosticsProperty('button', _down?.buttons, defaultValue: null)); + properties.add(IntProperty('button', _down?.buttons, defaultValue: null)); properties.add(FlagProperty('sentTapDown', value: _sentTapDown, ifTrue: 'sent tap down')); } } diff --git a/packages/flutter/lib/src/gestures/tap_and_drag.dart b/packages/flutter/lib/src/gestures/tap_and_drag.dart index 06b338ae6b1..5d30e9d7066 100644 --- a/packages/flutter/lib/src/gestures/tap_and_drag.dart +++ b/packages/flutter/lib/src/gestures/tap_and_drag.dart @@ -13,6 +13,7 @@ import 'package:flutter/foundation.dart'; import 'constants.dart'; import 'events.dart'; +import 'gesture_details.dart'; import 'monodrag.dart'; import 'recognizer.dart'; import 'scale.dart'; @@ -79,7 +80,7 @@ typedef GestureTapDragDownCallback = void Function(TapDragDownDetails details); /// * [TapDragStartDetails], the details for [GestureTapDragStartCallback]. /// * [TapDragUpdateDetails], the details for [GestureTapDragUpdateCallback]. /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. -class TapDragDownDetails with Diagnosticable { +class TapDragDownDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureTapDragDownCallback]. TapDragDownDetails({ required this.globalPosition, @@ -88,10 +89,12 @@ class TapDragDownDetails with Diagnosticable { required this.consecutiveTapCount, }); - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The kind of the device that initiated the event. @@ -106,8 +109,8 @@ class TapDragDownDetails with Diagnosticable { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('globalPosition', globalPosition)); properties.add(DiagnosticsProperty('localPosition', localPosition)); - properties.add(DiagnosticsProperty('kind', kind)); - properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); + properties.add(EnumProperty('kind', kind)); + properties.add(IntProperty('consecutiveTapCount', consecutiveTapCount)); } } @@ -130,19 +133,21 @@ typedef GestureTapDragUpCallback = void Function(TapDragUpDetails details); /// * [TapDragStartDetails], the details for [GestureTapDragStartCallback]. /// * [TapDragUpdateDetails], the details for [GestureTapDragUpdateCallback]. /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. -class TapDragUpDetails with Diagnosticable { +class TapDragUpDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureTapDragUpCallback]. TapDragUpDetails({ - required this.kind, required this.globalPosition, required this.localPosition, + required this.kind, required this.consecutiveTapCount, }); - /// The global position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override final Offset globalPosition; - /// The local position at which the pointer contacted the screen. + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override final Offset localPosition; /// The kind of the device that initiated the event. @@ -157,8 +162,8 @@ class TapDragUpDetails with Diagnosticable { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('globalPosition', globalPosition)); properties.add(DiagnosticsProperty('localPosition', localPosition)); - properties.add(DiagnosticsProperty('kind', kind)); - properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); + properties.add(EnumProperty('kind', kind)); + properties.add(IntProperty('consecutiveTapCount', consecutiveTapCount)); } } @@ -181,34 +186,30 @@ typedef GestureTapDragStartCallback = void Function(TapDragStartDetails details) /// * [TapDragUpDetails], the details for [GestureTapDragUpCallback]. /// * [TapDragUpdateDetails], the details for [GestureTapDragUpdateCallback]. /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. -class TapDragStartDetails with Diagnosticable { +class TapDragStartDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureTapDragStartCallback]. TapDragStartDetails({ - this.sourceTimeStamp, required this.globalPosition, required this.localPosition, + this.sourceTimeStamp, this.kind, required this.consecutiveTapCount, }); + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override + final Offset globalPosition; + + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// Recorded timestamp of the source pointer event that triggered the drag /// event. /// /// Could be null if triggered from proxied events such as accessibility. final Duration? sourceTimeStamp; - /// The global position at which the pointer contacted the screen. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. - final Offset globalPosition; - - /// The local position in the coordinate system of the event receiver at - /// which the pointer contacted the screen. - final Offset localPosition; - /// The kind of the device that initiated the event. final PointerDeviceKind? kind; @@ -219,11 +220,11 @@ class TapDragStartDetails with Diagnosticable { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); properties.add(DiagnosticsProperty('globalPosition', globalPosition)); properties.add(DiagnosticsProperty('localPosition', localPosition)); - properties.add(DiagnosticsProperty('kind', kind)); - properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); + properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); + properties.add(EnumProperty('kind', kind)); + properties.add(IntProperty('consecutiveTapCount', consecutiveTapCount)); } } @@ -246,18 +247,18 @@ typedef GestureTapDragUpdateCallback = void Function(TapDragUpdateDetails detail /// * [TapDragUpDetails], the details for [GestureTapDragUpCallback]. /// * [TapDragStartDetails], the details for [GestureTapDragStartCallback]. /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. -class TapDragUpdateDetails with Diagnosticable { +class TapDragUpdateDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureTapDragUpdateCallback]. /// /// If [primaryDelta] is non-null, then its value must match one of the /// coordinates of [delta] and the other coordinate must be zero. TapDragUpdateDetails({ + required this.globalPosition, + required this.localPosition, this.sourceTimeStamp, this.delta = Offset.zero, this.primaryDelta, - required this.globalPosition, this.kind, - required this.localPosition, required this.offsetFromOrigin, required this.localOffsetFromOrigin, required this.consecutiveTapCount, @@ -267,6 +268,14 @@ class TapDragUpdateDetails with Diagnosticable { (primaryDelta == delta.dy && delta.dx == 0.0), ); + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override + final Offset globalPosition; + + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// Recorded timestamp of the source pointer event that triggered the drag /// event. /// @@ -296,20 +305,6 @@ class TapDragUpdateDetails with Diagnosticable { /// Defaults to null if not specified in the constructor. final double? primaryDelta; - /// The pointer's global position when it triggered this update. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. - final Offset globalPosition; - - /// The local position in the coordinate system of the event receiver at - /// which the pointer contacted the screen. - /// - /// Defaults to [globalPosition] if not specified in the constructor. - final Offset localPosition; - /// The kind of the device that initiated the event. final PointerDeviceKind? kind; @@ -336,15 +331,15 @@ class TapDragUpdateDetails with Diagnosticable { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); - properties.add(DiagnosticsProperty('delta', delta)); - properties.add(DiagnosticsProperty('primaryDelta', primaryDelta)); properties.add(DiagnosticsProperty('globalPosition', globalPosition)); properties.add(DiagnosticsProperty('localPosition', localPosition)); - properties.add(DiagnosticsProperty('kind', kind)); + properties.add(DiagnosticsProperty('sourceTimeStamp', sourceTimeStamp)); + properties.add(DiagnosticsProperty('delta', delta)); + properties.add(DoubleProperty('primaryDelta', primaryDelta)); + properties.add(EnumProperty('kind', kind)); properties.add(DiagnosticsProperty('offsetFromOrigin', offsetFromOrigin)); properties.add(DiagnosticsProperty('localOffsetFromOrigin', localOffsetFromOrigin)); - properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); + properties.add(IntProperty('consecutiveTapCount', consecutiveTapCount)); } } @@ -367,14 +362,14 @@ typedef GestureTapDragEndCallback = void Function(TapDragEndDetails endDetails); /// * [TapDragUpDetails], the details for [GestureTapDragUpCallback]. /// * [TapDragStartDetails], the details for [GestureTapDragStartCallback]. /// * [TapDragUpdateDetails], the details for [GestureTapDragUpdateCallback]. -class TapDragEndDetails with Diagnosticable { +class TapDragEndDetails with Diagnosticable implements PositionedGestureDetails { /// Creates details for a [GestureTapDragEndCallback]. TapDragEndDetails({ + this.globalPosition = Offset.zero, + Offset? localPosition, this.velocity = Velocity.zero, this.primaryVelocity, required this.consecutiveTapCount, - this.globalPosition = Offset.zero, - Offset? localPosition, }) : assert( primaryVelocity == null || primaryVelocity == velocity.pixelsPerSecond.dx || @@ -382,6 +377,14 @@ class TapDragEndDetails with Diagnosticable { ), localPosition = localPosition ?? globalPosition; + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition} + @override + final Offset globalPosition; + + /// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition} + @override + final Offset localPosition; + /// The velocity the pointer was moving when it stopped contacting the screen. /// /// Defaults to zero if not specified in the constructor. @@ -403,28 +406,14 @@ class TapDragEndDetails with Diagnosticable { /// the number in the series this tap is. final int consecutiveTapCount; - /// The global position at which the pointer lifted from the screen. - /// - /// See also: - /// - /// * [localPosition], which is the [globalPosition] transformed to the - /// coordinate space of the event receiver. - final Offset globalPosition; - - /// The local position in the coordinate system of the event receiver at which - /// the pointer lifted from the screen. - /// - /// Defaults to [globalPosition] if not specified in the constructor. - final Offset localPosition; - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('velocity', velocity)); - properties.add(DiagnosticsProperty('primaryVelocity', primaryVelocity)); - properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); properties.add(DiagnosticsProperty('globalPosition', globalPosition)); properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DiagnosticsProperty('velocity', velocity)); + properties.add(DoubleProperty('primaryVelocity', primaryVelocity)); + properties.add(IntProperty('consecutiveTapCount', consecutiveTapCount)); } } @@ -1464,12 +1453,12 @@ class TapAndPanGestureRecognizer extends BaseTapAndDragGestureRecognizer { String get debugDescription => 'tap and pan'; } +/// {@macro flutter.gestures.selectionrecognizers.TapAndPanGestureRecognizer} @Deprecated( 'Use TapAndPanGestureRecognizer instead. ' 'TapAndPanGestureRecognizer works exactly the same but has a more disambiguated name from BaseTapAndDragGestureRecognizer. ' 'This feature was deprecated after v3.9.0-19.0.pre.', ) -/// {@macro flutter.gestures.selectionrecognizers.TapAndPanGestureRecognizer} class TapAndDragGestureRecognizer extends BaseTapAndDragGestureRecognizer { /// Create a gesture recognizer for interactions on a plane. @Deprecated( diff --git a/packages/flutter/test/gestures/debug_test.dart b/packages/flutter/test/gestures/debug_test.dart index 84913111622..701960d0372 100644 --- a/packages/flutter/test/gestures/debug_test.dart +++ b/packages/flutter/test/gestures/debug_test.dart @@ -223,4 +223,224 @@ void main() { GestureBinding.instance.gestureArena.close(1); tap.dispose(); }); + + test('Gesture details debugFillProperties', () { + final List<(Diagnosticable, List)> pairs = <(Diagnosticable, List)>[ + ( + DragDownDetails(), + ['globalPosition: Offset(0.0, 0.0)', 'localPosition: Offset(0.0, 0.0)'], + ), + ( + DragStartDetails(), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'sourceTimeStamp: null', + 'kind: null', + ], + ), + ( + DragUpdateDetails(globalPosition: Offset.zero), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'sourceTimeStamp: null', + 'delta: Offset(0.0, 0.0)', + 'primaryDelta: null', + ], + ), + ( + DragEndDetails(), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'velocity: Velocity(0.0, 0.0)', + 'primaryVelocity: null', + ], + ), + ( + ForcePressDetails(globalPosition: Offset.zero, pressure: 1.0), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'pressure: 1.0', + ], + ), + ( + const LongPressDownDetails(), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: null', + ], + ), + ( + const LongPressStartDetails(), + ['globalPosition: Offset(0.0, 0.0)', 'localPosition: Offset(0.0, 0.0)'], + ), + ( + const LongPressMoveUpdateDetails(), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'offsetFromOrigin: Offset(0.0, 0.0)', + 'localOffsetFromOrigin: Offset(0.0, 0.0)', + ], + ), + ( + const LongPressEndDetails(), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'velocity: Velocity(0.0, 0.0)', + ], + ), + ( + SerialTapDownDetails(kind: PointerDeviceKind.unknown), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: unknown', + 'buttons: 0', + 'count: 1', + ], + ), + (SerialTapCancelDetails(), ['count: 1']), + ( + SerialTapUpDetails(), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: null', + 'count: 1', + ], + ), + ( + ScaleStartDetails(), + [ + 'focalPoint: Offset(0.0, 0.0)', + 'localFocalPoint: Offset(0.0, 0.0)', + 'pointerCount: 0', + 'sourceTimeStamp: null', + ], + ), + ( + ScaleUpdateDetails(), + [ + 'focalPointDelta: Offset(0.0, 0.0)', + 'focalPoint: Offset(0.0, 0.0)', + 'localFocalPoint: Offset(0.0, 0.0)', + 'scale: 1.0', + 'horizontalScale: 1.0', + 'verticalScale: 1.0', + 'rotation: 0.0', + 'pointerCount: 0', + 'sourceTimeStamp: null', + ], + ), + ( + ScaleEndDetails(), + ['velocity: Velocity(0.0, 0.0)', 'scaleVelocity: 0.0', 'pointerCount: 0'], + ), + ( + TapDownDetails(kind: PointerDeviceKind.unknown), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: unknown', + ], + ), + ( + TapUpDetails(kind: PointerDeviceKind.unknown), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: unknown', + ], + ), + ( + TapDragDownDetails( + globalPosition: Offset.zero, + localPosition: Offset.zero, + consecutiveTapCount: 1, + ), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: null', + 'consecutiveTapCount: 1', + ], + ), + ( + TapDragUpDetails( + globalPosition: Offset.zero, + localPosition: Offset.zero, + kind: PointerDeviceKind.unknown, + consecutiveTapCount: 1, + ), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'kind: unknown', + 'consecutiveTapCount: 1', + ], + ), + ( + TapDragStartDetails( + globalPosition: Offset.zero, + localPosition: Offset.zero, + consecutiveTapCount: 1, + ), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'sourceTimeStamp: null', + 'kind: null', + 'consecutiveTapCount: 1', + ], + ), + ( + TapDragUpdateDetails( + globalPosition: Offset.zero, + localPosition: Offset.zero, + offsetFromOrigin: Offset.zero, + localOffsetFromOrigin: Offset.zero, + consecutiveTapCount: 1, + ), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'sourceTimeStamp: null', + 'delta: Offset(0.0, 0.0)', + 'primaryDelta: null', + 'kind: null', + 'offsetFromOrigin: Offset(0.0, 0.0)', + 'localOffsetFromOrigin: Offset(0.0, 0.0)', + 'consecutiveTapCount: 1', + ], + ), + ( + TapDragEndDetails(consecutiveTapCount: 1), + [ + 'globalPosition: Offset(0.0, 0.0)', + 'localPosition: Offset(0.0, 0.0)', + 'velocity: Velocity(0.0, 0.0)', + 'primaryVelocity: null', + 'consecutiveTapCount: 1', + ], + ), + ]; + + for (final (Diagnosticable detail, List expected) in pairs) { + final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); + // ignore: invalid_use_of_protected_member + detail.debugFillProperties(builder); + final List description = + builder.properties + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); + expect(description, expected); + } + }); }