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 {
void checkForResolutionAfterMove() { }
/// 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(_client == null);
_client = client;
_client.move(pendingDelta);
assert(pendingDelta != null);
_pendingDelta = null;
_arenaEntry = null;
}
/// Called when the gesture was rejected.
void rejected() {
void _startDrag(Drag client) {
assert(_arenaEntry != null);
assert(_client == null);
assert(client != null);
assert(pendingDelta != null);
_client = client;
_client.move(pendingDelta);
_pendingDelta = null;
_arenaEntry = null;
}
void _up() {
......@@ -106,7 +115,9 @@ abstract class MultiDragPointerState {
_arenaEntry = null;
}
void dispose() { }
void dispose() {
assert(() { _pendingDelta = null; return true; });
}
}
abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> extends GestureRecognizer {
......@@ -168,14 +179,23 @@ abstract class MultiDragGestureRecognizer<T extends MultiDragPointerState> exten
assert(_pointers != null);
T state = _pointers[pointer];
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;
if (onStart != null)
drag = onStart(state.initialPosition);
drag = onStart(initialPosition);
if (drag != null) {
state.accepted(drag);
state._startDrag(drag);
} else {
_removeState(pointer);
}
return drag;
}
void rejectGesture(int pointer) {
......@@ -214,6 +234,10 @@ class _ImmediatePointerState extends MultiDragPointerState {
if (pendingDelta.distance > kTouchSlop)
resolve(GestureDisposition.accepted);
}
void accepted(GestureMultiDragStartCallback starter) {
starter(initialPosition);
}
}
class ImmediateMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_ImmediatePointerState> {
......@@ -235,19 +259,28 @@ class _DelayedPointerState extends MultiDragPointerState {
}
Timer _timer;
GestureMultiDragStartCallback _starter;
void _delayPassed() {
assert(_timer != null);
assert(pendingDelta != null);
assert(pendingDelta.distance <= kTouchSlop);
resolve(GestureDisposition.accepted);
_timer = null;
if (_starter != null) {
_starter(initialPosition);
_starter = null;
} else {
resolve(GestureDisposition.accepted);
}
assert(_starter == null);
}
void accepted(Drag client) {
_timer?.cancel();
_timer = null;
super.accepted(client);
void accepted(GestureMultiDragStartCallback starter) {
assert(_starter == null);
if (_timer == null)
starter(initialPosition);
else
_starter = starter;
}
void checkForResolutionAfterMove() {
......
......@@ -169,7 +169,9 @@ void main() {
expect(events, equals(<String>['tap', 'tap', 'drop']));
events.clear();
});
});
test('Drag and drop - tapping button', () {
testWidgets((WidgetTester tester) {
TestPointer pointer = new TestPointer(7);
......@@ -230,6 +232,113 @@ void main() {
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