Commit 6b487e4e authored by Hixie's avatar Hixie

Refactor MultiDragPointerState to support delays

...even after winning the arena.
parent 94e9795b
...@@ -63,21 +63,30 @@ abstract class MultiDragPointerState { ...@@ -63,21 +63,30 @@ abstract class MultiDragPointerState {
void checkForResolutionAfterMove() { } void checkForResolutionAfterMove() { }
/// Called when the gesture was accepted. /// Called when the gesture was accepted.
void accepted(Drag client) { ///
/// Either immediately or at some future point before the gesture is disposed,
/// call starter(), passing it initialPosition, to start the drag.
void accepted(GestureMultiDragStartCallback starter);
/// Called when the gesture was rejected.
///
/// [dispose()] will be called immediately following this.
void rejected() {
assert(_arenaEntry != null); assert(_arenaEntry != null);
assert(_client == null); assert(_client == null);
_client = client; assert(pendingDelta != null);
_client.move(pendingDelta);
_pendingDelta = null; _pendingDelta = null;
_arenaEntry = null;
} }
/// Called when the gesture was rejected. void _startDrag(Drag client) {
void rejected() {
assert(_arenaEntry != null); assert(_arenaEntry != null);
assert(_client == null); assert(_client == null);
assert(client != null);
assert(pendingDelta != null); assert(pendingDelta != null);
_client = client;
_client.move(pendingDelta);
_pendingDelta = null; _pendingDelta = null;
_arenaEntry = null;
} }
void _up() { void _up() {
...@@ -106,7 +115,9 @@ abstract class MultiDragPointerState { ...@@ -106,7 +115,9 @@ abstract class MultiDragPointerState {
_arenaEntry = null; _arenaEntry = null;
} }
void dispose() { } void dispose() {
assert(() { _pendingDelta = null; return true; });
}
} }
abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> extends GestureRecognizer { abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> extends GestureRecognizer {
...@@ -168,14 +179,23 @@ abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> exten ...@@ -168,14 +179,23 @@ abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> exten
assert(_pointers != null); assert(_pointers != null);
T state = _pointers[pointer]; T state = _pointers[pointer];
assert(state != null); assert(state != null);
state.accepted((Point initialPosition) => _startDrag(initialPosition, pointer));
}
Drag _startDrag(Point initialPosition, int pointer) {
assert(_pointers != null);
T state = _pointers[pointer];
assert(state != null);
assert(state._pendingDelta != null);
Drag drag; Drag drag;
if (onStart != null) if (onStart != null)
drag = onStart(state.initialPosition); drag = onStart(initialPosition);
if (drag != null) { if (drag != null) {
state.accepted(drag); state._startDrag(drag);
} else { } else {
_removeState(pointer); _removeState(pointer);
} }
return drag;
} }
void rejectGesture(int pointer) { void rejectGesture(int pointer) {
...@@ -214,6 +234,10 @@ class _ImmediatePointerState extends MultiDragPointerState { ...@@ -214,6 +234,10 @@ class _ImmediatePointerState extends MultiDragPointerState {
if (pendingDelta.distance > kTouchSlop) if (pendingDelta.distance > kTouchSlop)
resolve(GestureDisposition.accepted); resolve(GestureDisposition.accepted);
} }
void accepted(GestureMultiDragStartCallback starter) {
starter(initialPosition);
}
} }
class ImmediateMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_ImmediatePointerState> { class ImmediateMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_ImmediatePointerState> {
...@@ -235,19 +259,28 @@ class _DelayedPointerState extends MultiDragPointerState { ...@@ -235,19 +259,28 @@ class _DelayedPointerState extends MultiDragPointerState {
} }
Timer _timer; Timer _timer;
GestureMultiDragStartCallback _starter;
void _delayPassed() { void _delayPassed() {
assert(_timer != null); assert(_timer != null);
assert(pendingDelta != null); assert(pendingDelta != null);
assert(pendingDelta.distance <= kTouchSlop); assert(pendingDelta.distance <= kTouchSlop);
resolve(GestureDisposition.accepted);
_timer = null; _timer = null;
if (_starter != null) {
_starter(initialPosition);
_starter = null;
} else {
resolve(GestureDisposition.accepted);
}
assert(_starter == null);
} }
void accepted(Drag client) { void accepted(GestureMultiDragStartCallback starter) {
_timer?.cancel(); assert(_starter == null);
_timer = null; if (_timer == null)
super.accepted(client); starter(initialPosition);
else
_starter = starter;
} }
void checkForResolutionAfterMove() { void checkForResolutionAfterMove() {
......
...@@ -169,7 +169,9 @@ void main() { ...@@ -169,7 +169,9 @@ void main() {
expect(events, equals(<String>['tap', 'tap', 'drop'])); expect(events, equals(<String>['tap', 'tap', 'drop']));
events.clear(); events.clear();
}); });
});
test('Drag and drop - tapping button', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
TestPointer pointer = new TestPointer(7); TestPointer pointer = new TestPointer(7);
...@@ -230,6 +232,113 @@ void main() { ...@@ -230,6 +232,113 @@ void main() {
events.clear(); events.clear();
}); });
});
test('Drag and drop - long press draggable, short press', () {
testWidgets((WidgetTester tester) {
TestPointer pointer = new TestPointer(7);
List<String> events = <String>[];
Point firstLocation, secondLocation;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) { return new Column(
children: <Widget>[
new LongPressDraggable(
data: 1,
child: new Text('Source'),
feedback: new Text('Dragging')
),
new DragTarget(
builder: (context, data, rejects) {
return new Text('Target');
},
onAccept: (data) {
events.add('drop');
}
),
]);
},
}
));
expect(events, isEmpty);
expect(tester.findText('Source'), isNotNull);
expect(tester.findText('Target'), isNotNull);
expect(events, isEmpty);
tester.tap(tester.findText('Source'));
expect(events, isEmpty);
firstLocation = tester.getCenter(tester.findText('Source'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
secondLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
expect(events, isEmpty);
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, isEmpty);
});
});
test('Drag and drop - long press draggable, long press', () {
testWidgets((WidgetTester tester) {
TestPointer pointer = new TestPointer(7);
List<String> events = <String>[];
Point firstLocation, secondLocation;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) { return new Column(
children: <Widget>[
new Draggable(
data: 1,
child: new Text('Source'),
feedback: new Text('Dragging')
),
new DragTarget(
builder: (context, data, rejects) {
return new Text('Target');
},
onAccept: (data) {
events.add('drop');
}
),
]);
},
}
));
expect(events, isEmpty);
expect(tester.findText('Source'), isNotNull);
expect(tester.findText('Target'), isNotNull);
expect(events, isEmpty);
tester.tap(tester.findText('Source'));
expect(events, isEmpty);
firstLocation = tester.getCenter(tester.findText('Source'));
tester.dispatchEvent(pointer.down(firstLocation), firstLocation);
tester.pump();
tester.pump(const Duration(seconds: 20));
secondLocation = tester.getCenter(tester.findText('Target'));
tester.dispatchEvent(pointer.move(secondLocation), firstLocation);
tester.pump();
expect(events, isEmpty);
tester.dispatchEvent(pointer.up(), firstLocation);
tester.pump();
expect(events, equals(<String>['drop']));
});
}); });
} }
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