forked from firka/flutter
add PointerDeviceKind to ScaleStartDetails (#165096)
Adds the `PointerDeviceKind` of the scale start event to `ScaleStartDetails`, which is currently missing. This is a bug according to #115061. Additionally, according to the docs: >Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan. Just use the scale gesture recognizer. See also #135936 for similar issues and the PRs fixing them. If multiple pointers are contacting the screen at scale start, then the `PointerDeviceKind` of the first pointer is used. In practice this should be good enough as I don't know of any UI that expects you to use two different pointer kinds at the same time. However, if this is an issue, we could either give a list of pointers with their kinds or a set of all active `PointerDeviceKind`s. I don't think this is necessary though. Closes #115061. ## 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]. <!-- Links --> [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
This commit is contained in:
@@ -99,6 +99,7 @@ class ScaleStartDetails {
|
||||
Offset? localFocalPoint,
|
||||
this.pointerCount = 0,
|
||||
this.sourceTimeStamp,
|
||||
this.kind,
|
||||
}) : localFocalPoint = localFocalPoint ?? focalPoint;
|
||||
|
||||
/// The initial focal point of the pointers in contact with the screen.
|
||||
@@ -134,6 +135,12 @@ class ScaleStartDetails {
|
||||
/// Could be null if triggered from proxied events such as accessibility.
|
||||
final Duration? sourceTimeStamp;
|
||||
|
||||
/// The kind of the device that initiated the event.
|
||||
///
|
||||
/// If multiple pointers are touching the screen, the kind of the pointer
|
||||
/// device that first initiated the event is used.
|
||||
final PointerDeviceKind? kind;
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'ScaleStartDetails(focalPoint: $focalPoint, localFocalPoint: $localFocalPoint, pointersCount: $pointerCount)';
|
||||
@@ -771,6 +778,12 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
|
||||
localFocalPoint: _localFocalPoint,
|
||||
pointerCount: pointerCount,
|
||||
sourceTimeStamp: _initialEventTimestamp,
|
||||
kind:
|
||||
_pointerQueue.isNotEmpty
|
||||
? getKindForPointer(_pointerQueue.first)
|
||||
: _pointerPanZooms.isNotEmpty
|
||||
? getKindForPointer(_pointerPanZooms.keys.first)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1830,4 +1830,91 @@ void main() {
|
||||
tap.dispose();
|
||||
},
|
||||
);
|
||||
|
||||
testGesture('ScaleStartDetails should contain the correct PointerDeviceKind', (
|
||||
GestureTester tester,
|
||||
) {
|
||||
final ScaleGestureRecognizer scale = ScaleGestureRecognizer();
|
||||
|
||||
bool didStartScale = false;
|
||||
PointerDeviceKind? updatedKind;
|
||||
scale.onStart = (ScaleStartDetails details) {
|
||||
didStartScale = true;
|
||||
updatedKind = details.kind;
|
||||
};
|
||||
scale.onEnd = (ScaleEndDetails details) {
|
||||
didStartScale = false;
|
||||
};
|
||||
|
||||
// The default kind is touch.
|
||||
// ignore: avoid_redundant_argument_values
|
||||
final TestPointer pointer1 = TestPointer(1, PointerDeviceKind.touch);
|
||||
final PointerDownEvent down = pointer1.down(Offset.zero);
|
||||
scale.addPointer(down);
|
||||
tester.closeArena(1);
|
||||
// One-finger panning
|
||||
tester.route(down);
|
||||
tester.route(pointer1.move(const Offset(20.0, 30.0)));
|
||||
expect(didStartScale, isTrue);
|
||||
expect(updatedKind, PointerDeviceKind.touch);
|
||||
tester.route(pointer1.up());
|
||||
expect(didStartScale, isFalse);
|
||||
|
||||
final TestPointer pointer2 = TestPointer(2, PointerDeviceKind.mouse);
|
||||
final PointerDownEvent down2 = pointer2.down(const Offset(10.0, 20.0));
|
||||
scale.addPointer(down2);
|
||||
tester.closeArena(2);
|
||||
tester.route(down2);
|
||||
tester.route(pointer2.move(const Offset(20.0, 30.0)));
|
||||
expect(didStartScale, isTrue);
|
||||
expect(updatedKind, PointerDeviceKind.mouse);
|
||||
tester.route(pointer2.up());
|
||||
expect(didStartScale, isFalse);
|
||||
|
||||
final TestPointer pointer3 = TestPointer(3, PointerDeviceKind.stylus);
|
||||
final PointerDownEvent down3 = pointer3.down(const Offset(10.0, 20.0));
|
||||
scale.addPointer(down3);
|
||||
tester.closeArena(3);
|
||||
tester.route(down3);
|
||||
tester.route(pointer3.move(const Offset(20.0, 30.0)));
|
||||
expect(didStartScale, isTrue);
|
||||
expect(updatedKind, PointerDeviceKind.stylus);
|
||||
tester.route(pointer3.up());
|
||||
expect(didStartScale, isFalse);
|
||||
|
||||
final TestPointer pointer4 = TestPointer(4, PointerDeviceKind.invertedStylus);
|
||||
final PointerDownEvent down4 = pointer4.down(const Offset(10.0, 20.0));
|
||||
scale.addPointer(down4);
|
||||
tester.closeArena(4);
|
||||
tester.route(down4);
|
||||
tester.route(pointer4.move(const Offset(20.0, 30.0)));
|
||||
expect(didStartScale, isTrue);
|
||||
expect(updatedKind, PointerDeviceKind.invertedStylus);
|
||||
tester.route(pointer4.up());
|
||||
expect(didStartScale, isFalse);
|
||||
|
||||
final TestPointer pointer5 = TestPointer(5, PointerDeviceKind.unknown);
|
||||
final PointerDownEvent down5 = pointer5.down(const Offset(10.0, 20.0));
|
||||
scale.addPointer(down5);
|
||||
tester.closeArena(5);
|
||||
tester.route(down5);
|
||||
tester.route(pointer5.move(const Offset(20.0, 30.0)));
|
||||
expect(didStartScale, isTrue);
|
||||
expect(updatedKind, PointerDeviceKind.unknown);
|
||||
tester.route(pointer5.up());
|
||||
expect(didStartScale, isFalse);
|
||||
|
||||
final TestPointer pointer6 = TestPointer(6, PointerDeviceKind.trackpad);
|
||||
final PointerPanZoomStartEvent down6 = pointer6.panZoomStart(const Offset(10.0, 20.0));
|
||||
scale.addPointerPanZoom(down6);
|
||||
tester.closeArena(6);
|
||||
tester.route(down6);
|
||||
tester.route(pointer6.panZoomUpdate(const Offset(20.0, 30.0)));
|
||||
expect(didStartScale, isTrue);
|
||||
expect(updatedKind, PointerDeviceKind.trackpad);
|
||||
tester.route(pointer6.panZoomEnd());
|
||||
expect(didStartScale, isFalse);
|
||||
|
||||
scale.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user