// Copyright 2014 The Flutter 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 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'gesture_tester.dart'; class TestDrag extends Drag {} void main() { TestWidgetsFlutterBinding.ensureInitialized(); testGesture('MultiDrag: moving before delay rejects', (GestureTester tester) { final drag = DelayedMultiDragGestureRecognizer(); var didStartDrag = false; drag.onStart = (Offset position) { didStartDrag = true; return TestDrag(); }; final pointer = TestPointer(5); final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0)); drag.addPointer(down); tester.closeArena(5); expect(didStartDrag, isFalse); tester.async.flushMicrotasks(); expect(didStartDrag, isFalse); tester.route( pointer.move(const Offset(20.0, 60.0)), ); // move more than touch slop before delay expires expect(didStartDrag, isFalse); tester.async.elapse(kLongPressTimeout * 2); // expire delay expect(didStartDrag, isFalse); tester.route(pointer.move(const Offset(30.0, 120.0))); // move some more after delay expires expect(didStartDrag, isFalse); drag.dispose(); }); testGesture('MultiDrag: delay triggers', (GestureTester tester) { final drag = DelayedMultiDragGestureRecognizer(); var didStartDrag = false; drag.onStart = (Offset position) { didStartDrag = true; return TestDrag(); }; final pointer = TestPointer(5); final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0)); drag.addPointer(down); tester.closeArena(5); expect(didStartDrag, isFalse); tester.async.flushMicrotasks(); expect(didStartDrag, isFalse); tester.route( pointer.move(const Offset(20.0, 20.0)), ); // move less than touch slop before delay expires expect(didStartDrag, isFalse); tester.async.elapse(kLongPressTimeout * 2); // expire delay expect(didStartDrag, isTrue); tester.route( pointer.move(const Offset(30.0, 70.0)), ); // move more than touch slop after delay expires expect(didStartDrag, isTrue); drag.dispose(); }); testGesture('MultiDrag: can filter based on device kind', (GestureTester tester) { final drag = DelayedMultiDragGestureRecognizer( supportedDevices: {PointerDeviceKind.touch}, ); var didStartDrag = false; drag.onStart = (Offset position) { didStartDrag = true; return TestDrag(); }; final mousePointer = TestPointer(5, PointerDeviceKind.mouse); final PointerDownEvent down = mousePointer.down(const Offset(10.0, 10.0)); drag.addPointer(down); tester.closeArena(5); expect(didStartDrag, isFalse); tester.async.flushMicrotasks(); expect(didStartDrag, isFalse); tester.route( mousePointer.move(const Offset(20.0, 20.0)), ); // move less than touch slop before delay expires expect(didStartDrag, isFalse); tester.async.elapse(kLongPressTimeout * 2); // expire delay // Still false because it shouldn't recognize mouse events. expect(didStartDrag, isFalse); tester.route( mousePointer.move(const Offset(30.0, 70.0)), ); // move more than touch slop after delay expires // And still false. expect(didStartDrag, isFalse); drag.dispose(); }); test('allowedButtonsFilter should work the same when null or not specified', () { // Regression test for https://github.com/flutter/flutter/pull/122227 final recognizer1 = ImmediateMultiDragGestureRecognizer(); final recognizer2 = ImmediateMultiDragGestureRecognizer( allowedButtonsFilter: null, // ignore: avoid_redundant_argument_values ); // We want to test _allowedButtonsFilter, which is called in this method. const allowedPointer = PointerDownEvent(timeStamp: Duration(days: 10)); // ignore: invalid_use_of_protected_member expect(recognizer1.isPointerAllowed(allowedPointer), true); // ignore: invalid_use_of_protected_member expect(recognizer2.isPointerAllowed(allowedPointer), true); const rejectedPointer = PointerDownEvent( timeStamp: Duration(days: 10), buttons: kMiddleMouseButton, ); // ignore: invalid_use_of_protected_member expect(recognizer1.isPointerAllowed(rejectedPointer), false); // ignore: invalid_use_of_protected_member expect(recognizer2.isPointerAllowed(rejectedPointer), false); }); test('$MultiDragPointerState dispatches memory events', () async { await expectLater( await memoryEvents( () => _MultiDragPointerState(Offset.zero, PointerDeviceKind.touch, null).dispose(), _MultiDragPointerState, ), areCreateAndDispose, ); }); } class _MultiDragPointerState extends MultiDragPointerState { _MultiDragPointerState(super.initialPosition, super.kind, super.gestureSettings); @override void accepted(GestureMultiDragStartCallback starter) {} @override void dispose() { super.dispose(); } }