scale_test.dart 8.23 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4
// 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.

Adam Barth's avatar
Adam Barth committed
5
import 'package:flutter_test/flutter_test.dart';
6
import 'package:flutter/gestures.dart';
7

8 9
import 'gesture_tester.dart';

10
void main() {
11
  setUp(ensureGestureBinding);
12

13
  testGesture('Should recognize scale gestures', (GestureTester tester) {
14 15
    final ScaleGestureRecognizer scale = new ScaleGestureRecognizer();
    final TapGestureRecognizer tap = new TapGestureRecognizer();
16 17

    bool didStartScale = false;
18
    Offset updatedFocalPoint;
19
    scale.onStart = (ScaleStartDetails details) {
20
      didStartScale = true;
21
      updatedFocalPoint = details.focalPoint;
22 23 24
    };

    double updatedScale;
25 26 27
    scale.onUpdate = (ScaleUpdateDetails details) {
      updatedScale = details.scale;
      updatedFocalPoint = details.focalPoint;
28 29 30
    };

    bool didEndScale = false;
31
    scale.onEnd = (ScaleEndDetails details) {
32 33 34 35 36 37 38 39
      didEndScale = true;
    };

    bool didTap = false;
    tap.onTap = () {
      didTap = true;
    };

40
    final TestPointer pointer1 = new TestPointer(1);
41

42
    final PointerDownEvent down = pointer1.down(const Offset(0.0, 0.0));
43 44 45
    scale.addPointer(down);
    tap.addPointer(down);

46
    tester.closeArena(1);
47 48 49 50 51 52 53
    expect(didStartScale, isFalse);
    expect(updatedScale, isNull);
    expect(updatedFocalPoint, isNull);
    expect(didEndScale, isFalse);
    expect(didTap, isFalse);

    // One-finger panning
54
    tester.route(down);
55 56 57 58 59 60
    expect(didStartScale, isFalse);
    expect(updatedScale, isNull);
    expect(updatedFocalPoint, isNull);
    expect(didEndScale, isFalse);
    expect(didTap, isFalse);

61
    tester.route(pointer1.move(const Offset(20.0, 30.0)));
62 63
    expect(didStartScale, isTrue);
    didStartScale = false;
64
    expect(updatedFocalPoint, const Offset(20.0, 30.0));
65 66 67 68 69 70 71
    updatedFocalPoint = null;
    expect(updatedScale, 1.0);
    updatedScale = null;
    expect(didEndScale, isFalse);
    expect(didTap, isFalse);

    // Two-finger scaling
72
    final TestPointer pointer2 = new TestPointer(2);
73
    final PointerDownEvent down2 = pointer2.down(const Offset(10.0, 20.0));
74 75
    scale.addPointer(down2);
    tap.addPointer(down2);
76 77
    tester.closeArena(2);
    tester.route(down2);
78 79 80 81 82 83 84 85

    expect(didEndScale, isTrue);
    didEndScale = false;
    expect(updatedScale, isNull);
    expect(updatedFocalPoint, isNull);
    expect(didStartScale, isFalse);

    // Zoom in
86
    tester.route(pointer2.move(const Offset(0.0, 10.0)));
87 88
    expect(didStartScale, isTrue);
    didStartScale = false;
89
    expect(updatedFocalPoint, const Offset(10.0, 20.0));
90 91 92 93 94 95 96
    updatedFocalPoint = null;
    expect(updatedScale, 2.0);
    updatedScale = null;
    expect(didEndScale, isFalse);
    expect(didTap, isFalse);

    // Zoom out
97 98
    tester.route(pointer2.move(const Offset(15.0, 25.0)));
    expect(updatedFocalPoint, const Offset(17.5, 27.5));
99 100 101 102 103 104
    updatedFocalPoint = null;
    expect(updatedScale, 0.5);
    updatedScale = null;
    expect(didTap, isFalse);

    // Three-finger scaling
105
    final TestPointer pointer3 = new TestPointer(3);
106
    final PointerDownEvent down3 = pointer3.down(const Offset(25.0, 35.0));
107 108
    scale.addPointer(down3);
    tap.addPointer(down3);
109 110
    tester.closeArena(3);
    tester.route(down3);
111 112 113 114 115 116 117 118

    expect(didEndScale, isTrue);
    didEndScale = false;
    expect(updatedScale, isNull);
    expect(updatedFocalPoint, isNull);
    expect(didStartScale, isFalse);

    // Zoom in
119
    tester.route(pointer3.move(const Offset(55.0, 65.0)));
120 121
    expect(didStartScale, isTrue);
    didStartScale = false;
122
    expect(updatedFocalPoint, const Offset(30.0, 40.0));
123 124 125 126 127 128 129
    updatedFocalPoint = null;
    expect(updatedScale, 5.0);
    updatedScale = null;
    expect(didEndScale, isFalse);
    expect(didTap, isFalse);

    // Return to original positions but with different fingers
130 131 132
    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)));
