Commit 51b1550d authored by Adam Barth's avatar Adam Barth

Delay win-by-default in gesture arena (#3552)

Wait until the end of the microtask to tell gesture recognizers that
they've won in the gesture arena. This lets recognizers dispose reject
themselves at arbitrary times without triggering gestures in awkward
call stacks.

Fixes #3183
parent c69f4396
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
/// Whether the gesture was accepted or rejected. /// Whether the gesture was accepted or rejected.
enum GestureDisposition { enum GestureDisposition {
/// This gesture was accepted as the interpretation of the user's input. /// This gesture was accepted as the interpretation of the user's input.
...@@ -130,12 +132,22 @@ class GestureArenaManager { ...@@ -130,12 +132,22 @@ class GestureArenaManager {
sweep(pointer); sweep(pointer);
} }
void _resolveByDefault(int pointer, _GestureArena state) {
if (!_arenas.containsKey(pointer))
return; // Already resolved earlier.
assert(_arenas[pointer] == state);
assert(!state.isOpen);
final List<GestureArenaMember> members = state.members;
assert(members.length == 1);
_arenas.remove(pointer);
state.members.first.acceptGesture(pointer);
}
void _tryToResolveArena(int pointer, _GestureArena state) { void _tryToResolveArena(int pointer, _GestureArena state) {
assert(_arenas[pointer] == state); assert(_arenas[pointer] == state);
assert(!state.isOpen); assert(!state.isOpen);
if (state.members.length == 1) { if (state.members.length == 1) {
_arenas.remove(pointer); scheduleMicrotask(() => _resolveByDefault(pointer, state));
state.members.first.acceptGesture(pointer);
} else if (state.members.isEmpty) { } else if (state.members.isEmpty) {
_arenas.remove(pointer); _arenas.remove(pointer);
} else if (state.eagerWinner != null) { } else if (state.eagerWinner != null) {
......
...@@ -8,10 +8,10 @@ import 'constants.dart'; ...@@ -8,10 +8,10 @@ import 'constants.dart';
import 'events.dart'; import 'events.dart';
import 'velocity_tracker.dart'; import 'velocity_tracker.dart';
enum DragState { enum _DragState {
ready, ready,
possible, possible,
accepted accepted,
} }
typedef void GestureDragDownCallback(Point globalPosition); typedef void GestureDragDownCallback(Point globalPosition);
...@@ -41,7 +41,7 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest ...@@ -41,7 +41,7 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
GestureDragEndCallback onEnd; GestureDragEndCallback onEnd;
GestureDragCancelCallback onCancel; GestureDragCancelCallback onCancel;
DragState _state = DragState.ready; _DragState _state = _DragState.ready;
Point _initialPosition; Point _initialPosition;
T _pendingDragDelta; T _pendingDragDelta;
...@@ -55,8 +55,8 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest ...@@ -55,8 +55,8 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
void addPointer(PointerEvent event) { void addPointer(PointerEvent event) {
startTrackingPointer(event.pointer); startTrackingPointer(event.pointer);
_velocityTrackers[event.pointer] = new VelocityTracker(); _velocityTrackers[event.pointer] = new VelocityTracker();
if (_state == DragState.ready) { if (_state == _DragState.ready) {
_state = DragState.possible; _state = _DragState.possible;
_initialPosition = event.position; _initialPosition = event.position;
_pendingDragDelta = _initialPendingDragDelta; _pendingDragDelta = _initialPendingDragDelta;
if (onDown != null) if (onDown != null)
...@@ -66,13 +66,13 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest ...@@ -66,13 +66,13 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
@override @override
void handleEvent(PointerEvent event) { void handleEvent(PointerEvent event) {
assert(_state != DragState.ready); assert(_state != _DragState.ready);
if (event is PointerMoveEvent) { if (event is PointerMoveEvent) {
VelocityTracker tracker = _velocityTrackers[event.pointer]; VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null); assert(tracker != null);
tracker.addPosition(event.timeStamp, event.position); tracker.addPosition(event.timeStamp, event.position);
T delta = _getDragDelta(event); T delta = _getDragDelta(event);
if (_state == DragState.accepted) { if (_state == _DragState.accepted) {
if (onUpdate != null) if (onUpdate != null)
onUpdate(delta); onUpdate(delta);
} else { } else {
...@@ -86,8 +86,8 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest ...@@ -86,8 +86,8 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
@override @override
void acceptGesture(int pointer) { void acceptGesture(int pointer) {
if (_state != DragState.accepted) { if (_state != _DragState.accepted) {
_state = DragState.accepted; _state = _DragState.accepted;
T delta = _pendingDragDelta; T delta = _pendingDragDelta;
_pendingDragDelta = _initialPendingDragDelta; _pendingDragDelta = _initialPendingDragDelta;
if (onStart != null) if (onStart != null)
...@@ -104,15 +104,15 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest ...@@ -104,15 +104,15 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
@override @override
void didStopTrackingLastPointer(int pointer) { void didStopTrackingLastPointer(int pointer) {
if (_state == DragState.possible) { if (_state == _DragState.possible) {
resolve(GestureDisposition.rejected); resolve(GestureDisposition.rejected);
_state = DragState.ready; _state = _DragState.ready;
if (onCancel != null) if (onCancel != null)
onCancel(); onCancel();
return; return;
} }
bool wasAccepted = (_state == DragState.accepted); bool wasAccepted = (_state == _DragState.accepted);
_state = DragState.ready; _state = _DragState.ready;
if (wasAccepted && onEnd != null) { if (wasAccepted && onEnd != null) {
VelocityTracker tracker = _velocityTrackers[pointer]; VelocityTracker tracker = _velocityTrackers[pointer];
assert(tracker != null); assert(tracker != null);
......
...@@ -168,7 +168,8 @@ abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> exten ...@@ -168,7 +168,8 @@ abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> exten
void acceptGesture(int pointer) { void acceptGesture(int pointer) {
assert(_pointers != null); assert(_pointers != null);
T state = _pointers[pointer]; T state = _pointers[pointer];
assert(state != null); if (state == null)
return; // We might already have canceled this drag if the up comes before the accept.
state.accepted((Point initialPosition) => _startDrag(initialPosition, pointer)); state.accepted((Point initialPosition) => _startDrag(initialPosition, pointer));
} }
......
...@@ -57,7 +57,7 @@ abstract class GestureRecognizer extends GestureArenaMember { ...@@ -57,7 +57,7 @@ abstract class GestureRecognizer extends GestureArenaMember {
/// which manages each pointer independently and can consider multiple /// which manages each pointer independently and can consider multiple
/// simultaneous touches to each result in a separate tap. /// simultaneous touches to each result in a separate tap.
abstract class OneSequenceGestureRecognizer extends GestureRecognizer { abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
final List<GestureArenaEntry> _entries = <GestureArenaEntry>[]; final Map<int, GestureArenaEntry> _entries = <int, GestureArenaEntry>{};
final Set<int> _trackedPointers = new HashSet<int>(); final Set<int> _trackedPointers = new HashSet<int>();
void handleEvent(PointerEvent event); void handleEvent(PointerEvent event);
...@@ -71,7 +71,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer { ...@@ -71,7 +71,7 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
void didStopTrackingLastPointer(int pointer); void didStopTrackingLastPointer(int pointer);
void resolve(GestureDisposition disposition) { void resolve(GestureDisposition disposition) {
List<GestureArenaEntry> localEntries = new List<GestureArenaEntry>.from(_entries); List<GestureArenaEntry> localEntries = new List<GestureArenaEntry>.from(_entries.values);
_entries.clear(); _entries.clear();
for (GestureArenaEntry entry in localEntries) for (GestureArenaEntry entry in localEntries)
entry.resolve(disposition); entry.resolve(disposition);
...@@ -89,7 +89,8 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer { ...@@ -89,7 +89,8 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
void startTrackingPointer(int pointer) { void startTrackingPointer(int pointer) {
GestureBinding.instance.pointerRouter.addRoute(pointer, handleEvent); GestureBinding.instance.pointerRouter.addRoute(pointer, handleEvent);
_trackedPointers.add(pointer); _trackedPointers.add(pointer);
_entries.add(GestureBinding.instance.gestureArena.add(pointer, this)); assert(!_entries.containsValue(pointer));
_entries[pointer] = GestureBinding.instance.gestureArena.add(pointer, this);
} }
void stopTrackingPointer(int pointer) { void stopTrackingPointer(int pointer) {
......
...@@ -86,7 +86,7 @@ void main() { ...@@ -86,7 +86,7 @@ void main() {
position: const Point(11.0, 9.0) position: const Point(11.0, 9.0)
); );
test('Should recognize double tap', () { testGesture('Should recognize double tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -95,23 +95,23 @@ void main() { ...@@ -95,23 +95,23 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
...@@ -119,7 +119,7 @@ void main() { ...@@ -119,7 +119,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Inter-tap distance cancels double tap', () { testGesture('Inter-tap distance cancels double tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -128,23 +128,23 @@ void main() { ...@@ -128,23 +128,23 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down3); tap.addPointer(down3);
GestureBinding.instance.gestureArena.close(3); tester.closeArena(3);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down3); tester.route(down3);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up3); tester.route(up3);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(3); GestureBinding.instance.gestureArena.sweep(3);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -152,7 +152,7 @@ void main() { ...@@ -152,7 +152,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Intra-tap distance cancels double tap', () { testGesture('Intra-tap distance cancels double tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -161,25 +161,25 @@ void main() { ...@@ -161,25 +161,25 @@ void main() {
}; };
tap.addPointer(down4); tap.addPointer(down4);
GestureBinding.instance.gestureArena.close(4); tester.closeArena(4);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down4); tester.route(down4);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(move4); tester.route(move4);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up4); tester.route(up4);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(4); GestureBinding.instance.gestureArena.sweep(4);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -187,7 +187,7 @@ void main() { ...@@ -187,7 +187,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Inter-tap delay cancels double tap', () { testGesture('Inter-tap delay cancels double tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -195,35 +195,33 @@ void main() { ...@@ -195,35 +195,33 @@ void main() {
doubleTapRecognized = true; doubleTapRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { tap.addPointer(down1);
tap.addPointer(down1); tester.closeArena(1);
GestureBinding.instance.gestureArena.close(1); expect(doubleTapRecognized, isFalse);
expect(doubleTapRecognized, isFalse); tester.route(down1);
GestureBinding.instance.pointerRouter.route(down1); expect(doubleTapRecognized, isFalse);
expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
async.elapse(new Duration(milliseconds: 5000)); tester.async.elapse(new Duration(milliseconds: 5000));
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
});
tap.dispose(); tap.dispose();
}); });
test('Inter-tap delay resets double tap, allowing third tap to be a double-tap', () { testGesture('Inter-tap delay resets double tap, allowing third tap to be a double-tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -231,47 +229,45 @@ void main() { ...@@ -231,47 +229,45 @@ void main() {
doubleTapRecognized = true; doubleTapRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { tap.addPointer(down1);
tap.addPointer(down1); tester.closeArena(1);
GestureBinding.instance.gestureArena.close(1); expect(doubleTapRecognized, isFalse);
expect(doubleTapRecognized, isFalse); tester.route(down1);
GestureBinding.instance.pointerRouter.route(down1); expect(doubleTapRecognized, isFalse);
expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
async.elapse(new Duration(milliseconds: 5000)); tester.async.elapse(new Duration(milliseconds: 5000));
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
async.elapse(new Duration(milliseconds: 100)); tester.async.elapse(new Duration(milliseconds: 100));
tap.addPointer(down5); tap.addPointer(down5);
GestureBinding.instance.gestureArena.close(5); tester.closeArena(5);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down5); tester.route(down5);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up5); tester.route(up5);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
GestureBinding.instance.gestureArena.sweep(5); GestureBinding.instance.gestureArena.sweep(5);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
});
tap.dispose(); tap.dispose();
}); });
test('Intra-tap delay does not cancel double tap', () { testGesture('Intra-tap delay does not cancel double tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -279,35 +275,33 @@ void main() { ...@@ -279,35 +275,33 @@ void main() {
doubleTapRecognized = true; doubleTapRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { tap.addPointer(down1);
tap.addPointer(down1); tester.closeArena(1);
GestureBinding.instance.gestureArena.close(1); expect(doubleTapRecognized, isFalse);
expect(doubleTapRecognized, isFalse); tester.route(down1);
GestureBinding.instance.pointerRouter.route(down1); expect(doubleTapRecognized, isFalse);
expect(doubleTapRecognized, isFalse);
async.elapse(new Duration(milliseconds: 1000)); tester.async.elapse(new Duration(milliseconds: 1000));
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
});
tap.dispose(); tap.dispose();
}); });
test('Should not recognize two overlapping taps', () { testGesture('Should not recognize two overlapping taps', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -316,23 +310,23 @@ void main() { ...@@ -316,23 +310,23 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -340,7 +334,7 @@ void main() { ...@@ -340,7 +334,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Should recognize one tap of group followed by second tap', () { testGesture('Should recognize one tap of group followed by second tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -349,34 +343,34 @@ void main() { ...@@ -349,34 +343,34 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isTrue); expect(doubleTapRecognized, isTrue);
...@@ -385,7 +379,7 @@ void main() { ...@@ -385,7 +379,7 @@ void main() {
}); });
test('Should cancel on arena reject during first tap', () { testGesture('Should cancel on arena reject during first tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -396,12 +390,12 @@ void main() { ...@@ -396,12 +390,12 @@ void main() {
tap.addPointer(down1); tap.addPointer(down1);
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member); GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
entry.resolve(GestureDisposition.accepted); entry.resolve(GestureDisposition.accepted);
expect(member.accepted, isTrue); expect(member.accepted, isTrue);
...@@ -410,12 +404,12 @@ void main() { ...@@ -410,12 +404,12 @@ void main() {
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -423,7 +417,7 @@ void main() { ...@@ -423,7 +417,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Should cancel on arena reject between taps', () { testGesture('Should cancel on arena reject between taps', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -434,12 +428,12 @@ void main() { ...@@ -434,12 +428,12 @@ void main() {
tap.addPointer(down1); tap.addPointer(down1);
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member); GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -448,12 +442,12 @@ void main() { ...@@ -448,12 +442,12 @@ void main() {
expect(member.accepted, isTrue); expect(member.accepted, isTrue);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -461,7 +455,7 @@ void main() { ...@@ -461,7 +455,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Should cancel on arena reject during last tap', () { testGesture('Should cancel on arena reject during last tap', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -472,26 +466,26 @@ void main() { ...@@ -472,26 +466,26 @@ void main() {
tap.addPointer(down1); tap.addPointer(down1);
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member); GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down2); tester.route(down2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
entry.resolve(GestureDisposition.accepted); entry.resolve(GestureDisposition.accepted);
expect(member.accepted, isTrue); expect(member.accepted, isTrue);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
...@@ -499,7 +493,7 @@ void main() { ...@@ -499,7 +493,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Passive gesture should trigger on double tap cancel', () { testGesture('Passive gesture should trigger on double tap cancel', (GestureTester tester) {
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
bool doubleTapRecognized = false; bool doubleTapRecognized = false;
...@@ -511,12 +505,12 @@ void main() { ...@@ -511,12 +505,12 @@ void main() {
tap.addPointer(down1); tap.addPointer(down1);
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureBinding.instance.gestureArena.add(1, member); GestureBinding.instance.gestureArena.add(1, member);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart';
import 'package:quiver/testing/async.dart';
class TestGestureFlutterBinding extends BindingBase with GestureBinding { } class TestGestureFlutterBinding extends BindingBase with GestureBinding { }
...@@ -12,3 +14,28 @@ void ensureGestureBinding() { ...@@ -12,3 +14,28 @@ void ensureGestureBinding() {
new TestGestureFlutterBinding(); new TestGestureFlutterBinding();
assert(GestureBinding.instance != null); assert(GestureBinding.instance != null);
} }
class GestureTester {
GestureTester._(this.async);
final FakeAsync async;
void closeArena(int pointer) {
GestureBinding.instance.gestureArena.close(pointer);
}
void route(PointerEvent event) {
GestureBinding.instance.pointerRouter.route(event);
async.flushMicrotasks();
}
}
typedef void GestureTest(GestureTester tester);
void testGesture(String description, GestureTest callback) {
test(description, () {
new FakeAsync().run((FakeAsync async) {
callback(new GestureTester._(async));
});
});
}
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:quiver/testing/async.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
...@@ -21,7 +20,7 @@ const PointerUpEvent up = const PointerUpEvent( ...@@ -21,7 +20,7 @@ const PointerUpEvent up = const PointerUpEvent(
void main() { void main() {
setUp(ensureGestureBinding); setUp(ensureGestureBinding);
test('Should recognize long press', () { testGesture('Should recognize long press', (GestureTester tester) {
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(); LongPressGestureRecognizer longPress = new LongPressGestureRecognizer();
bool longPressRecognized = false; bool longPressRecognized = false;
...@@ -29,22 +28,20 @@ void main() { ...@@ -29,22 +28,20 @@ void main() {
longPressRecognized = true; longPressRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { longPress.addPointer(down);
longPress.addPointer(down); tester.closeArena(5);
GestureBinding.instance.gestureArena.close(5); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.route(down);
GestureBinding.instance.pointerRouter.route(down); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.async.elapse(const Duration(milliseconds: 300));
async.elapse(const Duration(milliseconds: 300)); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.async.elapse(const Duration(milliseconds: 700));
async.elapse(const Duration(milliseconds: 700)); expect(longPressRecognized, isTrue);
expect(longPressRecognized, isTrue);
});
longPress.dispose(); longPress.dispose();
}); });
test('Up cancels long press', () { testGesture('Up cancels long press', (GestureTester tester) {
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(); LongPressGestureRecognizer longPress = new LongPressGestureRecognizer();
bool longPressRecognized = false; bool longPressRecognized = false;
...@@ -52,24 +49,22 @@ void main() { ...@@ -52,24 +49,22 @@ void main() {
longPressRecognized = true; longPressRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { longPress.addPointer(down);
longPress.addPointer(down); tester.closeArena(5);
GestureBinding.instance.gestureArena.close(5); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.route(down);
GestureBinding.instance.pointerRouter.route(down); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.async.elapse(const Duration(milliseconds: 300));
async.elapse(const Duration(milliseconds: 300)); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.route(up);
GestureBinding.instance.pointerRouter.route(up); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.async.elapse(const Duration(seconds: 1));
async.elapse(const Duration(seconds: 1)); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse);
});
longPress.dispose(); longPress.dispose();
}); });
test('Should recognize both tap down and long press', () { testGesture('Should recognize both tap down and long press', (GestureTester tester) {
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer(); LongPressGestureRecognizer longPress = new LongPressGestureRecognizer();
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
...@@ -83,24 +78,63 @@ void main() { ...@@ -83,24 +78,63 @@ void main() {
longPressRecognized = true; longPressRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { tap.addPointer(down);
tap.addPointer(down); longPress.addPointer(down);
longPress.addPointer(down); tester.closeArena(5);
GestureBinding.instance.gestureArena.close(5); expect(tapDownRecognized, isFalse);
expect(tapDownRecognized, isFalse); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.route(down);
GestureBinding.instance.pointerRouter.route(down); expect(tapDownRecognized, isFalse);
expect(tapDownRecognized, isFalse); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.async.elapse(const Duration(milliseconds: 300));
async.elapse(const Duration(milliseconds: 300)); expect(tapDownRecognized, isTrue);
expect(tapDownRecognized, isTrue); expect(longPressRecognized, isFalse);
expect(longPressRecognized, isFalse); tester.async.elapse(const Duration(milliseconds: 700));
async.elapse(const Duration(milliseconds: 700)); expect(tapDownRecognized, isTrue);
expect(tapDownRecognized, isTrue); expect(longPressRecognized, isTrue);
expect(longPressRecognized, isTrue);
});
tap.dispose(); tap.dispose();
longPress.dispose(); longPress.dispose();
}); });
testGesture('Drag start delayed by microtask', (GestureTester tester) {
LongPressGestureRecognizer longPress = new LongPressGestureRecognizer();
HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
bool isDangerousStack = false;
bool dragStartRecognized = false;
drag.onStart = (Point globalPosition) {
expect(isDangerousStack, isFalse);
dragStartRecognized = true;
};
bool longPressRecognized = false;
longPress.onLongPress = () {
expect(isDangerousStack, isFalse);
longPressRecognized = true;
};
drag.addPointer(down);
longPress.addPointer(down);
tester.closeArena(5);
expect(dragStartRecognized, isFalse);
expect(longPressRecognized, isFalse);
tester.route(down);
expect(dragStartRecognized, isFalse);
expect(longPressRecognized, isFalse);
tester.async.elapse(const Duration(milliseconds: 300));
expect(dragStartRecognized, isFalse);
expect(longPressRecognized, isFalse);
isDangerousStack = true;
longPress.dispose();
isDangerousStack = false;
expect(dragStartRecognized, isFalse);
expect(longPressRecognized, isFalse);
tester.async.flushMicrotasks();
expect(dragStartRecognized, isTrue);
expect(longPressRecognized, isFalse);
drag.dispose();
});
} }
...@@ -11,9 +11,7 @@ import 'gesture_tester.dart'; ...@@ -11,9 +11,7 @@ import 'gesture_tester.dart';
void main() { void main() {
setUp(ensureGestureBinding); setUp(ensureGestureBinding);
test('Should recognize scale gestures', () { testGesture('Should recognize scale gestures', (GestureTester tester) {
GestureArenaManager gestureArena = GestureBinding.instance.gestureArena;
PointerRouter pointerRouter = GestureBinding.instance.pointerRouter;
ScaleGestureRecognizer scale = new ScaleGestureRecognizer(); ScaleGestureRecognizer scale = new ScaleGestureRecognizer();
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
...@@ -46,7 +44,7 @@ void main() { ...@@ -46,7 +44,7 @@ void main() {
scale.addPointer(down); scale.addPointer(down);
tap.addPointer(down); tap.addPointer(down);
gestureArena.close(1); tester.closeArena(1);
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedScale, isNull); expect(updatedScale, isNull);
expect(updatedFocalPoint, isNull); expect(updatedFocalPoint, isNull);
...@@ -54,14 +52,14 @@ void main() { ...@@ -54,14 +52,14 @@ void main() {
expect(didTap, isFalse); expect(didTap, isFalse);
// One-finger panning // One-finger panning
pointerRouter.route(down); tester.route(down);
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedScale, isNull); expect(updatedScale, isNull);
expect(updatedFocalPoint, isNull); expect(updatedFocalPoint, isNull);
expect(didEndScale, isFalse); expect(didEndScale, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
pointerRouter.route(pointer1.move(const Point(20.0, 30.0))); tester.route(pointer1.move(const Point(20.0, 30.0)));
expect(didStartScale, isTrue); expect(didStartScale, isTrue);
didStartScale = false; didStartScale = false;
expect(updatedFocalPoint, const Point(20.0, 30.0)); expect(updatedFocalPoint, const Point(20.0, 30.0));
...@@ -76,8 +74,8 @@ void main() { ...@@ -76,8 +74,8 @@ void main() {
PointerDownEvent down2 = pointer2.down(const Point(10.0, 20.0)); PointerDownEvent down2 = pointer2.down(const Point(10.0, 20.0));
scale.addPointer(down2); scale.addPointer(down2);
tap.addPointer(down2); tap.addPointer(down2);
gestureArena.close(2); tester.closeArena(2);
pointerRouter.route(down2); tester.route(down2);
expect(didEndScale, isTrue); expect(didEndScale, isTrue);
didEndScale = false; didEndScale = false;
...@@ -86,7 +84,7 @@ void main() { ...@@ -86,7 +84,7 @@ void main() {
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
// Zoom in // Zoom in
pointerRouter.route(pointer2.move(const Point(0.0, 10.0))); tester.route(pointer2.move(const Point(0.0, 10.0)));
expect(didStartScale, isTrue); expect(didStartScale, isTrue);
didStartScale = false; didStartScale = false;
expect(updatedFocalPoint, const Point(10.0, 20.0)); expect(updatedFocalPoint, const Point(10.0, 20.0));
...@@ -97,7 +95,7 @@ void main() { ...@@ -97,7 +95,7 @@ void main() {
expect(didTap, isFalse); expect(didTap, isFalse);
// Zoom out // Zoom out
pointerRouter.route(pointer2.move(const Point(15.0, 25.0))); tester.route(pointer2.move(const Point(15.0, 25.0)));
expect(updatedFocalPoint, const Point(17.5, 27.5)); expect(updatedFocalPoint, const Point(17.5, 27.5));
updatedFocalPoint = null; updatedFocalPoint = null;
expect(updatedScale, 0.5); expect(updatedScale, 0.5);
...@@ -109,8 +107,8 @@ void main() { ...@@ -109,8 +107,8 @@ void main() {
PointerDownEvent down3 = pointer3.down(const Point(25.0, 35.0)); PointerDownEvent down3 = pointer3.down(const Point(25.0, 35.0));
scale.addPointer(down3); scale.addPointer(down3);
tap.addPointer(down3); tap.addPointer(down3);
gestureArena.close(3); tester.closeArena(3);
pointerRouter.route(down3); tester.route(down3);
expect(didEndScale, isTrue); expect(didEndScale, isTrue);
didEndScale = false; didEndScale = false;
...@@ -119,7 +117,7 @@ void main() { ...@@ -119,7 +117,7 @@ void main() {
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
// Zoom in // Zoom in
pointerRouter.route(pointer3.move(const Point(55.0, 65.0))); tester.route(pointer3.move(const Point(55.0, 65.0)));
expect(didStartScale, isTrue); expect(didStartScale, isTrue);
didStartScale = false; didStartScale = false;
expect(updatedFocalPoint, const Point(30.0, 40.0)); expect(updatedFocalPoint, const Point(30.0, 40.0));
...@@ -130,9 +128,9 @@ void main() { ...@@ -130,9 +128,9 @@ void main() {
expect(didTap, isFalse); expect(didTap, isFalse);
// Return to original positions but with different fingers // Return to original positions but with different fingers
pointerRouter.route(pointer1.move(const Point(25.0, 35.0))); tester.route(pointer1.move(const Point(25.0, 35.0)));
pointerRouter.route(pointer2.move(const Point(20.0, 30.0))); tester.route(pointer2.move(const Point(20.0, 30.0)));
pointerRouter.route(pointer3.move(const Point(15.0, 25.0))); tester.route(pointer3.move(const Point(15.0, 25.0)));
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedFocalPoint, const Point(20.0, 30.0)); expect(updatedFocalPoint, const Point(20.0, 30.0));
updatedFocalPoint = null; updatedFocalPoint = null;
...@@ -141,7 +139,7 @@ void main() { ...@@ -141,7 +139,7 @@ void main() {
expect(didEndScale, isFalse); expect(didEndScale, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
pointerRouter.route(pointer1.up()); tester.route(pointer1.up());
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedFocalPoint, isNull); expect(updatedFocalPoint, isNull);
expect(updatedScale, isNull); expect(updatedScale, isNull);
...@@ -150,7 +148,7 @@ void main() { ...@@ -150,7 +148,7 @@ void main() {
expect(didTap, isFalse); expect(didTap, isFalse);
// Continue scaling with two fingers // Continue scaling with two fingers
pointerRouter.route(pointer3.move(const Point(10.0, 20.0))); tester.route(pointer3.move(const Point(10.0, 20.0)));
expect(didStartScale, isTrue); expect(didStartScale, isTrue);
didStartScale = false; didStartScale = false;
expect(updatedFocalPoint, const Point(15.0, 25.0)); expect(updatedFocalPoint, const Point(15.0, 25.0));
...@@ -158,7 +156,7 @@ void main() { ...@@ -158,7 +156,7 @@ void main() {
expect(updatedScale, 2.0); expect(updatedScale, 2.0);
updatedScale = null; updatedScale = null;
pointerRouter.route(pointer2.up()); tester.route(pointer2.up());
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedFocalPoint, isNull); expect(updatedFocalPoint, isNull);
expect(updatedScale, isNull); expect(updatedScale, isNull);
...@@ -167,7 +165,7 @@ void main() { ...@@ -167,7 +165,7 @@ void main() {
expect(didTap, isFalse); expect(didTap, isFalse);
// Continue panning with one finger // Continue panning with one finger
pointerRouter.route(pointer3.move(const Point(0.0, 0.0))); tester.route(pointer3.move(const Point(0.0, 0.0)));
expect(didStartScale, isTrue); expect(didStartScale, isTrue);
didStartScale = false; didStartScale = false;
expect(updatedFocalPoint, const Point(0.0, 0.0)); expect(updatedFocalPoint, const Point(0.0, 0.0));
...@@ -176,7 +174,7 @@ void main() { ...@@ -176,7 +174,7 @@ void main() {
updatedScale = null; updatedScale = null;
// We are done // We are done
pointerRouter.route(pointer3.up()); tester.route(pointer3.up());
expect(didStartScale, isFalse); expect(didStartScale, isFalse);
expect(updatedFocalPoint, isNull); expect(updatedFocalPoint, isNull);
expect(updatedScale, isNull); expect(updatedScale, isNull);
......
...@@ -11,9 +11,7 @@ import 'gesture_tester.dart'; ...@@ -11,9 +11,7 @@ import 'gesture_tester.dart';
void main() { void main() {
setUp(ensureGestureBinding); setUp(ensureGestureBinding);
test('Should recognize pan', () { testGesture('Should recognize pan', (GestureTester tester) {
GestureArenaManager gestureArena = GestureBinding.instance.gestureArena;
PointerRouter pointerRouter = GestureBinding.instance.pointerRouter;
PanGestureRecognizer pan = new PanGestureRecognizer(); PanGestureRecognizer pan = new PanGestureRecognizer();
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
...@@ -41,19 +39,19 @@ void main() { ...@@ -41,19 +39,19 @@ void main() {
PointerDownEvent down = pointer.down(const Point(10.0, 10.0)); PointerDownEvent down = pointer.down(const Point(10.0, 10.0));
pan.addPointer(down); pan.addPointer(down);
tap.addPointer(down); tap.addPointer(down);
gestureArena.close(5); tester.closeArena(5);
expect(didStartPan, isFalse); expect(didStartPan, isFalse);
expect(updatedScrollDelta, isNull); expect(updatedScrollDelta, isNull);
expect(didEndPan, isFalse); expect(didEndPan, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
pointerRouter.route(down); tester.route(down);
expect(didStartPan, isFalse); expect(didStartPan, isFalse);
expect(updatedScrollDelta, isNull); expect(updatedScrollDelta, isNull);
expect(didEndPan, isFalse); expect(didEndPan, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
pointerRouter.route(pointer.move(const Point(20.0, 20.0))); tester.route(pointer.move(const Point(20.0, 20.0)));
expect(didStartPan, isTrue); expect(didStartPan, isTrue);
didStartPan = false; didStartPan = false;
expect(updatedScrollDelta, const Offset(10.0, 10.0)); expect(updatedScrollDelta, const Offset(10.0, 10.0));
...@@ -61,14 +59,14 @@ void main() { ...@@ -61,14 +59,14 @@ void main() {
expect(didEndPan, isFalse); expect(didEndPan, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
pointerRouter.route(pointer.move(const Point(20.0, 25.0))); tester.route(pointer.move(const Point(20.0, 25.0)));
expect(didStartPan, isFalse); expect(didStartPan, isFalse);
expect(updatedScrollDelta, const Offset(0.0, 5.0)); expect(updatedScrollDelta, const Offset(0.0, 5.0));
updatedScrollDelta = null; updatedScrollDelta = null;
expect(didEndPan, isFalse); expect(didEndPan, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
pointerRouter.route(pointer.up()); tester.route(pointer.up());
expect(didStartPan, isFalse); expect(didStartPan, isFalse);
expect(updatedScrollDelta, isNull); expect(updatedScrollDelta, isNull);
expect(didEndPan, isTrue); expect(didEndPan, isTrue);
...@@ -78,4 +76,57 @@ void main() { ...@@ -78,4 +76,57 @@ void main() {
pan.dispose(); pan.dispose();
tap.dispose(); tap.dispose();
}); });
testGesture('Should recognize drag', (GestureTester tester) {
HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
bool didStartDrag = false;
drag.onStart = (_) {
didStartDrag = true;
};
double updatedDelta;
drag.onUpdate = (double delta) {
updatedDelta = delta;
};
bool didEndDrag = false;
drag.onEnd = (Velocity velocity) {
didEndDrag = true;
};
TestPointer pointer = new TestPointer(5);
PointerDownEvent down = pointer.down(const Point(10.0, 10.0));
drag.addPointer(down);
tester.closeArena(5);
expect(didStartDrag, isFalse);
expect(updatedDelta, isNull);
expect(didEndDrag, isFalse);
tester.route(down);
expect(didStartDrag, isTrue);
expect(updatedDelta, isNull);
expect(didEndDrag, isFalse);
tester.route(pointer.move(const Point(20.0, 25.0)));
expect(didStartDrag, isTrue);
didStartDrag = false;
expect(updatedDelta, 10.0);
updatedDelta = null;
expect(didEndDrag, isFalse);
tester.route(pointer.move(const Point(20.0, 25.0)));
expect(didStartDrag, isFalse);
expect(updatedDelta, 0.0);
updatedDelta = null;
expect(didEndDrag, isFalse);
tester.route(pointer.up());
expect(didStartDrag, isFalse);
expect(updatedDelta, isNull);
expect(didEndDrag, isTrue);
didEndDrag = false;
drag.dispose();
});
} }
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:quiver/testing/async.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'gesture_tester.dart'; import 'gesture_tester.dart';
...@@ -57,7 +56,7 @@ void main() { ...@@ -57,7 +56,7 @@ void main() {
position: const Point(25.0, 25.0) position: const Point(25.0, 25.0)
); );
test('Should recognize tap', () { testGesture('Should recognize tap', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
bool tapRecognized = false; bool tapRecognized = false;
...@@ -66,12 +65,12 @@ void main() { ...@@ -66,12 +65,12 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
...@@ -79,7 +78,7 @@ void main() { ...@@ -79,7 +78,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('No duplicate tap events', () { testGesture('No duplicate tap events', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
int tapsRecognized = 0; int tapsRecognized = 0;
...@@ -88,23 +87,23 @@ void main() { ...@@ -88,23 +87,23 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(tapsRecognized, 2); expect(tapsRecognized, 2);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(tapsRecognized, 2); expect(tapsRecognized, 2);
...@@ -112,7 +111,7 @@ void main() { ...@@ -112,7 +111,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Should not recognize two overlapping taps', () { testGesture('Should not recognize two overlapping taps', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
int tapsRecognized = 0; int tapsRecognized = 0;
...@@ -121,24 +120,24 @@ void main() { ...@@ -121,24 +120,24 @@ void main() {
}; };
tap.addPointer(down1); tap.addPointer(down1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
tap.addPointer(down2); tap.addPointer(down2);
GestureBinding.instance.gestureArena.close(2); tester.closeArena(2);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapsRecognized, 0); expect(tapsRecognized, 0);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureBinding.instance.pointerRouter.route(up2); tester.route(up2);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
GestureBinding.instance.gestureArena.sweep(2); GestureBinding.instance.gestureArena.sweep(2);
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
...@@ -146,7 +145,7 @@ void main() { ...@@ -146,7 +145,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Distance cancels tap', () { testGesture('Distance cancels tap', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
bool tapRecognized = false; bool tapRecognized = false;
...@@ -159,17 +158,17 @@ void main() { ...@@ -159,17 +158,17 @@ void main() {
}; };
tap.addPointer(down3); tap.addPointer(down3);
GestureBinding.instance.gestureArena.close(3); tester.closeArena(3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isFalse); expect(tapCanceled, isFalse);
GestureBinding.instance.pointerRouter.route(down3); tester.route(down3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isFalse); expect(tapCanceled, isFalse);
GestureBinding.instance.pointerRouter.route(move3); tester.route(move3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isTrue); expect(tapCanceled, isTrue);
GestureBinding.instance.pointerRouter.route(up3); tester.route(up3);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
expect(tapCanceled, isTrue); expect(tapCanceled, isTrue);
GestureBinding.instance.gestureArena.sweep(3); GestureBinding.instance.gestureArena.sweep(3);
...@@ -179,7 +178,7 @@ void main() { ...@@ -179,7 +178,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Timeout does not cancel tap', () { testGesture('Timeout does not cancel tap', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
bool tapRecognized = false; bool tapRecognized = false;
...@@ -187,25 +186,23 @@ void main() { ...@@ -187,25 +186,23 @@ void main() {
tapRecognized = true; tapRecognized = true;
}; };
new FakeAsync().run((FakeAsync async) { tap.addPointer(down1);
tap.addPointer(down1); tester.closeArena(1);
GestureBinding.instance.gestureArena.close(1); expect(tapRecognized, isFalse);
expect(tapRecognized, isFalse); tester.route(down1);
GestureBinding.instance.pointerRouter.route(down1); expect(tapRecognized, isFalse);
expect(tapRecognized, isFalse);
tester.async.elapse(new Duration(milliseconds: 500));
async.elapse(new Duration(milliseconds: 500)); expect(tapRecognized, isFalse);
expect(tapRecognized, isFalse); tester.route(up1);
GestureBinding.instance.pointerRouter.route(up1); expect(tapRecognized, isTrue);
expect(tapRecognized, isTrue); GestureBinding.instance.gestureArena.sweep(1);
GestureBinding.instance.gestureArena.sweep(1); expect(tapRecognized, isTrue);
expect(tapRecognized, isTrue);
});
tap.dispose(); tap.dispose();
}); });
test('Should yield to other arena members', () { testGesture('Should yield to other arena members', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
bool tapRecognized = false; bool tapRecognized = false;
...@@ -217,12 +214,12 @@ void main() { ...@@ -217,12 +214,12 @@ void main() {
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member); GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
GestureBinding.instance.gestureArena.hold(1); GestureBinding.instance.gestureArena.hold(1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
...@@ -233,7 +230,7 @@ void main() { ...@@ -233,7 +230,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Should trigger on release of held arena', () { testGesture('Should trigger on release of held arena', (GestureTester tester) {
TapGestureRecognizer tap = new TapGestureRecognizer(); TapGestureRecognizer tap = new TapGestureRecognizer();
bool tapRecognized = false; bool tapRecognized = false;
...@@ -245,17 +242,18 @@ void main() { ...@@ -245,17 +242,18 @@ void main() {
TestGestureArenaMember member = new TestGestureArenaMember(); TestGestureArenaMember member = new TestGestureArenaMember();
GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member); GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
GestureBinding.instance.gestureArena.hold(1); GestureBinding.instance.gestureArena.hold(1);
GestureBinding.instance.gestureArena.close(1); tester.closeArena(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(down1); tester.route(down1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.pointerRouter.route(up1); tester.route(up1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
GestureBinding.instance.gestureArena.sweep(1); GestureBinding.instance.gestureArena.sweep(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
entry.resolve(GestureDisposition.rejected); entry.resolve(GestureDisposition.rejected);
tester.async.flushMicrotasks();
expect(tapRecognized, isTrue); expect(tapRecognized, isTrue);
tap.dispose(); tap.dispose();
......
...@@ -164,10 +164,8 @@ class Instrumentation { ...@@ -164,10 +164,8 @@ class Instrumentation {
/// Dispatch a pointer down / pointer up sequence at the given /// Dispatch a pointer down / pointer up sequence at the given
/// location. /// location.
void tapAt(Point location, { int pointer: 1 }) { void tapAt(Point location, { int pointer: 1 }) {
HitTestResult result = _hitTest(location); startGesture(location, pointer: pointer)
TestPointer p = new TestPointer(pointer); ..up();
binding.dispatchEvent(p.down(location), result);
binding.dispatchEvent(p.up(), result);
} }
/// Attempts a fling gesture starting from the center of the given /// Attempts a fling gesture starting from the center of the given
...@@ -210,14 +208,9 @@ class Instrumentation { ...@@ -210,14 +208,9 @@ class Instrumentation {
/// Attempts a drag gesture consisting of a pointer down, a move by /// Attempts a drag gesture consisting of a pointer down, a move by
/// the given offset, and a pointer up. /// the given offset, and a pointer up.
void scrollAt(Point startLocation, Offset offset, { int pointer: 1 }) { void scrollAt(Point startLocation, Offset offset, { int pointer: 1 }) {
Point endLocation = startLocation + offset; startGesture(startLocation, pointer: pointer)
TestPointer p = new TestPointer(pointer); ..moveBy(offset)
// Events for the entire press-drag-release gesture are dispatched ..up();
// to the widgets "hit" by the pointer down event.
HitTestResult result = _hitTest(startLocation);
binding.dispatchEvent(p.down(startLocation), result);
binding.dispatchEvent(p.move(endLocation), result);
binding.dispatchEvent(p.up(), result);
} }
/// Begins a gesture at a particular point, and returns the /// Begins a gesture at a particular point, and returns the
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:quiver/testing/async.dart';
export 'dart:ui' show Point; export 'dart:ui' show Point;
...@@ -139,11 +140,12 @@ class TestGesture { ...@@ -139,11 +140,12 @@ class TestGesture {
return new TestGesture._(dispatcher, result, testPointer); return new TestGesture._(dispatcher, result, testPointer);
} }
const TestGesture._(this._dispatcher, this._result, this._pointer); TestGesture._(this._dispatcher, this._result, this._pointer);
final HitTestDispatcher _dispatcher; final HitTestDispatcher _dispatcher;
final HitTestResult _result; final HitTestResult _result;
final TestPointer _pointer; final TestPointer _pointer;
FakeAsync async;
/// Send a move event moving the pointer by the given offset. /// Send a move event moving the pointer by the given offset.
void moveBy(Offset offset) { void moveBy(Offset offset) {
...@@ -155,6 +157,7 @@ class TestGesture { ...@@ -155,6 +157,7 @@ class TestGesture {
void moveTo(Point location) { void moveTo(Point location) {
assert(_pointer._isDown); assert(_pointer._isDown);
_dispatcher.dispatchEvent(_pointer.move(location), _result); _dispatcher.dispatchEvent(_pointer.move(location), _result);
async?.flushMicrotasks();
} }
/// End the gesture by releasing the pointer. /// End the gesture by releasing the pointer.
...@@ -164,6 +167,7 @@ class TestGesture { ...@@ -164,6 +167,7 @@ class TestGesture {
assert(_pointer._isDown); assert(_pointer._isDown);
_dispatcher.dispatchEvent(_pointer.up(), _result); _dispatcher.dispatchEvent(_pointer.up(), _result);
assert(!_pointer._isDown); assert(!_pointer._isDown);
async?.flushMicrotasks();
} }
/// End the gesture by canceling the pointer (as would happen if the /// End the gesture by canceling the pointer (as would happen if the
...@@ -175,5 +179,6 @@ class TestGesture { ...@@ -175,5 +179,6 @@ class TestGesture {
assert(_pointer._isDown); assert(_pointer._isDown);
_dispatcher.dispatchEvent(_pointer.cancel(), _result); _dispatcher.dispatchEvent(_pointer.cancel(), _result);
assert(!_pointer._isDown); assert(!_pointer._isDown);
async?.flushMicrotasks();
} }
} }
...@@ -143,7 +143,8 @@ class WidgetTester { ...@@ -143,7 +143,8 @@ class WidgetTester {
/// ///
/// See [ElementTreeTester.tapAt] for details. /// See [ElementTreeTester.tapAt] for details.
void tapAt(Point location, { int pointer: 1 }) { void tapAt(Point location, { int pointer: 1 }) {
elementTreeTester.tapAt(location, pointer: pointer); startGesture(location, pointer: pointer)
..up();
} }
/// Scrolls by dragging the center of a widget found by [finder] by [offset]. /// Scrolls by dragging the center of a widget found by [finder] by [offset].
...@@ -155,7 +156,9 @@ class WidgetTester { ...@@ -155,7 +156,9 @@ class WidgetTester {
/// ///
/// See [ElementTreeTester.scrollAt] for details. /// See [ElementTreeTester.scrollAt] for details.
void scrollAt(Point startLocation, Offset offset, { int pointer: 1 }) { void scrollAt(Point startLocation, Offset offset, { int pointer: 1 }) {
elementTreeTester.scrollAt(startLocation, offset, pointer: pointer); startGesture(startLocation, pointer: pointer)
..moveBy(offset)
..up();
} }
/// Attempts a fling gesture starting at the center of a widget found by /// Attempts a fling gesture starting at the center of a widget found by
...@@ -172,12 +175,15 @@ class WidgetTester { ...@@ -172,12 +175,15 @@ class WidgetTester {
/// See [ElementTreeTester.flingFrom] for details. /// See [ElementTreeTester.flingFrom] for details.
void flingFrom(Point startLocation, Offset offset, double velocity, { int pointer: 1 }) { void flingFrom(Point startLocation, Offset offset, double velocity, { int pointer: 1 }) {
elementTreeTester.flingFrom(startLocation, offset, velocity, pointer: pointer); elementTreeTester.flingFrom(startLocation, offset, velocity, pointer: pointer);
flushMicrotasks();
} }
/// Begins a gesture at a particular point, and returns the /// Begins a gesture at a particular point, and returns the
/// [TestGesture] object which you can use to continue the gesture. /// [TestGesture] object which you can use to continue the gesture.
TestGesture startGesture(Point downLocation, { int pointer: 1 }) { TestGesture startGesture(Point downLocation, { int pointer: 1 }) {
return elementTreeTester.startGesture(downLocation, pointer: pointer); TestGesture gesture = elementTreeTester.startGesture(downLocation, pointer: pointer)..async = async;
flushMicrotasks();
return gesture;
} }
/// Returns the size of the element corresponding to the widget located by /// Returns the size of the element corresponding to the widget located by
......
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