// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/gestures.dart'; import '../flutter_test_alternative.dart'; import 'gesture_tester.dart'; const PointerDownEvent down = PointerDownEvent( pointer: 5, position: Offset(10, 10), ); const PointerUpEvent up = PointerUpEvent( pointer: 5, position: Offset(11, 9), ); const PointerMoveEvent move = PointerMoveEvent( pointer: 5, position: Offset(100, 200), ); void main() { setUp(ensureGestureBinding); group('Long press', () { LongPressGestureRecognizer longPress; bool longPressDown; bool longPressUp; setUp(() { longPress = LongPressGestureRecognizer(); longPressDown = false; longPress.onLongPress = () { longPressDown = true; }; longPressUp = false; longPress.onLongPressUp = () { longPressUp = 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.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 is ok', (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)); expect(longPressDown, isTrue); expect(longPressUp, isTrue); 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(); }); }); group('long press drag', () { LongPressGestureRecognizer longPressDrag; bool longPressStart; bool longPressUp; Offset longPressDragUpdate; setUp(() { longPressDrag = LongPressGestureRecognizer(); longPressStart = false; longPressDrag.onLongPressStart = (LongPressStartDetails details) { longPressStart = true; }; longPressUp = false; longPressDrag.onLongPressEnd = (LongPressEndDetails details) { longPressUp = true; }; longPressDragUpdate = null; longPressDrag.onLongPressMoveUpdate = (LongPressMoveUpdateDetails details) { longPressDragUpdate = details.globalPosition; }; }); 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); longPressDrag.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); longPressDrag.dispose(); }); 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); longPressDrag.dispose(); }); 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); longPressDrag.dispose(); }); }); testGesture('Can filter long press based on device kind', (GestureTester tester) { final LongPressGestureRecognizer mouseLongPress = LongPressGestureRecognizer(kind: PointerDeviceKind.mouse); bool mouseLongPressDown = false; mouseLongPress.onLongPress = () { mouseLongPressDown = true; }; const PointerDownEvent mouseDown = PointerDownEvent( pointer: 5, position: Offset(10, 10), kind: PointerDeviceKind.mouse, ); const PointerDownEvent touchDown = PointerDownEvent( pointer: 5, position: Offset(10, 10), kind: PointerDeviceKind.touch, ); // Touch events shouldn't be recognized. mouseLongPress.addPointer(touchDown); tester.closeArena(5); expect(mouseLongPressDown, isFalse); tester.route(touchDown); expect(mouseLongPressDown, isFalse); tester.async.elapse(const Duration(seconds: 2)); expect(mouseLongPressDown, isFalse); // Mouse events are still recognized. mouseLongPress.addPointer(mouseDown); tester.closeArena(5); expect(mouseLongPressDown, isFalse); tester.route(mouseDown); expect(mouseLongPressDown, isFalse); tester.async.elapse(const Duration(seconds: 2)); expect(mouseLongPressDown, isTrue); mouseLongPress.dispose(); }); }