Merge pull request #1790 from Hixie/tap-drag
Refactor MultiDragPointerState to support delays
This commit is contained in:
commit
41b7fbf06b
@ -63,15 +63,14 @@ abstract class MultiDragPointerState {
|
||||
void checkForResolutionAfterMove() { }
|
||||
|
||||
/// Called when the gesture was accepted.
|
||||
void accepted(Drag client) {
|
||||
assert(_arenaEntry != null);
|
||||
assert(_client == null);
|
||||
_client = client;
|
||||
_client.move(pendingDelta);
|
||||
_pendingDelta = null;
|
||||
}
|
||||
///
|
||||
/// 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);
|
||||
@ -80,6 +79,16 @@ abstract class MultiDragPointerState {
|
||||
_arenaEntry = null;
|
||||
}
|
||||
|
||||
void _startDrag(Drag client) {
|
||||
assert(_arenaEntry != null);
|
||||
assert(_client == null);
|
||||
assert(client != null);
|
||||
assert(pendingDelta != null);
|
||||
_client = client;
|
||||
_client.move(pendingDelta);
|
||||
_pendingDelta = null;
|
||||
}
|
||||
|
||||
void _up() {
|
||||
assert(_arenaEntry != null);
|
||||
if (_client != null) {
|
||||
@ -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']));
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user