mirror of
https://github.com/alibaba/flutter-go.git
synced 2025-07-15 03:04:25 +08:00
590 lines
18 KiB
Dart
590 lines
18 KiB
Dart
// 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 'dart:math' as math;
|
|
|
|
import 'package:flutter_web_test/flutter_web_test.dart';
|
|
import 'package:flutter_web/gestures.dart';
|
|
|
|
import 'gesture_tester.dart';
|
|
|
|
void main() {
|
|
setUp(ensureGestureBinding);
|
|
|
|
testGesture('Should recognize scale gestures', (GestureTester tester) {
|
|
final ScaleGestureRecognizer scale = ScaleGestureRecognizer();
|
|
final TapGestureRecognizer tap = TapGestureRecognizer();
|
|
|
|
bool didStartScale = false;
|
|
Offset updatedFocalPoint;
|
|
scale.onStart = (ScaleStartDetails details) {
|
|
didStartScale = true;
|
|
updatedFocalPoint = details.focalPoint;
|
|
};
|
|
|
|
double updatedScale;
|
|
double updatedHorizontalScale;
|
|
double updatedVerticalScale;
|
|
scale.onUpdate = (ScaleUpdateDetails details) {
|
|
updatedScale = details.scale;
|
|
updatedHorizontalScale = details.horizontalScale;
|
|
updatedVerticalScale = details.verticalScale;
|
|
updatedFocalPoint = details.focalPoint;
|
|
};
|
|
|
|
bool didEndScale = false;
|
|
scale.onEnd = (ScaleEndDetails details) {
|
|
didEndScale = true;
|
|
};
|
|
|
|
bool didTap = false;
|
|
tap.onTap = () {
|
|
didTap = true;
|
|
};
|
|
|
|
final TestPointer pointer1 = TestPointer(1);
|
|
|
|
final PointerDownEvent down = pointer1.down(const Offset(0.0, 0.0));
|
|
scale.addPointer(down);
|
|
tap.addPointer(down);
|
|
|
|
tester.closeArena(1);
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedScale, isNull);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// One-finger panning
|
|
tester.route(down);
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedScale, isNull);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
tester.route(pointer1.move(const Offset(20.0, 30.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(20.0, 30.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 1.0);
|
|
updatedScale = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Two-finger scaling
|
|
final TestPointer pointer2 = TestPointer(2);
|
|
final PointerDownEvent down2 = pointer2.down(const Offset(10.0, 20.0));
|
|
scale.addPointer(down2);
|
|
tap.addPointer(down2);
|
|
tester.closeArena(2);
|
|
tester.route(down2);
|
|
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(updatedScale, isNull);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(didStartScale, isFalse);
|
|
|
|
// Zoom in
|
|
tester.route(pointer2.move(const Offset(0.0, 10.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(10.0, 20.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 2.0);
|
|
expect(updatedHorizontalScale, 2.0);
|
|
expect(updatedVerticalScale, 2.0);
|
|
updatedScale = null;
|
|
updatedHorizontalScale = null;
|
|
updatedVerticalScale = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Zoom out
|
|
tester.route(pointer2.move(const Offset(15.0, 25.0)));
|
|
expect(updatedFocalPoint, const Offset(17.5, 27.5));
|
|
expect(updatedScale, 0.5);
|
|
expect(updatedHorizontalScale, 0.5);
|
|
expect(updatedVerticalScale, 0.5);
|
|
expect(didTap, isFalse);
|
|
|
|
// Horizontal scaling
|
|
tester.route(pointer2.move(const Offset(0.0, 20.0)));
|
|
expect(updatedHorizontalScale, 2.0);
|
|
expect(updatedVerticalScale, 1.0);
|
|
|
|
// Vertical scaling
|
|
tester.route(pointer2.move(const Offset(10.0, 10.0)));
|
|
expect(updatedHorizontalScale, 1.0);
|
|
expect(updatedVerticalScale, 2.0);
|
|
tester.route(pointer2.move(const Offset(15.0, 25.0)));
|
|
updatedFocalPoint = null;
|
|
updatedScale = null;
|
|
|
|
// Three-finger scaling
|
|
final TestPointer pointer3 = TestPointer(3);
|
|
final PointerDownEvent down3 = pointer3.down(const Offset(25.0, 35.0));
|
|
scale.addPointer(down3);
|
|
tap.addPointer(down3);
|
|
tester.closeArena(3);
|
|
tester.route(down3);
|
|
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(updatedScale, isNull);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(didStartScale, isFalse);
|
|
|
|
// Zoom in
|
|
tester.route(pointer3.move(const Offset(55.0, 65.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(30.0, 40.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 5.0);
|
|
updatedScale = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Return to original positions but with different fingers
|
|
tester.route(pointer1.move(const Offset(25.0, 35.0)));
|
|
tester.route(pointer2.move(const Offset(20.0, 30.0)));
|
|
tester.route(pointer3.move(const Offset(15.0, 25.0)));
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, const Offset(20.0, 30.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 1.0);
|
|
updatedScale = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
tester.route(pointer1.up());
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedScale, isNull);
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(didTap, isFalse);
|
|
|
|
// Continue scaling with two fingers
|
|
tester.route(pointer3.move(const Offset(10.0, 20.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(15.0, 25.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 2.0);
|
|
updatedScale = null;
|
|
|
|
// Continue rotating with two fingers
|
|
tester.route(pointer3.move(const Offset(30.0, 40.0)));
|
|
expect(updatedFocalPoint, const Offset(25.0, 35.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 2.0);
|
|
updatedScale = null;
|
|
tester.route(pointer3.move(const Offset(10.0, 20.0)));
|
|
expect(updatedFocalPoint, const Offset(15.0, 25.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 2.0);
|
|
updatedScale = null;
|
|
|
|
tester.route(pointer2.up());
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedScale, isNull);
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(didTap, isFalse);
|
|
|
|
// Continue panning with one finger
|
|
tester.route(pointer3.move(const Offset(0.0, 0.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(0.0, 0.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 1.0);
|
|
updatedScale = null;
|
|
|
|
// We are done
|
|
tester.route(pointer3.up());
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedScale, isNull);
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(didTap, isFalse);
|
|
|
|
scale.dispose();
|
|
tap.dispose();
|
|
});
|
|
|
|
testGesture('Rejects scale gestures from unallowed device kinds',
|
|
(GestureTester tester) {
|
|
final ScaleGestureRecognizer scale =
|
|
ScaleGestureRecognizer(kind: PointerDeviceKind.touch);
|
|
|
|
bool didStartScale = false;
|
|
scale.onStart = (ScaleStartDetails details) {
|
|
didStartScale = true;
|
|
};
|
|
|
|
double updatedScale;
|
|
scale.onUpdate = (ScaleUpdateDetails details) {
|
|
updatedScale = details.scale;
|
|
};
|
|
|
|
final TestPointer mousePointer = TestPointer(1, PointerDeviceKind.mouse);
|
|
|
|
final PointerDownEvent down = mousePointer.down(const Offset(0.0, 0.0));
|
|
scale.addPointer(down);
|
|
tester.closeArena(1);
|
|
|
|
// One-finger panning
|
|
tester.route(down);
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedScale, isNull);
|
|
|
|
// Using a mouse, the scale gesture shouldn't even start.
|
|
tester.route(mousePointer.move(const Offset(20.0, 30.0)));
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedScale, isNull);
|
|
|
|
scale.dispose();
|
|
});
|
|
|
|
testGesture(
|
|
'Scale gestures starting from allowed device kinds cannot be ended from unallowed devices',
|
|
(GestureTester tester) {
|
|
final ScaleGestureRecognizer scale =
|
|
ScaleGestureRecognizer(kind: PointerDeviceKind.touch);
|
|
|
|
bool didStartScale = false;
|
|
Offset updatedFocalPoint;
|
|
scale.onStart = (ScaleStartDetails details) {
|
|
didStartScale = true;
|
|
updatedFocalPoint = details.focalPoint;
|
|
};
|
|
|
|
double updatedScale;
|
|
scale.onUpdate = (ScaleUpdateDetails details) {
|
|
updatedScale = details.scale;
|
|
updatedFocalPoint = details.focalPoint;
|
|
};
|
|
|
|
bool didEndScale = false;
|
|
scale.onEnd = (ScaleEndDetails details) {
|
|
didEndScale = true;
|
|
};
|
|
|
|
final TestPointer touchPointer = TestPointer(1, PointerDeviceKind.touch);
|
|
|
|
final PointerDownEvent down = touchPointer.down(const Offset(0.0, 0.0));
|
|
scale.addPointer(down);
|
|
tester.closeArena(1);
|
|
|
|
// One-finger panning
|
|
tester.route(down);
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedScale, isNull);
|
|
expect(updatedFocalPoint, const Offset(0.0, 0.0));
|
|
expect(didEndScale, isFalse);
|
|
|
|
// The gesture can start using one touch finger.
|
|
tester.route(touchPointer.move(const Offset(20.0, 30.0)));
|
|
expect(updatedFocalPoint, const Offset(20.0, 30.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedScale, 1.0);
|
|
updatedScale = null;
|
|
expect(didEndScale, isFalse);
|
|
|
|
// Two-finger scaling
|
|
final TestPointer mousePointer = TestPointer(2, PointerDeviceKind.mouse);
|
|
final PointerDownEvent down2 = mousePointer.down(const Offset(10.0, 20.0));
|
|
scale.addPointer(down2);
|
|
tester.closeArena(2);
|
|
tester.route(down2);
|
|
|
|
// Mouse-generated events are ignored.
|
|
expect(didEndScale, isFalse);
|
|
expect(updatedScale, isNull);
|
|
expect(didStartScale, isFalse);
|
|
|
|
// Zoom in using a mouse doesn't work either.
|
|
tester.route(mousePointer.move(const Offset(0.0, 10.0)));
|
|
expect(updatedScale, isNull);
|
|
expect(didEndScale, isFalse);
|
|
|
|
scale.dispose();
|
|
});
|
|
|
|
testGesture('Scale gesture competes with drag', (GestureTester tester) {
|
|
final ScaleGestureRecognizer scale = ScaleGestureRecognizer();
|
|
final HorizontalDragGestureRecognizer drag =
|
|
HorizontalDragGestureRecognizer();
|
|
|
|
final List<String> log = <String>[];
|
|
|
|
scale.onStart = (ScaleStartDetails details) {
|
|
log.add('scale-start');
|
|
};
|
|
scale.onUpdate = (ScaleUpdateDetails details) {
|
|
log.add('scale-update');
|
|
};
|
|
scale.onEnd = (ScaleEndDetails details) {
|
|
log.add('scale-end');
|
|
};
|
|
|
|
drag.onStart = (DragStartDetails details) {
|
|
log.add('drag-start');
|
|
};
|
|
drag.onEnd = (DragEndDetails details) {
|
|
log.add('drag-end');
|
|
};
|
|
|
|
final TestPointer pointer1 = TestPointer(1);
|
|
|
|
final PointerDownEvent down = pointer1.down(const Offset(10.0, 10.0));
|
|
scale.addPointer(down);
|
|
drag.addPointer(down);
|
|
|
|
tester.closeArena(1);
|
|
expect(log, isEmpty);
|
|
|
|
// Vertical moves are scales.
|
|
tester.route(down);
|
|
expect(log, isEmpty);
|
|
|
|
// scale will win if focal point delta exceeds 18.0*2
|
|
|
|
tester.route(pointer1
|
|
.move(const Offset(10.0, 50.0))); // delta of 40.0 exceeds 18.0*2
|
|
expect(log, equals(<String>['scale-start', 'scale-update']));
|
|
log.clear();
|
|
|
|
final TestPointer pointer2 = TestPointer(2);
|
|
final PointerDownEvent down2 = pointer2.down(const Offset(10.0, 20.0));
|
|
scale.addPointer(down2);
|
|
drag.addPointer(down2);
|
|
|
|
tester.closeArena(2);
|
|
expect(log, isEmpty);
|
|
|
|
// Second pointer joins scale even though it moves horizontally.
|
|
tester.route(down2);
|
|
expect(log, <String>['scale-end']);
|
|
log.clear();
|
|
|
|
tester.route(pointer2.move(const Offset(30.0, 20.0)));
|
|
expect(log, equals(<String>['scale-start', 'scale-update']));
|
|
log.clear();
|
|
|
|
tester.route(pointer1.up());
|
|
expect(log, equals(<String>['scale-end']));
|
|
log.clear();
|
|
|
|
tester.route(pointer2.up());
|
|
expect(log, isEmpty);
|
|
log.clear();
|
|
|
|
// Horizontal moves are either drags or scales, depending on which wins first.
|
|
// TODO(ianh): https://github.com/flutter/flutter/issues/11384
|
|
// In this case, we move fast, so that the scale wins. If we moved slowly,
|
|
// the horizontal drag would win, since it was added first.
|
|
final TestPointer pointer3 = TestPointer(3);
|
|
final PointerDownEvent down3 = pointer3.down(const Offset(30.0, 30.0));
|
|
scale.addPointer(down3);
|
|
drag.addPointer(down3);
|
|
tester.closeArena(3);
|
|
tester.route(down3);
|
|
|
|
expect(log, isEmpty);
|
|
|
|
tester.route(pointer3.move(const Offset(100.0, 30.0)));
|
|
expect(log, equals(<String>['scale-start', 'scale-update']));
|
|
log.clear();
|
|
|
|
tester.route(pointer3.up());
|
|
expect(log, equals(<String>['scale-end']));
|
|
log.clear();
|
|
|
|
scale.dispose();
|
|
drag.dispose();
|
|
});
|
|
|
|
testGesture('Should recognize rotation gestures', (GestureTester tester) {
|
|
final ScaleGestureRecognizer scale = ScaleGestureRecognizer();
|
|
final TapGestureRecognizer tap = TapGestureRecognizer();
|
|
|
|
bool didStartScale = false;
|
|
Offset updatedFocalPoint;
|
|
scale.onStart = (ScaleStartDetails details) {
|
|
didStartScale = true;
|
|
updatedFocalPoint = details.focalPoint;
|
|
};
|
|
|
|
double updatedRotation;
|
|
scale.onUpdate = (ScaleUpdateDetails details) {
|
|
updatedRotation = details.rotation;
|
|
updatedFocalPoint = details.focalPoint;
|
|
};
|
|
|
|
bool didEndScale = false;
|
|
scale.onEnd = (ScaleEndDetails details) {
|
|
didEndScale = true;
|
|
};
|
|
|
|
bool didTap = false;
|
|
tap.onTap = () {
|
|
didTap = true;
|
|
};
|
|
|
|
final TestPointer pointer1 = TestPointer(1);
|
|
|
|
final PointerDownEvent down = pointer1.down(const Offset(0.0, 0.0));
|
|
scale.addPointer(down);
|
|
tap.addPointer(down);
|
|
|
|
tester.closeArena(1);
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedRotation, isNull);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
tester.route(down);
|
|
tester.route(pointer1.move(const Offset(20.0, 30.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
|
|
expect(updatedFocalPoint, const Offset(20.0, 30.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, 0.0);
|
|
updatedRotation = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Two-finger scaling
|
|
final TestPointer pointer2 = TestPointer(2);
|
|
final PointerDownEvent down2 = pointer2.down(const Offset(30.0, 40.0));
|
|
scale.addPointer(down2);
|
|
tap.addPointer(down2);
|
|
tester.closeArena(2);
|
|
tester.route(down2);
|
|
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedRotation, isNull);
|
|
expect(didStartScale, isFalse);
|
|
|
|
// Zoom in
|
|
tester.route(pointer2.move(const Offset(40.0, 50.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(30.0, 40.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, 0.0);
|
|
updatedRotation = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Rotation
|
|
tester.route(pointer2.move(const Offset(0.0, 10.0)));
|
|
expect(updatedFocalPoint, const Offset(10.0, 20.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, math.pi);
|
|
updatedRotation = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Three-finger scaling
|
|
final TestPointer pointer3 = TestPointer(3);
|
|
final PointerDownEvent down3 = pointer3.down(const Offset(25.0, 35.0));
|
|
scale.addPointer(down3);
|
|
tap.addPointer(down3);
|
|
tester.closeArena(3);
|
|
tester.route(down3);
|
|
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedRotation, isNull);
|
|
expect(didStartScale, isFalse);
|
|
|
|
// Zoom in
|
|
tester.route(pointer3.move(const Offset(55.0, 65.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(25.0, 35.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, 0.0);
|
|
updatedRotation = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
// Return to original positions but with different fingers
|
|
tester.route(pointer1.move(const Offset(25.0, 35.0)));
|
|
tester.route(pointer2.move(const Offset(20.0, 30.0)));
|
|
tester.route(pointer3.move(const Offset(15.0, 25.0)));
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, const Offset(20.0, 30.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, 0.0);
|
|
updatedRotation = null;
|
|
expect(didEndScale, isFalse);
|
|
expect(didTap, isFalse);
|
|
|
|
tester.route(pointer1.up());
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedRotation, isNull);
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(didTap, isFalse);
|
|
|
|
// Continue scaling with two fingers
|
|
tester.route(pointer3.move(const Offset(10.0, 20.0)));
|
|
expect(didStartScale, isTrue);
|
|
didStartScale = false;
|
|
expect(updatedFocalPoint, const Offset(15.0, 25.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, 0.0);
|
|
updatedRotation = null;
|
|
|
|
// Continue rotating with two fingers
|
|
tester.route(pointer3.move(const Offset(30.0, 40.0)));
|
|
expect(updatedFocalPoint, const Offset(25.0, 35.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, -math.pi);
|
|
updatedRotation = null;
|
|
tester.route(pointer3.move(const Offset(10.0, 20.0)));
|
|
expect(updatedFocalPoint, const Offset(15.0, 25.0));
|
|
updatedFocalPoint = null;
|
|
expect(updatedRotation, 0.0);
|
|
updatedRotation = null;
|
|
|
|
tester.route(pointer2.up());
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedRotation, isNull);
|
|
expect(didEndScale, isTrue);
|
|
didEndScale = false;
|
|
expect(didTap, isFalse);
|
|
|
|
// We are done
|
|
tester.route(pointer3.up());
|
|
expect(didStartScale, isFalse);
|
|
expect(updatedFocalPoint, isNull);
|
|
expect(updatedRotation, isNull);
|
|
expect(didEndScale, isFalse);
|
|
didEndScale = false;
|
|
expect(didTap, isFalse);
|
|
|
|
scale.dispose();
|
|
tap.dispose();
|
|
});
|
|
}
|