revert 26001 (#28032)
This commit is contained in:
@@ -478,25 +478,8 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
|
||||
_requestKeyboard();
|
||||
}
|
||||
|
||||
void _handleSingleLongTapStart(GestureLongPressDragStartDetails details) {
|
||||
_renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSingleLongTapDragUpdate(GestureLongPressDragUpdateDetails details) {
|
||||
_renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSingleLongTapUp(GestureLongPressDragUpDetails details) {
|
||||
_renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress
|
||||
);
|
||||
void _handleSingleLongTapDown() {
|
||||
_renderEditable.selectPosition(cause: SelectionChangedCause.longPress);
|
||||
_editableTextKey.currentState.showToolbar();
|
||||
}
|
||||
|
||||
@@ -505,12 +488,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
|
||||
_editableTextKey.currentState.showToolbar();
|
||||
}
|
||||
|
||||
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) {
|
||||
if (cause == SelectionChangedCause.longPress) {
|
||||
_editableTextKey.currentState?.bringIntoView(selection.base);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => _controller?.text?.isNotEmpty == true;
|
||||
|
||||
@@ -664,7 +641,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
|
||||
selectionColor: _kSelectionHighlightColor,
|
||||
selectionControls: cupertinoTextSelectionControls,
|
||||
onChanged: widget.onChanged,
|
||||
onSelectionChanged: _handleSelectionChanged,
|
||||
onEditingComplete: widget.onEditingComplete,
|
||||
onSubmitted: widget.onSubmitted,
|
||||
inputFormatters: formatters,
|
||||
@@ -705,9 +681,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
|
||||
onForcePressStart: _handleForcePressStarted,
|
||||
onForcePressEnd: _handleForcePressEnded,
|
||||
onSingleTapUp: _handleSingleTapUp,
|
||||
onSingleLongTapStart: _handleSingleLongTapStart,
|
||||
onSingleLongTapDragUpdate: _handleSingleLongTapDragUpdate,
|
||||
onSingleLongTapUp: _handleSingleLongTapUp,
|
||||
onSingleLongTapDown: _handleSingleLongTapDown,
|
||||
onDoubleTapDown: _handleDoubleTapDown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: _addTextDependentAttachments(paddedEditable, textStyle),
|
||||
|
||||
@@ -11,117 +11,9 @@ import 'recognizer.dart';
|
||||
/// same location for a long period of time.
|
||||
typedef GestureLongPressCallback = void Function();
|
||||
|
||||
/// Signature for when a pointer stops contacting the screen after a long press
|
||||
/// gesture was detected.
|
||||
/// Signature for when a pointer stops contacting the screen after a long press gesture was detected.
|
||||
typedef GestureLongPressUpCallback = void Function();
|
||||
|
||||
/// Signature from a [LongPressDragGestureRecognizer] when a pointer has remained
|
||||
/// in contact with the screen at the same location for a long period of time.
|
||||
typedef GestureLongPressDragStartCallback = void Function(GestureLongPressDragStartDetails details);
|
||||
|
||||
/// Signature from a [LongPressDragGestureRecognizer] when a pointer is moving
|
||||
/// after being held in contact at the same location for a long period of time.
|
||||
typedef GestureLongPressDragUpdateCallback = void Function(GestureLongPressDragUpdateDetails details);
|
||||
|
||||
/// Signature from a [LongPressDragGestureRecognizer] after a pointer stops
|
||||
/// contacting the screen.
|
||||
///
|
||||
/// The contact stop position may be different from the contact start position.
|
||||
typedef GestureLongPressDragUpCallback = void Function(GestureLongPressDragUpDetails details);
|
||||
|
||||
/// Details for callbacks that use [GestureLongPressDragStartCallback].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [LongPressDragGestureRecognizer.onLongPressStart], which uses [GestureLongPressDragStartCallback].
|
||||
/// * [GestureLongPressDragUpdateDetails], the details for [GestureLongPressDragUpdateCallback]
|
||||
/// * [GestureLongPressDragUpDetails], the details for [GestureLongPressDragUpCallback].
|
||||
class GestureLongPressDragStartDetails {
|
||||
/// Creates the details for a [GestureLongPressDragStartCallback].
|
||||
///
|
||||
/// The [globalPosition] argument must not be null.
|
||||
const GestureLongPressDragStartDetails({ this.sourceTimeStamp, this.globalPosition = Offset.zero })
|
||||
: assert(globalPosition != null);
|
||||
|
||||
/// Recorded timestamp of the source pointer event that triggered the press
|
||||
/// event.
|
||||
///
|
||||
/// Could be null if triggered by proxied events such as accessibility.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PointerEvent.synthesized] for details on synthesized pointer events.
|
||||
final Duration sourceTimeStamp;
|
||||
|
||||
/// The global position at which the pointer contacted the screen.
|
||||
final Offset globalPosition;
|
||||
}
|
||||
|
||||
/// Details for callbacks that use [GestureLongPressDragUpdateCallback].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [LongPressDragGestureRecognizer.onLongPressDragUpdate], which uses [GestureLongPressDragUpdateCallback].
|
||||
/// * [GestureLongPressDragUpDetails], the details for [GestureLongPressDragUpCallback]
|
||||
/// * [GestureLongPressDragStartDetails], the details for [GestureLongPressDragStartCallback].
|
||||
class GestureLongPressDragUpdateDetails {
|
||||
/// Creates the details for a [GestureLongPressDragUpdateCallback].
|
||||
///
|
||||
/// The [globalPosition] and [offsetFromOrigin] arguments must not be null.
|
||||
const GestureLongPressDragUpdateDetails({
|
||||
this.sourceTimeStamp,
|
||||
this.globalPosition = Offset.zero,
|
||||
this.offsetFromOrigin = Offset.zero,
|
||||
}) : assert(globalPosition != null),
|
||||
assert(offsetFromOrigin != null);
|
||||
|
||||
/// Recorded timestamp of the source pointer event that triggered the press
|
||||
/// event.
|
||||
///
|
||||
/// Could be null if triggered by proxied events such as accessibility.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PointerEvent.synthesized] for details on synthesized pointer events.
|
||||
final Duration sourceTimeStamp;
|
||||
|
||||
/// The global position of the pointer when it triggered this update.
|
||||
final Offset globalPosition;
|
||||
|
||||
/// A delta offset from the point where the long press drag initially contacted
|
||||
/// the screen to the point where the pointer is currently located when
|
||||
/// this callback is triggered.
|
||||
final Offset offsetFromOrigin;
|
||||
}
|
||||
|
||||
/// Details for callbacks that use [GestureLongPressDragUpCallback].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [LongPressDragGestureRecognizer.onLongPressUp], which uses [GestureLongPressDragUpCallback].
|
||||
/// * [GestureLongPressDragUpdateDetails], the details for [GestureLongPressDragUpdateCallback]
|
||||
/// * [GestureLongPressDragStartDetails], the details for [GestureLongPressDragStartCallback].
|
||||
class GestureLongPressDragUpDetails {
|
||||
/// Creates the details for a [GestureLongPressDragUpCallback].
|
||||
///
|
||||
/// The [globalPosition] argument must not be null.
|
||||
const GestureLongPressDragUpDetails({ this.sourceTimeStamp, this.globalPosition = Offset.zero })
|
||||
: assert(globalPosition != null);
|
||||
|
||||
/// Recorded timestamp of the source pointer event that triggered the press
|
||||
/// event.
|
||||
///
|
||||
/// Could be null if triggered by proxied events such as accessibility.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PointerEvent.synthesized] for details on synthesized pointer events.
|
||||
final Duration sourceTimeStamp;
|
||||
|
||||
/// The global position at which the pointer lifted from the screen.
|
||||
final Offset globalPosition;
|
||||
}
|
||||
|
||||
/// Recognizes when the user has pressed down at the same location for a long
|
||||
/// period of time.
|
||||
class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
@@ -136,8 +28,7 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
/// Called when a long press gesture has been recognized.
|
||||
GestureLongPressCallback onLongPress;
|
||||
|
||||
/// Called when the pointer stops contacting the screen after the long-press
|
||||
/// gesture has been recognized.
|
||||
/// Called when the pointer stops contacting the screen after the long-press gesture has been recognized.
|
||||
GestureLongPressUpCallback onLongPressUp;
|
||||
|
||||
@override
|
||||
@@ -167,107 +58,3 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
@override
|
||||
String get debugDescription => 'long press';
|
||||
}
|
||||
|
||||
/// Recognizes long presses that can be subsequently dragged around.
|
||||
///
|
||||
/// Similar to a [LongPressGestureRecognizer] where a press has to be held down
|
||||
/// at the same location for a long period of time. However drag events that
|
||||
/// occur after the long-press hold threshold has past will not cancel the
|
||||
/// gesture. The [onLongPressDragUpdate] callback will be called until an up
|
||||
/// event occurs.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [LongPressGestureRecognizer], which cancels its gesture if a drag event
|
||||
/// occurs at any point during the long-press.
|
||||
class LongPressDragGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
||||
/// Creates a long-press-drag gesture recognizer.
|
||||
///
|
||||
/// Consider assigning the [onLongPressStart], [onLongPressDragUpdate] and
|
||||
/// the [onLongPressUp] callbacks after creating this object.
|
||||
LongPressDragGestureRecognizer({ Object debugOwner }) : super(
|
||||
deadline: kLongPressTimeout,
|
||||
// Since it's a drag gesture, no travel distance will cause it to get
|
||||
// rejected after the long-press is accepted.
|
||||
postAcceptSlopTolerance: null,
|
||||
debugOwner: debugOwner,
|
||||
);
|
||||
|
||||
bool _longPressAccepted = false;
|
||||
|
||||
Offset _longPressOrigin;
|
||||
|
||||
Duration _longPressStartTimestamp;
|
||||
|
||||
/// Called when a long press gesture has been recognized.
|
||||
GestureLongPressDragStartCallback onLongPressStart;
|
||||
|
||||
/// Called as the primary pointer is dragged after the long press.
|
||||
GestureLongPressDragUpdateCallback onLongPressDragUpdate;
|
||||
|
||||
/// Called when the pointer stops contacting the screen after the
|
||||
/// long-press gesture has been recognized.
|
||||
GestureLongPressDragUpCallback onLongPressUp;
|
||||
|
||||
@override
|
||||
void didExceedDeadline() {
|
||||
resolve(GestureDisposition.accepted);
|
||||
_longPressAccepted = true;
|
||||
super.acceptGesture(primaryPointer);
|
||||
if (onLongPressStart != null) {
|
||||
invokeCallback<void>('onLongPressStart', () {
|
||||
onLongPressStart(GestureLongPressDragStartDetails(
|
||||
sourceTimeStamp: _longPressStartTimestamp,
|
||||
globalPosition: _longPressOrigin,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handlePrimaryPointer(PointerEvent event) {
|
||||
if (event is PointerUpEvent) {
|
||||
if (_longPressAccepted == true && onLongPressUp != null) {
|
||||
_longPressAccepted = false;
|
||||
invokeCallback<void>('onLongPressUp', () {
|
||||
onLongPressUp(GestureLongPressDragUpDetails(
|
||||
sourceTimeStamp: event.timeStamp,
|
||||
globalPosition: event.position,
|
||||
));
|
||||
});
|
||||
} else {
|
||||
resolve(GestureDisposition.rejected);
|
||||
}
|
||||
} else if (event is PointerDownEvent) {
|
||||
// The first touch.
|
||||
_longPressAccepted = false;
|
||||
_longPressStartTimestamp = event.timeStamp;
|
||||
_longPressOrigin = event.position;
|
||||
} else if (event is PointerMoveEvent && _longPressAccepted && onLongPressDragUpdate != null) {
|
||||
invokeCallback<void>('onLongPressDrag', () {
|
||||
onLongPressDragUpdate(GestureLongPressDragUpdateDetails(
|
||||
sourceTimeStamp: event.timeStamp,
|
||||
globalPosition: event.position,
|
||||
offsetFromOrigin: event.position - _longPressOrigin,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void acceptGesture(int pointer) {
|
||||
// Winning the arena isn't important here since it may happen from a sweep.
|
||||
// Explicitly exceeding the deadline puts the gesture in accepted state.
|
||||
}
|
||||
|
||||
@override
|
||||
void didStopTrackingLastPointer(int pointer) {
|
||||
_longPressAccepted = false;
|
||||
_longPressOrigin = null;
|
||||
_longPressStartTimestamp = null;
|
||||
super.didStopTrackingLastPointer(pointer);
|
||||
}
|
||||
|
||||
@override
|
||||
String get debugDescription => 'long press drag';
|
||||
}
|
||||
|
||||
@@ -262,10 +262,10 @@ abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
|
||||
/// The possible states of a [PrimaryPointerGestureRecognizer].
|
||||
///
|
||||
/// The recognizer advances from [ready] to [possible] when starts tracking a
|
||||
/// primary pointer. The recognizer moves to [accepted] when resolved to win the
|
||||
/// gesture arena. It may then move to [defunct] from [accepted] or go to
|
||||
/// [defunct] directly when rejected. Once the recognizer has stopped tracking
|
||||
/// any remaining pointers, the recognizer returns to [ready].
|
||||
/// primary pointer. When the primary pointer is resolve (either accepted or
|
||||
/// or rejected), the recognizers advances to [defunct]. Once the recognizer
|
||||
/// has stopped tracking any remaining pointers, the recognizer returns to
|
||||
/// [ready].
|
||||
enum GestureRecognizerState {
|
||||
/// The recognizer is ready to start recognizing a gesture.
|
||||
ready,
|
||||
@@ -275,9 +275,6 @@ enum GestureRecognizerState {
|
||||
/// been accepted definitively.
|
||||
possible,
|
||||
|
||||
/// The gesture has been definitively accepted by the recognizer.
|
||||
accepted,
|
||||
|
||||
/// Further pointer events cannot cause this recognizer to recognize the
|
||||
/// gesture until the recognizer returns to the [ready] state (typically when
|
||||
/// all the pointers the recognizer is tracking are removed from the screen).
|
||||
@@ -287,43 +284,18 @@ enum GestureRecognizerState {
|
||||
/// A base class for gesture recognizers that track a single primary pointer.
|
||||
///
|
||||
/// Gestures based on this class will reject the gesture if the primary pointer
|
||||
/// travels beyond [preAcceptSlopTolerance] pixels from the original contact
|
||||
/// point before the gesture is accepted or beyond [postAcceptSlopTolerance]
|
||||
/// from where the pointer was after the gesture was accepted.
|
||||
/// travels beyond [kTouchSlop] pixels from the original contact point.
|
||||
abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecognizer {
|
||||
/// Initializes the [deadline] field during construction of subclasses.
|
||||
PrimaryPointerGestureRecognizer({
|
||||
this.deadline,
|
||||
this.preAcceptSlopTolerance = kTouchSlop,
|
||||
this.postAcceptSlopTolerance = kTouchSlop,
|
||||
Object debugOwner,
|
||||
}) : assert(
|
||||
preAcceptSlopTolerance == null || preAcceptSlopTolerance >= 0,
|
||||
'The preAcceptSlopTolerance must be positive or null',
|
||||
),
|
||||
assert(
|
||||
postAcceptSlopTolerance == null || postAcceptSlopTolerance >= 0,
|
||||
'The postAcceptSlopTolerance must be positive or null',
|
||||
),
|
||||
super(debugOwner: debugOwner);
|
||||
}) : super(debugOwner: debugOwner);
|
||||
|
||||
/// If non-null, the recognizer will call [didExceedDeadline] after this
|
||||
/// amount of time has elapsed since starting to track the primary pointer.
|
||||
final Duration deadline;
|
||||
|
||||
/// The maximum distance in logical pixels the gesture is allowed to drift
|
||||
/// from the initial touch down position before the gesture is accepted.
|
||||
///
|
||||
/// Drifting past the allowed slop amount causes the gesture to be rejected.
|
||||
final double preAcceptSlopTolerance;
|
||||
|
||||
/// The maximum distance in logical pixels the gesture is allowed to drift
|
||||
/// after the gesture has been accepted.
|
||||
///
|
||||
/// Drifting past the allowed slop amount causes the gesture to be rejected,
|
||||
/// even after being accepted.
|
||||
final double postAcceptSlopTolerance;
|
||||
|
||||
/// The current state of the recognizer.
|
||||
///
|
||||
/// See [GestureRecognizerState] for a description of the states.
|
||||
@@ -352,17 +324,9 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
|
||||
@override
|
||||
void handleEvent(PointerEvent event) {
|
||||
assert(state != GestureRecognizerState.ready);
|
||||
if (event.pointer == primaryPointer) {
|
||||
final bool isPreAcceptSlopPastTolerance =
|
||||
state == GestureRecognizerState.possible &&
|
||||
preAcceptSlopTolerance != null &&
|
||||
_getDistance(event) > preAcceptSlopTolerance;
|
||||
final bool isPostAcceptSlopPastTolerance =
|
||||
state == GestureRecognizerState.accepted &&
|
||||
postAcceptSlopTolerance != null &&
|
||||
_getDistance(event) > postAcceptSlopTolerance;
|
||||
|
||||
if (event is PointerMoveEvent && (isPreAcceptSlopPastTolerance || isPostAcceptSlopPastTolerance)) {
|
||||
if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) {
|
||||
// TODO(abarth): Maybe factor the slop handling out into a separate class?
|
||||
if (event is PointerMoveEvent && _getDistance(event) > kTouchSlop) {
|
||||
resolve(GestureDisposition.rejected);
|
||||
stopTrackingPointer(primaryPointer);
|
||||
} else {
|
||||
@@ -384,20 +348,9 @@ abstract class PrimaryPointerGestureRecognizer extends OneSequenceGestureRecogni
|
||||
assert(deadline == null);
|
||||
}
|
||||
|
||||
@override
|
||||
void acceptGesture(int pointer) {
|
||||
// Ignore state 'ready' here because that would happen if this recognizer
|
||||
// won by a sweep.
|
||||
if (pointer == primaryPointer && state == GestureRecognizerState.possible) {
|
||||
state = GestureRecognizerState.accepted;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void rejectGesture(int pointer) {
|
||||
if (pointer == primaryPointer
|
||||
&& (state == GestureRecognizerState.possible ||
|
||||
state == GestureRecognizerState.accepted)) {
|
||||
if (pointer == primaryPointer && state == GestureRecognizerState.possible) {
|
||||
_stopTimer();
|
||||
state = GestureRecognizerState.defunct;
|
||||
}
|
||||
|
||||
@@ -566,15 +566,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
_editableTextKey.currentState?.requestKeyboard();
|
||||
}
|
||||
|
||||
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) {
|
||||
// iOS cursor doesn't move via a selection handle. The scroll happens
|
||||
// directly from new text selection changes.
|
||||
if (Theme.of(context).platform == TargetPlatform.iOS
|
||||
&& cause == SelectionChangedCause.longPress) {
|
||||
_editableTextKey.currentState?.bringIntoView(selection.base);
|
||||
}
|
||||
}
|
||||
|
||||
InteractiveInkFeature _createInkFeature(TapDownDetails details) {
|
||||
final MaterialInkController inkController = Material.of(context);
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
@@ -648,14 +639,11 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
_cancelCurrentSplash();
|
||||
}
|
||||
|
||||
void _handleSingleLongTapStart(GestureLongPressDragStartDetails details) {
|
||||
void _handleSingleLongTapDown() {
|
||||
if (widget.selectionEnabled) {
|
||||
switch (Theme.of(context).platform) {
|
||||
case TargetPlatform.iOS:
|
||||
_renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
_renderEditable.selectPosition(cause: SelectionChangedCause.longPress);
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
@@ -663,35 +651,11 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
Feedback.forLongPress(context);
|
||||
break;
|
||||
}
|
||||
_editableTextKey.currentState.showToolbar();
|
||||
}
|
||||
_confirmCurrentSplash();
|
||||
}
|
||||
|
||||
void _handleSingleLongTapDragUpdate(GestureLongPressDragUpdateDetails details) {
|
||||
if (widget.selectionEnabled) {
|
||||
switch (Theme.of(context).platform) {
|
||||
case TargetPlatform.iOS:
|
||||
_renderEditable.selectPositionAt(
|
||||
from: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
_renderEditable.selectWordsInRange(
|
||||
from: details.globalPosition - details.offsetFromOrigin,
|
||||
to: details.globalPosition,
|
||||
cause: SelectionChangedCause.longPress,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _handleSingleLongTapUp(GestureLongPressDragUpDetails details) {
|
||||
_editableTextKey.currentState.showToolbar();
|
||||
}
|
||||
|
||||
void _handleDoubleTapDown(TapDownDetails details) {
|
||||
if (widget.selectionEnabled) {
|
||||
_renderEditable.selectWord(cause: SelectionChangedCause.doubleTap);
|
||||
@@ -810,7 +774,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
selectionColor: themeData.textSelectionColor,
|
||||
selectionControls: widget.selectionEnabled ? textSelectionControls : null,
|
||||
onChanged: widget.onChanged,
|
||||
onSelectionChanged: _handleSelectionChanged,
|
||||
onEditingComplete: widget.onEditingComplete,
|
||||
onSubmitted: widget.onSubmitted,
|
||||
inputFormatters: formatters,
|
||||
@@ -859,9 +822,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
onForcePressStart: forcePressEnabled ? _handleForcePressStarted : null,
|
||||
onSingleTapUp: _handleSingleTapUp,
|
||||
onSingleTapCancel: _handleSingleTapCancel,
|
||||
onSingleLongTapStart: _handleSingleLongTapStart,
|
||||
onSingleLongTapDragUpdate: _handleSingleLongTapDragUpdate,
|
||||
onSingleLongTapUp: _handleSingleLongTapUp,
|
||||
onSingleLongTapDown: _handleSingleLongTapDown,
|
||||
onDoubleTapDown: _handleDoubleTapDown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: child,
|
||||
|
||||
@@ -1191,7 +1191,7 @@ class RenderEditable extends RenderBox {
|
||||
/// When [ignorePointer] is true, an ancestor widget must respond to tap
|
||||
/// down events by calling this method.
|
||||
void handleTapDown(TapDownDetails details) {
|
||||
_lastTapDownPosition = details.globalPosition - _paintOffset;
|
||||
_lastTapDownPosition = details.globalPosition + -_paintOffset;
|
||||
}
|
||||
void _handleTapDown(TapDownDetails details) {
|
||||
assert(!ignorePointer);
|
||||
@@ -1247,27 +1247,12 @@ class RenderEditable extends RenderBox {
|
||||
/// programmatically manipulate its `value` or `selection` directly.
|
||||
/// {@endtemplate}
|
||||
void selectPosition({@required SelectionChangedCause cause}) {
|
||||
selectPositionAt(from: _lastTapDownPosition, cause: cause);
|
||||
}
|
||||
|
||||
/// Select text between the global positions [from] and [to].
|
||||
void selectPositionAt({@required Offset from, Offset to, @required SelectionChangedCause cause}) {
|
||||
assert(cause != null);
|
||||
_layoutText(constraints.maxWidth);
|
||||
assert(_lastTapDownPosition != null);
|
||||
if (onSelectionChanged != null) {
|
||||
final TextPosition fromPosition = _textPainter.getPositionForOffset(globalToLocal(from - _paintOffset));
|
||||
final TextPosition toPosition = to == null
|
||||
? null
|
||||
: _textPainter.getPositionForOffset(globalToLocal(to - _paintOffset));
|
||||
onSelectionChanged(
|
||||
TextSelection(
|
||||
baseOffset: fromPosition.offset,
|
||||
extentOffset: toPosition?.offset ?? fromPosition.offset,
|
||||
affinity: fromPosition.affinity,
|
||||
),
|
||||
this,
|
||||
cause,
|
||||
);
|
||||
final TextPosition position = _textPainter.getPositionForOffset(globalToLocal(_lastTapDownPosition));
|
||||
onSelectionChanged(TextSelection.fromPosition(position), this, cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1288,10 +1273,10 @@ class RenderEditable extends RenderBox {
|
||||
assert(cause != null);
|
||||
_layoutText(constraints.maxWidth);
|
||||
if (onSelectionChanged != null) {
|
||||
final TextPosition firstPosition = _textPainter.getPositionForOffset(globalToLocal(from - _paintOffset));
|
||||
final TextPosition firstPosition = _textPainter.getPositionForOffset(globalToLocal(from + -_paintOffset));
|
||||
final TextSelection firstWord = _selectWordAtOffset(firstPosition);
|
||||
final TextSelection lastWord = to == null ?
|
||||
firstWord : _selectWordAtOffset(_textPainter.getPositionForOffset(globalToLocal(to - _paintOffset)));
|
||||
firstWord : _selectWordAtOffset(_textPainter.getPositionForOffset(globalToLocal(to + -_paintOffset)));
|
||||
|
||||
onSelectionChanged(
|
||||
TextSelection(
|
||||
|
||||
@@ -19,10 +19,6 @@ export 'package:flutter/gestures.dart' show
|
||||
GestureTapCallback,
|
||||
GestureTapCancelCallback,
|
||||
GestureLongPressCallback,
|
||||
GestureLongPressUpCallback,
|
||||
GestureLongPressDragStartCallback,
|
||||
GestureLongPressDragUpdateCallback,
|
||||
GestureLongPressDragUpCallback,
|
||||
GestureDragDownCallback,
|
||||
GestureDragStartCallback,
|
||||
GestureDragUpdateCallback,
|
||||
@@ -35,9 +31,6 @@ export 'package:flutter/gestures.dart' show
|
||||
GestureForcePressPeakCallback,
|
||||
GestureForcePressEndCallback,
|
||||
GestureForcePressUpdateCallback,
|
||||
GestureLongPressDragStartDetails,
|
||||
GestureLongPressDragUpdateDetails,
|
||||
GestureLongPressDragUpDetails,
|
||||
ScaleStartDetails,
|
||||
ScaleUpdateDetails,
|
||||
ScaleEndDetails,
|
||||
@@ -157,10 +150,6 @@ class GestureDetector extends StatelessWidget {
|
||||
/// because a combination of a horizontal and vertical drag is a pan. Simply
|
||||
/// use the pan callbacks instead.
|
||||
///
|
||||
/// Long press and long press drag callbacks cannot be used simultaneously
|
||||
/// since they overlap. A long press cannot be subsequently dragged while a
|
||||
/// long press drag can be dragged after a long press.
|
||||
///
|
||||
/// By default, gesture detectors contribute semantic information to the tree
|
||||
/// that is used by assistive technology.
|
||||
GestureDetector({
|
||||
@@ -173,9 +162,6 @@ class GestureDetector extends StatelessWidget {
|
||||
this.onDoubleTap,
|
||||
this.onLongPress,
|
||||
this.onLongPressUp,
|
||||
this.onLongPressDragStart,
|
||||
this.onLongPressDragUpdate,
|
||||
this.onLongPressDragUp,
|
||||
this.onVerticalDragDown,
|
||||
this.onVerticalDragStart,
|
||||
this.onVerticalDragUpdate,
|
||||
@@ -208,8 +194,6 @@ class GestureDetector extends StatelessWidget {
|
||||
final bool haveHorizontalDrag = onHorizontalDragStart != null || onHorizontalDragUpdate != null || onHorizontalDragEnd != null;
|
||||
final bool havePan = onPanStart != null || onPanUpdate != null || onPanEnd != null;
|
||||
final bool haveScale = onScaleStart != null || onScaleUpdate != null || onScaleEnd != null;
|
||||
final bool haveLongPress = onLongPress != null || onLongPressUp != null;
|
||||
final bool haveLongPressDrag = onLongPressDragStart != null || onLongPressDragUpdate != null || onLongPressDragUp != null;
|
||||
if (havePan || haveScale) {
|
||||
if (havePan && haveScale) {
|
||||
throw FlutterError(
|
||||
@@ -226,15 +210,6 @@ class GestureDetector extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
if (haveLongPress && haveLongPressDrag) {
|
||||
throw FlutterError(
|
||||
'Incorrect GestureDetector arguments.\n'
|
||||
'Having both a long press and a long press drag recognizer is '
|
||||
'redundant as the long press drag is a superset of long press. '
|
||||
'Except long press drag allows for drags after the long press is '
|
||||
'triggered.'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}()),
|
||||
super(key: key);
|
||||
@@ -283,37 +258,11 @@ class GestureDetector extends StatelessWidget {
|
||||
|
||||
/// A pointer has remained in contact with the screen at the same location for
|
||||
/// a long period of time.
|
||||
///
|
||||
/// The long press drag callbacks [onLongPressDragStart], [onLongPressDragUpdate]
|
||||
/// and [onLongPressDragUp] cannot be set while this callback is set.
|
||||
final GestureLongPressCallback onLongPress;
|
||||
|
||||
/// A pointer that has triggered a long-press has stopped contacting the screen.
|
||||
///
|
||||
/// The long press drag callbacks [onLongPressDragStart], [onLongPressDragUpdate]
|
||||
/// and [onLongPressDragUp] cannot be set while this callback is set.
|
||||
final GestureLongPressUpCallback onLongPressUp;
|
||||
|
||||
/// A pointer has remained in contact with the screen at the same location for
|
||||
/// a long period of time and can subsequently be dragged.
|
||||
///
|
||||
/// The non-drag long press callbacks [onLongPress] and [onLongPressUp] cannot
|
||||
/// be set while this callback is set.
|
||||
final GestureLongPressDragStartCallback onLongPressDragStart;
|
||||
|
||||
/// A pointer has been drag-moved after a long press.
|
||||
///
|
||||
/// The non-drag long press callbacks [onLongPress] and [onLongPressUp] cannot
|
||||
/// be set while this callback is set.
|
||||
final GestureLongPressDragUpdateCallback onLongPressDragUpdate;
|
||||
|
||||
/// A pointer that has triggered a long press has stopped contacting the screen
|
||||
/// regardless of whether the pointer is dragged after the long press.
|
||||
///
|
||||
/// The non-drag long press callbacks [onLongPress] and [onLongPressUp] cannot
|
||||
/// be set while this callback is set.
|
||||
final GestureLongPressDragUpCallback onLongPressDragUp;
|
||||
|
||||
/// A pointer has contacted the screen and might begin to move vertically.
|
||||
final GestureDragDownCallback onVerticalDragDown;
|
||||
|
||||
@@ -473,7 +422,7 @@ class GestureDetector extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if (onLongPress != null || onLongPressUp != null) {
|
||||
if (onLongPress != null || onLongPressUp !=null) {
|
||||
gestures[LongPressGestureRecognizer] = GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
|
||||
() => LongPressGestureRecognizer(debugOwner: this),
|
||||
(LongPressGestureRecognizer instance) {
|
||||
@@ -484,18 +433,6 @@ class GestureDetector extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if (onLongPressDragStart != null || onLongPressDragUpdate != null || onLongPressDragUp != null) {
|
||||
gestures[LongPressDragGestureRecognizer] = GestureRecognizerFactoryWithHandlers<LongPressDragGestureRecognizer>(
|
||||
() => LongPressDragGestureRecognizer(debugOwner: this),
|
||||
(LongPressDragGestureRecognizer instance) {
|
||||
instance
|
||||
..onLongPressStart = onLongPressDragStart
|
||||
..onLongPressDragUpdate = onLongPressDragUpdate
|
||||
..onLongPressUp = onLongPressDragUp;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (onVerticalDragDown != null ||
|
||||
onVerticalDragStart != null ||
|
||||
onVerticalDragUpdate != null ||
|
||||
|
||||
@@ -617,9 +617,7 @@ class TextSelectionGestureDetector extends StatefulWidget {
|
||||
this.onForcePressEnd,
|
||||
this.onSingleTapUp,
|
||||
this.onSingleTapCancel,
|
||||
this.onSingleLongTapStart,
|
||||
this.onSingleLongTapDragUpdate,
|
||||
this.onSingleLongTapUp,
|
||||
this.onSingleLongTapDown,
|
||||
this.onDoubleTapDown,
|
||||
this.behavior,
|
||||
@required this.child,
|
||||
@@ -653,13 +651,7 @@ class TextSelectionGestureDetector extends StatefulWidget {
|
||||
/// Called for a single long tap that's sustained for longer than
|
||||
/// [kLongPressTimeout] but not necessarily lifted. Not called for a
|
||||
/// double-tap-hold, which calls [onDoubleTapDown] instead.
|
||||
final GestureLongPressDragStartCallback onSingleLongTapStart;
|
||||
|
||||
/// Called after [onSingleLongTapStart] when the pointer is dragged.
|
||||
final GestureLongPressDragUpdateCallback onSingleLongTapDragUpdate;
|
||||
|
||||
/// Called after [onSingleLongTapStart] when the pointer is lifted.
|
||||
final GestureLongPressDragUpCallback onSingleLongTapUp;
|
||||
final GestureLongPressCallback onSingleLongTapDown;
|
||||
|
||||
/// Called after a momentary hold or a short tap that is close in space and
|
||||
/// time (within [kDoubleTapTimeout]) to a previous short tap.
|
||||
@@ -743,21 +735,9 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec
|
||||
widget.onForcePressEnd(details);
|
||||
}
|
||||
|
||||
void _handleLongDragStart(GestureLongPressDragStartDetails details) {
|
||||
if (!_isDoubleTap && widget.onSingleLongTapStart != null) {
|
||||
widget.onSingleLongTapStart(details);
|
||||
}
|
||||
}
|
||||
|
||||
void _handleLongDragUpdate(GestureLongPressDragUpdateDetails details) {
|
||||
if (!_isDoubleTap && widget.onSingleLongTapDragUpdate != null) {
|
||||
widget.onSingleLongTapDragUpdate(details);
|
||||
}
|
||||
}
|
||||
|
||||
void _handleLongDragUp(GestureLongPressDragUpDetails details) {
|
||||
if (!_isDoubleTap && widget.onSingleLongTapUp != null) {
|
||||
widget.onSingleLongTapUp(details);
|
||||
void _handleLongPress() {
|
||||
if (!_isDoubleTap && widget.onSingleLongTapDown != null) {
|
||||
widget.onSingleLongTapDown();
|
||||
}
|
||||
_isDoubleTap = false;
|
||||
}
|
||||
@@ -785,9 +765,7 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec
|
||||
onForcePressStart: widget.onForcePressStart != null ? _forcePressStarted : null,
|
||||
onForcePressEnd: widget.onForcePressEnd != null ? _forcePressEnded : null,
|
||||
onTapCancel: _handleTapCancel,
|
||||
onLongPressDragStart: _handleLongDragStart,
|
||||
onLongPressDragUpdate: _handleLongDragUpdate,
|
||||
onLongPressDragUp: _handleLongDragUp,
|
||||
onLongPress: _handleLongPress,
|
||||
excludeFromSemantics: true,
|
||||
behavior: widget.behavior,
|
||||
child: widget.child,
|
||||
|
||||
@@ -1046,7 +1046,7 @@ void main() {
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'long press tap cannot initiate a double tap',
|
||||
'long press tap is not a double tap',
|
||||
(WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Atwater Peel Sherbrooke Bonaventure',
|
||||
@@ -1076,162 +1076,11 @@ void main() {
|
||||
const TextSelection.collapsed(offset: 7, affinity: TextAffinity.upstream),
|
||||
);
|
||||
|
||||
// The toolbar from the long press is now dismissed by the second tap.
|
||||
// Collapsed toolbar shows 2 buttons.
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'long press drag moves the cursor under the drag and shows toolbar on lift',
|
||||
(WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Atwater Peel Sherbrooke Bonaventure',
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
home: Center(
|
||||
child: CupertinoTextField(
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final Offset textfieldStart = tester.getTopLeft(find.byType(CupertinoTextField));
|
||||
|
||||
final TestGesture gesture =
|
||||
await tester.startGesture(textfieldStart + const Offset(50.0, 5.0));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
// Long press on iOS shows collapsed selection cursor.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 3, affinity: TextAffinity.upstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.moveBy(const Offset(50, 0));
|
||||
await tester.pump();
|
||||
|
||||
// The selection position is now moved with the drag.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 6, affinity: TextAffinity.upstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.moveBy(const Offset(50, 0));
|
||||
await tester.pump();
|
||||
|
||||
// The selection position is now moved with the drag.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 9, affinity: TextAffinity.upstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
|
||||
// The selection isn't affected by the gesture lift.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 9, affinity: TextAffinity.upstream),
|
||||
);
|
||||
// The toolbar now shows up.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(2));
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('long press drag can edge scroll', (WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges',
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
home: Center(
|
||||
child: CupertinoTextField(
|
||||
controller: controller,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RenderEditable renderEditable = tester.renderObject<RenderEditable>(
|
||||
find.byElementPredicate((Element element) => element.renderObject is RenderEditable)
|
||||
);
|
||||
|
||||
List<TextSelectionPoint> lastCharEndpoint = renderEditable.getEndpointsForSelection(
|
||||
const TextSelection.collapsed(offset: 66), // Last character's position.
|
||||
);
|
||||
|
||||
expect(lastCharEndpoint.length, 1);
|
||||
// Just testing the test and making sure that the last character is off
|
||||
// the right side of the screen.
|
||||
expect(lastCharEndpoint[0].point.dx, moreOrLessEquals(1094.73486328125));
|
||||
|
||||
final Offset textfieldStart = tester.getTopLeft(find.byType(CupertinoTextField));
|
||||
|
||||
final TestGesture gesture =
|
||||
await tester.startGesture(textfieldStart + const Offset(300, 5));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 18, affinity: TextAffinity.upstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.moveBy(const Offset(600, 0));
|
||||
// To the edge of the screen basically.
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 54, affinity: TextAffinity.upstream),
|
||||
);
|
||||
// Keep moving out.
|
||||
await gesture.moveBy(const Offset(1, 0));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 61, affinity: TextAffinity.upstream),
|
||||
);
|
||||
await gesture.moveBy(const Offset(1, 0));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
); // We're at the edge now.
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
|
||||
// The selection isn't affected by the gesture lift.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
);
|
||||
// The toolbar now shows up.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(2));
|
||||
|
||||
lastCharEndpoint = renderEditable.getEndpointsForSelection(
|
||||
const TextSelection.collapsed(offset: 66), // Last character's position.
|
||||
);
|
||||
|
||||
expect(lastCharEndpoint.length, 1);
|
||||
// The last character is now on screen.
|
||||
expect(lastCharEndpoint[0].point.dx, moreOrLessEquals(786.73486328125));
|
||||
|
||||
final List<TextSelectionPoint> firstCharEndpoint = renderEditable.getEndpointsForSelection(
|
||||
const TextSelection.collapsed(offset: 0), // First character's position.
|
||||
);
|
||||
expect(firstCharEndpoint.length, 1);
|
||||
// The first character is now offscreen to the left.
|
||||
expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-308.20499999821186));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'long tap after a double tap select is not affected',
|
||||
(WidgetTester tester) async {
|
||||
|
||||
@@ -9,275 +9,153 @@ import 'gesture_tester.dart';
|
||||
|
||||
const PointerDownEvent down = PointerDownEvent(
|
||||
pointer: 5,
|
||||
position: Offset(10, 10),
|
||||
position: Offset(10.0, 10.0)
|
||||
);
|
||||
|
||||
const PointerUpEvent up = PointerUpEvent(
|
||||
pointer: 5,
|
||||
position: Offset(11, 9),
|
||||
);
|
||||
|
||||
const PointerMoveEvent move = PointerMoveEvent(
|
||||
pointer: 5,
|
||||
position: Offset(100, 200),
|
||||
position: Offset(11.0, 9.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
setUp(ensureGestureBinding);
|
||||
|
||||
group('Long press', () {
|
||||
LongPressGestureRecognizer longPress;
|
||||
bool longPressDown;
|
||||
bool longPressUp;
|
||||
testGesture('Should recognize long press', (GestureTester tester) {
|
||||
final LongPressGestureRecognizer longPress = LongPressGestureRecognizer();
|
||||
|
||||
setUp(() {
|
||||
longPress = LongPressGestureRecognizer();
|
||||
longPressDown = false;
|
||||
longPress.onLongPress = () {
|
||||
longPressDown = true;
|
||||
};
|
||||
longPressUp = false;
|
||||
longPress.onLongPressUp = () {
|
||||
longPressUp = true;
|
||||
};
|
||||
});
|
||||
bool longPressRecognized = false;
|
||||
longPress.onLongPress = () {
|
||||
longPressRecognized = true;
|
||||
};
|
||||
|
||||
testGesture('Should recognize long press', (GestureTester tester) {
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
expect(longPressDown, isTrue);
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
expect(longPressRecognized, isTrue);
|
||||
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
testGesture('Up cancels long press', (GestureTester tester) {
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(up);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
expect(longPressDown, isFalse);
|
||||
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
testGesture('Moving before accept cancels', (GestureTester tester) {
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(move);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
tester.route(up);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressDown, isFalse);
|
||||
expect(longPressUp, isFalse);
|
||||
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
testGesture('Moving after accept cancels', (GestureTester tester) {
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
expect(longPressDown, isTrue);
|
||||
tester.route(move);
|
||||
tester.route(up);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
// longPressDown is still true since it already happened but up never
|
||||
// happens because it's been canceled since.
|
||||
expect(longPressDown, isTrue);
|
||||
expect(longPressUp, isFalse);
|
||||
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
testGesture('Should recognize both tap down and long press', (GestureTester tester) {
|
||||
final TapGestureRecognizer tap = TapGestureRecognizer();
|
||||
|
||||
bool tapDownRecognized = false;
|
||||
tap.onTapDown = (_) {
|
||||
tapDownRecognized = true;
|
||||
};
|
||||
|
||||
tap.addPointer(down);
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(tapDownRecognized, isFalse);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(down);
|
||||
expect(tapDownRecognized, isFalse);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(tapDownRecognized, isTrue);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
expect(tapDownRecognized, isTrue);
|
||||
expect(longPressDown, isTrue);
|
||||
|
||||
tap.dispose();
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
testGesture('Drag start delayed by microtask', (GestureTester tester) {
|
||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
||||
|
||||
bool isDangerousStack = false;
|
||||
|
||||
bool dragStartRecognized = false;
|
||||
drag.onStart = (DragStartDetails details) {
|
||||
expect(isDangerousStack, isFalse);
|
||||
dragStartRecognized = true;
|
||||
};
|
||||
|
||||
drag.addPointer(down);
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.route(down);
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressDown, isFalse);
|
||||
isDangerousStack = true;
|
||||
longPress.dispose();
|
||||
isDangerousStack = false;
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressDown, isFalse);
|
||||
tester.async.flushMicrotasks();
|
||||
expect(dragStartRecognized, isTrue);
|
||||
expect(longPressDown, isFalse);
|
||||
drag.dispose();
|
||||
});
|
||||
|
||||
testGesture('Should recognize long press up', (GestureTester tester) {
|
||||
bool longPressUpRecognized = false;
|
||||
longPress.onLongPressUp = () {
|
||||
longPressUpRecognized = true;
|
||||
};
|
||||
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressUpRecognized, isFalse);
|
||||
tester.route(down); // kLongPressTimeout = 500;
|
||||
expect(longPressUpRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressUpRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
tester.route(up);
|
||||
expect(longPressUpRecognized, isTrue);
|
||||
|
||||
longPress.dispose();
|
||||
});
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
group('long press drag', () {
|
||||
LongPressDragGestureRecognizer longPressDrag;
|
||||
bool longPressStart;
|
||||
bool longPressUp;
|
||||
Offset longPressDragUpdate;
|
||||
testGesture('Up cancels long press', (GestureTester tester) {
|
||||
final LongPressGestureRecognizer longPress = LongPressGestureRecognizer();
|
||||
|
||||
setUp(() {
|
||||
longPressDrag = LongPressDragGestureRecognizer();
|
||||
longPressStart = false;
|
||||
longPressDrag.onLongPressStart = (GestureLongPressDragStartDetails details) {
|
||||
longPressStart = true;
|
||||
};
|
||||
longPressUp = false;
|
||||
longPressDrag.onLongPressUp = (GestureLongPressDragUpDetails details) {
|
||||
longPressUp = true;
|
||||
};
|
||||
longPressDragUpdate = null;
|
||||
longPressDrag.onLongPressDragUpdate = (GestureLongPressDragUpdateDetails details) {
|
||||
longPressDragUpdate = details.globalPosition;
|
||||
};
|
||||
});
|
||||
bool longPressRecognized = false;
|
||||
longPress.onLongPress = () {
|
||||
longPressRecognized = true;
|
||||
};
|
||||
|
||||
testGesture('Should recognize long press down', (GestureTester tester) {
|
||||
longPressDrag.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
expect(longPressStart, isTrue);
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.route(up);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
expect(longPressRecognized, isFalse);
|
||||
|
||||
longPressDrag.dispose();
|
||||
});
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
testGesture('Short up cancels long press', (GestureTester tester) {
|
||||
longPressDrag.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressStart, isFalse);
|
||||
tester.route(up);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
expect(longPressStart, isFalse);
|
||||
testGesture('Should recognize both tap down and long press', (GestureTester tester) {
|
||||
final LongPressGestureRecognizer longPress = LongPressGestureRecognizer();
|
||||
final TapGestureRecognizer tap = TapGestureRecognizer();
|
||||
|
||||
longPressDrag.dispose();
|
||||
});
|
||||
bool tapDownRecognized = false;
|
||||
tap.onTapDown = (_) {
|
||||
tapDownRecognized = true;
|
||||
};
|
||||
|
||||
testGesture('Moving before accept cancels', (GestureTester tester) {
|
||||
longPressDrag.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressStart, isFalse);
|
||||
tester.route(move);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
tester.route(up);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressStart, isFalse);
|
||||
expect(longPressUp, isFalse);
|
||||
bool longPressRecognized = false;
|
||||
longPress.onLongPress = () {
|
||||
longPressRecognized = true;
|
||||
};
|
||||
|
||||
longPressDrag.dispose();
|
||||
});
|
||||
tap.addPointer(down);
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(tapDownRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.route(down);
|
||||
expect(tapDownRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(tapDownRecognized, isTrue);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
expect(tapDownRecognized, isTrue);
|
||||
expect(longPressRecognized, isTrue);
|
||||
|
||||
testGesture('Moving after accept does not cancel', (GestureTester tester) {
|
||||
longPressDrag.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.route(down);
|
||||
expect(longPressStart, isFalse);
|
||||
tester.async.elapse(const Duration(seconds: 1));
|
||||
expect(longPressStart, isTrue);
|
||||
tester.route(move);
|
||||
expect(longPressDragUpdate, const Offset(100, 200));
|
||||
tester.route(up);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressStart, isTrue);
|
||||
expect(longPressUp, isTrue);
|
||||
tap.dispose();
|
||||
longPress.dispose();
|
||||
});
|
||||
|
||||
longPressDrag.dispose();
|
||||
});
|
||||
testGesture('Drag start delayed by microtask', (GestureTester tester) {
|
||||
final LongPressGestureRecognizer longPress = LongPressGestureRecognizer();
|
||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
||||
|
||||
bool isDangerousStack = false;
|
||||
|
||||
bool dragStartRecognized = false;
|
||||
drag.onStart = (DragStartDetails details) {
|
||||
expect(isDangerousStack, isFalse);
|
||||
dragStartRecognized = true;
|
||||
};
|
||||
|
||||
bool longPressRecognized = false;
|
||||
longPress.onLongPress = () {
|
||||
expect(isDangerousStack, isFalse);
|
||||
longPressRecognized = true;
|
||||
};
|
||||
|
||||
drag.addPointer(down);
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.route(down);
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
isDangerousStack = true;
|
||||
longPress.dispose();
|
||||
isDangerousStack = false;
|
||||
expect(dragStartRecognized, isFalse);
|
||||
expect(longPressRecognized, isFalse);
|
||||
tester.async.flushMicrotasks();
|
||||
expect(dragStartRecognized, isTrue);
|
||||
expect(longPressRecognized, isFalse);
|
||||
drag.dispose();
|
||||
});
|
||||
|
||||
testGesture('Should recognize long press up', (GestureTester tester) {
|
||||
final LongPressGestureRecognizer longPress = LongPressGestureRecognizer();
|
||||
|
||||
bool longPressUpRecognized = false;
|
||||
longPress.onLongPressUp = () {
|
||||
longPressUpRecognized = true;
|
||||
};
|
||||
|
||||
longPress.addPointer(down);
|
||||
tester.closeArena(5);
|
||||
expect(longPressUpRecognized, isFalse);
|
||||
tester.route(down); // kLongPressTimeout = 500;
|
||||
expect(longPressUpRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 300));
|
||||
expect(longPressUpRecognized, isFalse);
|
||||
tester.async.elapse(const Duration(milliseconds: 700));
|
||||
tester.route(up);
|
||||
expect(longPressUpRecognized, isTrue);
|
||||
|
||||
longPress.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4143,7 +4143,7 @@ void main() {
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'long press tap cannot initiate a double tap (iOS)',
|
||||
'long press tap is not a double tap (iOS)',
|
||||
(WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Atwater Peel Sherbrooke Bonaventure',
|
||||
@@ -4181,161 +4181,6 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'long press drag moves the cursor under the drag and shows toolbar on lift (iOS)',
|
||||
(WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Atwater Peel Sherbrooke Bonaventure',
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(platform: TargetPlatform.iOS),
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final Offset textfieldStart = tester.getTopLeft(find.byType(TextField));
|
||||
|
||||
final TestGesture gesture =
|
||||
await tester.startGesture(textfieldStart + const Offset(50.0, 5.0));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
// Long press on iOS shows collapsed selection cursor.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 3, affinity: TextAffinity.downstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.moveBy(const Offset(50, 0));
|
||||
await tester.pump();
|
||||
|
||||
// The selection position is now moved with the drag.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 6, affinity: TextAffinity.downstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.moveBy(const Offset(50, 0));
|
||||
await tester.pump();
|
||||
|
||||
// The selection position is now moved with the drag.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 9, affinity: TextAffinity.downstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
|
||||
// The selection isn't affected by the gesture lift.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 9, affinity: TextAffinity.downstream),
|
||||
);
|
||||
// The toolbar now shows up.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(2));
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('long press drag can edge scroll (iOS)', (WidgetTester tester) async {
|
||||
final TextEditingController controller = TextEditingController(
|
||||
text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges',
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(platform: TargetPlatform.iOS),
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RenderEditable renderEditable = findRenderEditable(tester);
|
||||
|
||||
List<TextSelectionPoint> lastCharEndpoint = renderEditable.getEndpointsForSelection(
|
||||
const TextSelection.collapsed(offset: 66), // Last character's position.
|
||||
);
|
||||
|
||||
expect(lastCharEndpoint.length, 1);
|
||||
// Just testing the test and making sure that the last character is off
|
||||
// the right side of the screen.
|
||||
expect(lastCharEndpoint[0].point.dx, 1056);
|
||||
|
||||
final Offset textfieldStart = tester.getTopLeft(find.byType(TextField));
|
||||
|
||||
final TestGesture gesture =
|
||||
await tester.startGesture(textfieldStart + const Offset(300, 5));
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 19, affinity: TextAffinity.upstream),
|
||||
);
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.moveBy(const Offset(600, 0));
|
||||
// To the edge of the screen basically.
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 56, affinity: TextAffinity.downstream),
|
||||
);
|
||||
// Keep moving out.
|
||||
await gesture.moveBy(const Offset(1, 0));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 62, affinity: TextAffinity.downstream),
|
||||
);
|
||||
await gesture.moveBy(const Offset(1, 0));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
); // We're at the edge now.
|
||||
expect(find.byType(CupertinoButton), findsNothing);
|
||||
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
|
||||
// The selection isn't affected by the gesture lift.
|
||||
expect(
|
||||
controller.selection,
|
||||
const TextSelection.collapsed(offset: 66, affinity: TextAffinity.upstream),
|
||||
);
|
||||
// The toolbar now shows up.
|
||||
expect(find.byType(CupertinoButton), findsNWidgets(2));
|
||||
|
||||
lastCharEndpoint = renderEditable.getEndpointsForSelection(
|
||||
const TextSelection.collapsed(offset: 66), // Last character's position.
|
||||
);
|
||||
|
||||
expect(lastCharEndpoint.length, 1);
|
||||
// The last character is now on screen.
|
||||
expect(lastCharEndpoint[0].point.dx, moreOrLessEquals(798.6666870117188));
|
||||
|
||||
final List<TextSelectionPoint> firstCharEndpoint = renderEditable.getEndpointsForSelection(
|
||||
const TextSelection.collapsed(offset: 0), // First character's position.
|
||||
);
|
||||
expect(firstCharEndpoint.length, 1);
|
||||
// The first character is now offscreen to the left.
|
||||
expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257.33331298828125));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'long tap after a double tap select is not affected (iOS)',
|
||||
(WidgetTester tester) async {
|
||||
|
||||
@@ -486,19 +486,4 @@ void main() {
|
||||
expect(horizontalDragStart, 1);
|
||||
expect(forcePressStart, 0);
|
||||
});
|
||||
|
||||
testWidgets('Cannot set both a long press and a long press drag callback', (WidgetTester tester) async {
|
||||
try {
|
||||
GestureDetector(
|
||||
onLongPress: () {},
|
||||
onLongPressDragUpdate: (GestureLongPressDragUpdateDetails details) {},
|
||||
child: Container(
|
||||
color: const Color(0xFF00FF00),
|
||||
),
|
||||
);
|
||||
throw 'setting long press and long press drag should throw';
|
||||
} on FlutterError catch (_) {
|
||||
// Should throw.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ void main() {
|
||||
int tapCount;
|
||||
int singleTapUpCount;
|
||||
int singleTapCancelCount;
|
||||
int singleLongTapStartCount;
|
||||
int singleLongTapDownCount;
|
||||
int doubleTapDownCount;
|
||||
int forcePressStartCount;
|
||||
int forcePressEndCount;
|
||||
@@ -17,7 +17,7 @@ void main() {
|
||||
void _handleTapDown(TapDownDetails details) { tapCount++; }
|
||||
void _handleSingleTapUp(TapUpDetails details) { singleTapUpCount++; }
|
||||
void _handleSingleTapCancel() { singleTapCancelCount++; }
|
||||
void _handleSingleLongTapStart(GestureLongPressDragStartDetails details) { singleLongTapStartCount++; }
|
||||
void _handleSingleLongTapDown() { singleLongTapDownCount++; }
|
||||
void _handleDoubleTapDown(TapDownDetails details) { doubleTapDownCount++; }
|
||||
void _handleForcePressStart(ForcePressDetails details) { forcePressStartCount++; }
|
||||
void _handleForcePressEnd(ForcePressDetails details) { forcePressEndCount++; }
|
||||
@@ -26,7 +26,7 @@ void main() {
|
||||
tapCount = 0;
|
||||
singleTapUpCount = 0;
|
||||
singleTapCancelCount = 0;
|
||||
singleLongTapStartCount = 0;
|
||||
singleLongTapDownCount = 0;
|
||||
doubleTapDownCount = 0;
|
||||
forcePressStartCount = 0;
|
||||
forcePressEndCount = 0;
|
||||
@@ -39,7 +39,7 @@ void main() {
|
||||
onTapDown: _handleTapDown,
|
||||
onSingleTapUp: _handleSingleTapUp,
|
||||
onSingleTapCancel: _handleSingleTapCancel,
|
||||
onSingleLongTapStart: _handleSingleLongTapStart,
|
||||
onSingleLongTapDown: _handleSingleLongTapDown,
|
||||
onDoubleTapDown: _handleDoubleTapDown,
|
||||
onForcePressStart: _handleForcePressStart,
|
||||
onForcePressEnd: _handleForcePressEnd,
|
||||
@@ -106,7 +106,7 @@ void main() {
|
||||
expect(singleTapCancelCount, 0);
|
||||
expect(doubleTapDownCount, 1);
|
||||
// The double tap down hold supersedes the single tap down.
|
||||
expect(singleLongTapStartCount, 0);
|
||||
expect(singleLongTapDownCount, 0);
|
||||
|
||||
await gesture.up();
|
||||
// Nothing else happens on up.
|
||||
@@ -114,7 +114,7 @@ void main() {
|
||||
expect(tapCount, 2);
|
||||
expect(singleTapCancelCount, 0);
|
||||
expect(doubleTapDownCount, 1);
|
||||
expect(singleLongTapStartCount, 0);
|
||||
expect(singleLongTapDownCount, 0);
|
||||
});
|
||||
|
||||
testWidgets('a very quick swipe is just a canceled tap', (WidgetTester tester) async {
|
||||
@@ -127,7 +127,7 @@ void main() {
|
||||
expect(tapCount, 0);
|
||||
expect(singleTapCancelCount, 1);
|
||||
expect(doubleTapDownCount, 0);
|
||||
expect(singleLongTapStartCount, 0);
|
||||
expect(singleLongTapDownCount, 0);
|
||||
|
||||
await gesture.up();
|
||||
// Nothing else happens on up.
|
||||
@@ -135,7 +135,7 @@ void main() {
|
||||
expect(tapCount, 0);
|
||||
expect(singleTapCancelCount, 1);
|
||||
expect(doubleTapDownCount, 0);
|
||||
expect(singleLongTapStartCount, 0);
|
||||
expect(singleLongTapDownCount, 0);
|
||||
});
|
||||
|
||||
testWidgets('a slower swipe has a tap down and a canceled tap', (WidgetTester tester) async {
|
||||
@@ -148,7 +148,7 @@ void main() {
|
||||
expect(tapCount, 1);
|
||||
expect(singleTapCancelCount, 1);
|
||||
expect(doubleTapDownCount, 0);
|
||||
expect(singleLongTapStartCount, 0);
|
||||
expect(singleLongTapDownCount, 0);
|
||||
});
|
||||
|
||||
testWidgets('a force press intiates a force press', (WidgetTester tester) async {
|
||||
|
||||
Reference in New Issue
Block a user