133
    expect(didStartScale, isFalse);
134
    expect(updatedFocalPoint, const Offset(20.0, 30.0));
135 136 137 138 139 140
    updatedFocalPoint = null;
    expect(updatedScale, 1.0);
    updatedScale = null;
    expect(didEndScale, isFalse);
    expect(didTap, isFalse);

141
    tester.route(pointer1.up());
142 143 144 145 146 147 148 149
    expect(didStartScale, isFalse);
    expect(updatedFocalPoint, isNull);
    expect(updatedScale, isNull);
    expect(didEndScale, isTrue);
    didEndScale = false;
    expect(didTap, isFalse);

    // Continue scaling with two fingers
150
    tester.route(pointer3.move(const Offset(10.0, 20.0)));
151 152
    expect(didStartScale, isTrue);
    didStartScale = false;
153
    expect(updatedFocalPoint, const Offset(15.0, 25.0));
154 155 156 157
    updatedFocalPoint = null;
    expect(updatedScale, 2.0);
    updatedScale = null;

158
    tester.route(pointer2.up());
159 160 161 162 163 164 165 166
    expect(didStartScale, isFalse);
    expect(updatedFocalPoint, isNull);
    expect(updatedScale, isNull);
    expect(didEndScale, isTrue);
    didEndScale = false;
    expect(didTap, isFalse);

    // Continue panning with one finger
167
    tester.route(pointer3.move(const Offset(0.0, 0.0)));
168 169
    expect(didStartScale, isTrue);
    didStartScale = false;
170
    expect(updatedFocalPoint, const Offset(0.0, 0.0));
171 172 173 174 175
    updatedFocalPoint = null;
    expect(updatedScale, 1.0);
    updatedScale = null;

    // We are done
176
    tester.route(pointer3.up());
177 178 179 180 181 182 183 184 185 186
    expect(didStartScale, isFalse);
    expect(updatedFocalPoint, isNull);
    expect(updatedScale, isNull);
    expect(didEndScale, isTrue);
    didEndScale = false;
    expect(didTap, isFalse);

    scale.dispose();
    tap.dispose();
  });
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

  testGesture('Scale gesture competes with drag', (GestureTester tester) {
    final ScaleGestureRecognizer scale = new ScaleGestureRecognizer();
    final HorizontalDragGestureRecognizer drag = new 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 = new TestPointer(1);

203
    final PointerDownEvent down = pointer1.down(const Offset(10.0, 10.0));
204 205 206 207 208 209 210 211 212 213
    scale.addPointer(down);
    drag.addPointer(down);

    tester.closeArena(1);
    expect(log, isEmpty);

    // Vertical moves are scales.
    tester.route(down);
    expect(log, isEmpty);

214 215 216
    // 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
217 218 219 220
    expect(log, equals(<String>['scale-start', 'scale-update']));
    log.clear();

    final TestPointer pointer2 = new TestPointer(2);
221
    final PointerDownEvent down2 = pointer2.down(const Offset(10.0, 20.0));
222 223 224 225 226 227 228 229 230 231 232
    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();

233
    tester.route(pointer2.move(const Offset(30.0, 20.0)));
234 235 236 237 238 239 240 241 242 243 244
    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();

245 246 247 248
    // 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.
249
    final TestPointer pointer3 = new TestPointer(3);
250
    final PointerDownEvent down3 = pointer3.down(const Offset(30.0, 30.0));
251 252 253 254 255 256 257
    scale.addPointer(down3);
    drag.addPointer(down3);
    tester.closeArena(3);
    tester.route(down3);

    expect(log, isEmpty);

258
    tester.route(pointer3.move(const Offset(100.0, 30.0)));
259 260 261 262 263 264 265 266 267 268
    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();
  });
269
}