Skip to content

Commit

Permalink
WidgetController.startGesture trackpad support (flutter#114631)
Browse files Browse the repository at this point in the history
  • Loading branch information
moffatman committed Nov 4, 2022
1 parent e1166e4 commit 48457d7
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 10 deletions.
16 changes: 11 additions & 5 deletions packages/flutter_test/lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1086,12 +1086,14 @@ abstract class WidgetController {
);
}

/// Creates a gesture with an initial down gesture at a particular point, and
/// returns the [TestGesture] object which you can use to continue the
/// gesture.
/// Creates a gesture with an initial appropriate starting gesture at a
/// particular point, and returns the [TestGesture] object which you can use
/// to continue the gesture. Usually, the starting gesture will be a down event,
/// but if [kind] is set to [PointerDeviceKind.trackpad], the gesture will start
/// with a panZoomStart gesture.
///
/// You can use [createGesture] if your gesture doesn't begin with an initial
/// down gesture.
/// down or panZoomStart gesture.
///
/// See also:
/// * [WidgetController.drag], a method to simulate a drag.
Expand All @@ -1110,7 +1112,11 @@ abstract class WidgetController {
kind: kind,
buttons: buttons,
);
await result.down(downLocation);
if (kind == PointerDeviceKind.trackpad) {
await result.panZoomStart(downLocation);
} else {
await result.down(downLocation);
}
return result;
}

Expand Down
32 changes: 27 additions & 5 deletions packages/flutter_test/lib/src/test_pointer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ class TestGesture {
/// Dispatch a pointer down event at the given `downLocation`, caching the
/// hit test result.
Future<void> down(Offset downLocation, { Duration timeStamp = Duration.zero }) async {
assert(_pointer.kind != PointerDeviceKind.trackpad, 'Trackpads are expected to send panZoomStart events, not down events.');
return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.down(downLocation, timeStamp: timeStamp));
});
Expand All @@ -463,6 +464,7 @@ class TestGesture {
/// Dispatch a pointer down event at the given `downLocation`, caching the
/// hit test result with a custom down event.
Future<void> downWithCustomEvent(Offset downLocation, PointerDownEvent event) async {
assert(_pointer.kind != PointerDeviceKind.trackpad, 'Trackpads are expected to send panZoomStart events, not down events');
_pointer.setDownInfo(event, downLocation);
return TestAsyncUtils.guard<void>(() async {
return _dispatcher(event);
Expand Down Expand Up @@ -507,7 +509,15 @@ class TestGesture {
/// * [WidgetController.fling], a method to simulate a fling.
Future<void> moveBy(Offset offset, { Duration timeStamp = Duration.zero }) {
assert(_pointer.location != null);
return moveTo(_pointer.location! + offset, timeStamp: timeStamp);
if (_pointer.isPanZoomActive) {
return panZoomUpdate(
_pointer.location!,
pan: (_pointer.pan ?? Offset.zero) + offset,
timeStamp: timeStamp
);
} else {
return moveTo(_pointer.location! + offset, timeStamp: timeStamp);
}
}

/// Send a move event moving the pointer to the given location.
Expand All @@ -521,6 +531,7 @@ class TestGesture {
/// It sends move events at a given frequency and it is useful when there are listeners involved.
/// * [WidgetController.fling], a method to simulate a fling.
Future<void> moveTo(Offset location, { Duration timeStamp = Duration.zero }) {
assert(_pointer.kind != PointerDeviceKind.trackpad);
return TestAsyncUtils.guard<void>(() {
if (_pointer._isDown) {
return _dispatcher(_pointer.move(location, timeStamp: timeStamp));
Expand All @@ -530,19 +541,27 @@ class TestGesture {
});
}

/// End the gesture by releasing the pointer.
/// End the gesture by releasing the pointer. For trackpad pointers this
/// will send a panZoomEnd event instead of an up event.
Future<void> up({ Duration timeStamp = Duration.zero }) {
return TestAsyncUtils.guard<void>(() async {
assert(_pointer._isDown);
await _dispatcher(_pointer.up(timeStamp: timeStamp));
assert(!_pointer._isDown);
if (_pointer.kind == PointerDeviceKind.trackpad) {
assert(_pointer._isPanZoomActive);
await _dispatcher(_pointer.panZoomEnd(timeStamp: timeStamp));
assert(!_pointer._isPanZoomActive);
} else {
assert(_pointer._isDown);
await _dispatcher(_pointer.up(timeStamp: timeStamp));
assert(!_pointer._isDown);
}
});
}

/// End the gesture by canceling the pointer (as would happen if the
/// system showed a modal dialog on top of the Flutter application,
/// for instance).
Future<void> cancel({ Duration timeStamp = Duration.zero }) {
assert(_pointer.kind != PointerDeviceKind.trackpad, 'Trackpads do not send cancel events.');
return TestAsyncUtils.guard<void>(() async {
assert(_pointer._isDown);
await _dispatcher(_pointer.cancel(timeStamp: timeStamp));
Expand All @@ -553,6 +572,7 @@ class TestGesture {
/// Dispatch a pointer pan zoom start event at the given `location`, caching the
/// hit test result.
Future<void> panZoomStart(Offset location, { Duration timeStamp = Duration.zero }) async {
assert(_pointer.kind == PointerDeviceKind.trackpad, 'Only trackpads can send PointerPanZoom events.');
return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.panZoomStart(location, timeStamp: timeStamp));
});
Expand All @@ -566,6 +586,7 @@ class TestGesture {
double rotation = 0,
Duration timeStamp = Duration.zero
}) async {
assert(_pointer.kind == PointerDeviceKind.trackpad, 'Only trackpads can send PointerPanZoom events.');
return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.panZoomUpdate(location,
pan: pan,
Expand All @@ -580,6 +601,7 @@ class TestGesture {
Future<void> panZoomEnd({
Duration timeStamp = Duration.zero
}) async {
assert(_pointer.kind == PointerDeviceKind.trackpad, 'Only trackpads can send PointerPanZoom events.');
return TestAsyncUtils.guard<void>(() async {
return _dispatcher(_pointer.panZoomEnd(
timeStamp: timeStamp
Expand Down
34 changes: 34 additions & 0 deletions packages/flutter_test/test/controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,40 @@ void main() {
},
);

testWidgets(
'WidgetTester.drag works with trackpad kind',
(WidgetTester tester) async {
final List<String> logs = <String>[];

await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Listener(
onPointerDown: (PointerDownEvent event) => logs.add('down ${event.buttons}'),
onPointerMove: (PointerMoveEvent event) => logs.add('move ${event.buttons}'),
onPointerUp: (PointerUpEvent event) => logs.add('up ${event.buttons}'),
onPointerPanZoomStart: (PointerPanZoomStartEvent event) => logs.add('panZoomStart'),
onPointerPanZoomUpdate: (PointerPanZoomUpdateEvent event) => logs.add('panZoomUpdate ${event.pan}'),
onPointerPanZoomEnd: (PointerPanZoomEndEvent event) => logs.add('panZoomEnd'),
child: const Text('test'),
),
),
);

await tester.drag(find.text('test'), const Offset(-150.0, 200.0), kind: PointerDeviceKind.trackpad);

for(int i = 0; i < logs.length; i++) {
if (i == 0) {
expect(logs[i], 'panZoomStart');
} else if (i != logs.length - 1) {
expect(logs[i], startsWith('panZoomUpdate'));
} else {
expect(logs[i], 'panZoomEnd');
}
}
},
);

testWidgets(
'WidgetTester.fling must respect buttons',
(WidgetTester tester) async {
Expand Down

0 comments on commit 48457d7

Please sign in to comment.