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() { }
|
void checkForResolutionAfterMove() { }
|
||||||
|
|
||||||
/// Called when the gesture was accepted.
|
/// Called when the gesture was accepted.
|
||||||
void accepted(Drag client) {
|
///
|
||||||
assert(_arenaEntry != null);
|
/// Either immediately or at some future point before the gesture is disposed,
|
||||||
assert(_client == null);
|
/// call starter(), passing it initialPosition, to start the drag.
|
||||||
_client = client;
|
void accepted(GestureMultiDragStartCallback starter);
|
||||||
_client.move(pendingDelta);
|
|
||||||
_pendingDelta = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when the gesture was rejected.
|
/// Called when the gesture was rejected.
|
||||||
|
///
|
||||||
|
/// [dispose()] will be called immediately following this.
|
||||||
void rejected() {
|
void rejected() {
|
||||||
assert(_arenaEntry != null);
|
assert(_arenaEntry != null);
|
||||||
assert(_client == null);
|
assert(_client == null);
|
||||||
@ -80,6 +79,16 @@ abstract class MultiDragPointerState {
|
|||||||
_arenaEntry = null;
|
_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() {
|
void _up() {
|
||||||
assert(_arenaEntry != null);
|
assert(_arenaEntry != null);
|
||||||
if (_client != null) {
|
if (_client != null) {
|
||||||
@ -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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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']));
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user