Pass on original pointer event timestamps to drag events (#11988)
* Record original pointer event timestamp * review * review * review
This commit is contained in:
parent
8566777dee
commit
2447f91844
@ -52,9 +52,15 @@ class DragStartDetails {
|
|||||||
/// Creates details for a [GestureDragStartCallback].
|
/// Creates details for a [GestureDragStartCallback].
|
||||||
///
|
///
|
||||||
/// The [globalPosition] argument must not be null.
|
/// The [globalPosition] argument must not be null.
|
||||||
DragStartDetails({ this.globalPosition: Offset.zero })
|
DragStartDetails({ this.sourceTimeStamp, this.globalPosition: Offset.zero })
|
||||||
: assert(globalPosition != null);
|
: assert(globalPosition != null);
|
||||||
|
|
||||||
|
/// Recorded timestamp of the source pointer event that triggered the drag
|
||||||
|
/// event.
|
||||||
|
///
|
||||||
|
/// Could be null if triggered from proxied events such as accessibility.
|
||||||
|
final Duration sourceTimeStamp;
|
||||||
|
|
||||||
/// The global position at which the pointer contacted the screen.
|
/// The global position at which the pointer contacted the screen.
|
||||||
///
|
///
|
||||||
/// Defaults to the origin if not specified in the constructor.
|
/// Defaults to the origin if not specified in the constructor.
|
||||||
@ -94,6 +100,7 @@ class DragUpdateDetails {
|
|||||||
///
|
///
|
||||||
/// The [globalPosition] argument must be provided and must not be null.
|
/// The [globalPosition] argument must be provided and must not be null.
|
||||||
DragUpdateDetails({
|
DragUpdateDetails({
|
||||||
|
this.sourceTimeStamp,
|
||||||
this.delta: Offset.zero,
|
this.delta: Offset.zero,
|
||||||
this.primaryDelta,
|
this.primaryDelta,
|
||||||
@required this.globalPosition
|
@required this.globalPosition
|
||||||
@ -102,6 +109,12 @@ class DragUpdateDetails {
|
|||||||
|| (primaryDelta == delta.dx && delta.dy == 0.0)
|
|| (primaryDelta == delta.dx && delta.dy == 0.0)
|
||||||
|| (primaryDelta == delta.dy && delta.dx == 0.0));
|
|| (primaryDelta == delta.dy && delta.dx == 0.0));
|
||||||
|
|
||||||
|
/// Recorded timestamp of the source pointer event that triggered the drag
|
||||||
|
/// event.
|
||||||
|
///
|
||||||
|
/// Could be null if triggered from proxied events such as accessibility.
|
||||||
|
final Duration sourceTimeStamp;
|
||||||
|
|
||||||
/// The amount the pointer has moved since the previous update.
|
/// The amount the pointer has moved since the previous update.
|
||||||
///
|
///
|
||||||
/// If the [GestureDragUpdateCallback] is for a one-dimensional drag (e.g.,
|
/// If the [GestureDragUpdateCallback] is for a one-dimensional drag (e.g.,
|
||||||
|
@ -101,6 +101,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
|
|||||||
_DragState _state = _DragState.ready;
|
_DragState _state = _DragState.ready;
|
||||||
Offset _initialPosition;
|
Offset _initialPosition;
|
||||||
Offset _pendingDragOffset;
|
Offset _pendingDragOffset;
|
||||||
|
Duration _lastPendingEventTimestamp;
|
||||||
|
|
||||||
bool _isFlingGesture(VelocityEstimate estimate);
|
bool _isFlingGesture(VelocityEstimate estimate);
|
||||||
Offset _getDeltaForDetails(Offset delta);
|
Offset _getDeltaForDetails(Offset delta);
|
||||||
@ -117,6 +118,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
|
|||||||
_state = _DragState.possible;
|
_state = _DragState.possible;
|
||||||
_initialPosition = event.position;
|
_initialPosition = event.position;
|
||||||
_pendingDragOffset = Offset.zero;
|
_pendingDragOffset = Offset.zero;
|
||||||
|
_lastPendingEventTimestamp = event.timeStamp;
|
||||||
if (onDown != null)
|
if (onDown != null)
|
||||||
invokeCallback<Null>('onDown', () => onDown(new DragDownDetails(globalPosition: _initialPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
invokeCallback<Null>('onDown', () => onDown(new DragDownDetails(globalPosition: _initialPosition))); // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
||||||
} else if (_state == _DragState.accepted) {
|
} else if (_state == _DragState.accepted) {
|
||||||
@ -139,6 +141,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
|
|||||||
if (_state == _DragState.accepted) {
|
if (_state == _DragState.accepted) {
|
||||||
if (onUpdate != null) {
|
if (onUpdate != null) {
|
||||||
invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
||||||
|
sourceTimeStamp: event.timeStamp,
|
||||||
delta: _getDeltaForDetails(delta),
|
delta: _getDeltaForDetails(delta),
|
||||||
primaryDelta: _getPrimaryValueFromOffset(delta),
|
primaryDelta: _getPrimaryValueFromOffset(delta),
|
||||||
globalPosition: event.position,
|
globalPosition: event.position,
|
||||||
@ -146,6 +149,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_pendingDragOffset += delta;
|
_pendingDragOffset += delta;
|
||||||
|
_lastPendingEventTimestamp = event.timeStamp;
|
||||||
if (_hasSufficientPendingDragDeltaToAccept)
|
if (_hasSufficientPendingDragDeltaToAccept)
|
||||||
resolve(GestureDisposition.accepted);
|
resolve(GestureDisposition.accepted);
|
||||||
}
|
}
|
||||||
@ -158,14 +162,18 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
|
|||||||
if (_state != _DragState.accepted) {
|
if (_state != _DragState.accepted) {
|
||||||
_state = _DragState.accepted;
|
_state = _DragState.accepted;
|
||||||
final Offset delta = _pendingDragOffset;
|
final Offset delta = _pendingDragOffset;
|
||||||
|
final Duration timestamp = _lastPendingEventTimestamp;
|
||||||
_pendingDragOffset = Offset.zero;
|
_pendingDragOffset = Offset.zero;
|
||||||
|
_lastPendingEventTimestamp = null;
|
||||||
if (onStart != null) {
|
if (onStart != null) {
|
||||||
invokeCallback<Null>('onStart', () => onStart(new DragStartDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
invokeCallback<Null>('onStart', () => onStart(new DragStartDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
||||||
|
sourceTimeStamp: timestamp,
|
||||||
globalPosition: _initialPosition,
|
globalPosition: _initialPosition,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if (delta != Offset.zero && onUpdate != null) {
|
if (delta != Offset.zero && onUpdate != null) {
|
||||||
invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
invokeCallback<Null>('onUpdate', () => onUpdate(new DragUpdateDetails( // ignore: STRONG_MODE_INVALID_CAST_FUNCTION_EXPR, https://github.com/dart-lang/sdk/issues/27504
|
||||||
|
sourceTimeStamp: timestamp,
|
||||||
delta: _getDeltaForDetails(delta),
|
delta: _getDeltaForDetails(delta),
|
||||||
primaryDelta: _getPrimaryValueFromOffset(delta),
|
primaryDelta: _getPrimaryValueFromOffset(delta),
|
||||||
globalPosition: _initialPosition,
|
globalPosition: _initialPosition,
|
||||||
|
@ -45,6 +45,8 @@ abstract class MultiDragPointerState {
|
|||||||
Offset get pendingDelta => _pendingDelta;
|
Offset get pendingDelta => _pendingDelta;
|
||||||
Offset _pendingDelta = Offset.zero;
|
Offset _pendingDelta = Offset.zero;
|
||||||
|
|
||||||
|
Duration _lastPendingEventTimestamp;
|
||||||
|
|
||||||
GestureArenaEntry _arenaEntry;
|
GestureArenaEntry _arenaEntry;
|
||||||
void _setArenaEntry(GestureArenaEntry entry) {
|
void _setArenaEntry(GestureArenaEntry entry) {
|
||||||
assert(_arenaEntry == null);
|
assert(_arenaEntry == null);
|
||||||
@ -68,12 +70,14 @@ abstract class MultiDragPointerState {
|
|||||||
assert(pendingDelta == null);
|
assert(pendingDelta == null);
|
||||||
// Call client last to avoid reentrancy.
|
// Call client last to avoid reentrancy.
|
||||||
_client.update(new DragUpdateDetails(
|
_client.update(new DragUpdateDetails(
|
||||||
|
sourceTimeStamp: event.timeStamp,
|
||||||
delta: event.delta,
|
delta: event.delta,
|
||||||
globalPosition: event.position,
|
globalPosition: event.position,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
assert(pendingDelta != null);
|
assert(pendingDelta != null);
|
||||||
_pendingDelta += event.delta;
|
_pendingDelta += event.delta;
|
||||||
|
_lastPendingEventTimestamp = event.timeStamp;
|
||||||
checkForResolutionAfterMove();
|
checkForResolutionAfterMove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,6 +105,7 @@ abstract class MultiDragPointerState {
|
|||||||
assert(_client == null);
|
assert(_client == null);
|
||||||
assert(pendingDelta != null);
|
assert(pendingDelta != null);
|
||||||
_pendingDelta = null;
|
_pendingDelta = null;
|
||||||
|
_lastPendingEventTimestamp = null;
|
||||||
_arenaEntry = null;
|
_arenaEntry = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,10 +116,12 @@ abstract class MultiDragPointerState {
|
|||||||
assert(pendingDelta != null);
|
assert(pendingDelta != null);
|
||||||
_client = client;
|
_client = client;
|
||||||
final DragUpdateDetails details = new DragUpdateDetails(
|
final DragUpdateDetails details = new DragUpdateDetails(
|
||||||
|
sourceTimeStamp: _lastPendingEventTimestamp,
|
||||||
delta: pendingDelta,
|
delta: pendingDelta,
|
||||||
globalPosition: initialPosition,
|
globalPosition: initialPosition,
|
||||||
);
|
);
|
||||||
_pendingDelta = null;
|
_pendingDelta = null;
|
||||||
|
_lastPendingEventTimestamp = null;
|
||||||
// Call client last to avoid reentrancy.
|
// Call client last to avoid reentrancy.
|
||||||
_client.update(details);
|
_client.update(details);
|
||||||
}
|
}
|
||||||
@ -131,6 +138,7 @@ abstract class MultiDragPointerState {
|
|||||||
} else {
|
} else {
|
||||||
assert(pendingDelta != null);
|
assert(pendingDelta != null);
|
||||||
_pendingDelta = null;
|
_pendingDelta = null;
|
||||||
|
_lastPendingEventTimestamp = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +153,7 @@ abstract class MultiDragPointerState {
|
|||||||
} else {
|
} else {
|
||||||
assert(pendingDelta != null);
|
assert(pendingDelta != null);
|
||||||
_pendingDelta = null;
|
_pendingDelta = null;
|
||||||
|
_lastPendingEventTimestamp = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,37 @@ void main() {
|
|||||||
drag.dispose();
|
drag.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testGesture('Should report original timestamps', (GestureTester tester) {
|
||||||
|
final HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
|
||||||
|
|
||||||
|
Duration startTimestamp;
|
||||||
|
drag.onStart = (DragStartDetails details) {
|
||||||
|
startTimestamp = details.sourceTimeStamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
Duration updatedTimestamp;
|
||||||
|
drag.onUpdate = (DragUpdateDetails details) {
|
||||||
|
updatedTimestamp = details.sourceTimeStamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
final TestPointer pointer = new TestPointer(5);
|
||||||
|
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0), timeStamp: const Duration(milliseconds: 100));
|
||||||
|
drag.addPointer(down);
|
||||||
|
tester.closeArena(5);
|
||||||
|
expect(startTimestamp, isNull);
|
||||||
|
|
||||||
|
tester.route(down);
|
||||||
|
expect(startTimestamp, const Duration(milliseconds: 100));
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(20.0, 25.0), timeStamp: const Duration(milliseconds: 200)));
|
||||||
|
expect(updatedTimestamp, const Duration(milliseconds: 200));
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(20.0, 25.0), timeStamp: const Duration(milliseconds: 300)));
|
||||||
|
expect(updatedTimestamp, const Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
drag.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
testGesture('Drag with multiple pointers', (GestureTester tester) {
|
testGesture('Drag with multiple pointers', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag1 = new HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag1 = new HorizontalDragGestureRecognizer();
|
||||||
final VerticalDragGestureRecognizer drag2 = new VerticalDragGestureRecognizer();
|
final VerticalDragGestureRecognizer drag2 = new VerticalDragGestureRecognizer();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user