blob: d1e33fbd10c68237c797e195b4fe442973b40d29 [file] [log] [blame]
// 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 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'gesture_utils.dart';
void main() {
testWidgets('Events bubble up the tree', (WidgetTester tester) async {
final List<String> log = <String>[];
await tester.pumpWidget(
Listener(
onPointerDown: (_) {
log.add('top');
},
child: Listener(
onPointerDown: (_) {
log.add('middle');
},
child: DecoratedBox(
decoration: const BoxDecoration(),
child: Listener(
onPointerDown: (_) {
log.add('bottom');
},
child: const Text('X', textDirection: TextDirection.ltr),
),
),
),
),
);
await tester.tap(find.text('X'));
expect(log, equals(<String>[
'bottom',
'middle',
'top',
]));
});
testWidgets('Detects hover events from touch devices', (WidgetTester tester) async {
final List<String> log = <String>[];
await tester.pumpWidget(
Center(
child: SizedBox(
width: 300,
height: 300,
child: Listener(
onPointerHover: (_) {
log.add('bottom');
},
child: const Text('X', textDirection: TextDirection.ltr),
),
),
),
);
final TestGesture gesture = await tester.createGesture();
await gesture.addPointer();
addTearDown(gesture.removePointer);
await gesture.moveTo(tester.getCenter(find.byType(Listener)));
expect(log, equals(<String>[
'bottom',
]));
});
group('transformed events', () {
testWidgets('simple offset for touch/signal', (WidgetTester tester) async {
final List<PointerEvent> events = <PointerEvent>[];
final Key key = UniqueKey();
await tester.pumpWidget(
Center(
child: Listener(
onPointerDown: (PointerDownEvent event) {
events.add(event);
},
onPointerUp: (PointerUpEvent event) {
events.add(event);
},
onPointerMove: (PointerMoveEvent event) {
events.add(event);
},
onPointerSignal: (PointerSignalEvent event) {
events.add(event);
},
child: Container(
key: key,
color: Colors.red,
height: 100,
width: 100,
),
),
),
);
const Offset moved = Offset(20, 30);
final Offset center = tester.getCenter(find.byKey(key));
final Offset topLeft = tester.getTopLeft(find.byKey(key));
final TestGesture gesture = await tester.startGesture(center);
await gesture.moveBy(moved);
await gesture.up();
expect(events, hasLength(3));
final PointerDownEvent down = events[0] as PointerDownEvent;
final PointerMoveEvent move = events[1] as PointerMoveEvent;
final PointerUpEvent up = events[2] as PointerUpEvent;
final Matrix4 expectedTransform = Matrix4.translationValues(-topLeft.dx, -topLeft.dy, 0);
expect(center, isNot(const Offset(50, 50)));
expect(down.localPosition, const Offset(50, 50));
expect(down.position, center);
expect(down.delta, Offset.zero);
expect(down.localDelta, Offset.zero);
expect(down.transform, expectedTransform);
expect(move.localPosition, const Offset(50, 50) + moved);
expect(move.position, center + moved);
expect(move.delta, moved);
expect(move.localDelta, moved);
expect(move.transform, expectedTransform);
expect(up.localPosition, const Offset(50, 50) + moved);
expect(up.position, center + moved);
expect(up.delta, Offset.zero);
expect(up.localDelta, Offset.zero);
expect(up.transform, expectedTransform);
events.clear();
await scrollAt(center, tester);
expect(events.single.localPosition, const Offset(50, 50));
expect(events.single.position, center);
expect(events.single.delta, Offset.zero);
expect(events.single.localDelta, Offset.zero);
expect(events.single.transform, expectedTransform);
});
testWidgets('scaled for touch/signal', (WidgetTester tester) async {
final List<PointerEvent> events = <PointerEvent>[];
final Key key = UniqueKey();
const double scaleFactor = 2;
await tester.pumpWidget(
Align(
alignment: Alignment.topLeft,
child: Transform(
transform: Matrix4.identity()..scale(scaleFactor),
child: Listener(
onPointerDown: (PointerDownEvent event) {
events.add(event);
},
onPointerUp: (PointerUpEvent event) {
events.add(event);
},
onPointerMove: (PointerMoveEvent event) {
events.add(event);
},
onPointerSignal: (PointerSignalEvent event) {
events.add(event);
},
child: Container(
key: key,
color: Colors.red,
height: 100,
width: 100,
),
),
),
),
);
const Offset moved = Offset(20, 30);
final Offset center = tester.getCenter(find.byKey(key));
final TestGesture gesture = await tester.startGesture(center);
addTearDown(gesture.removePointer);
await gesture.moveBy(moved);
await gesture.up();
expect(events, hasLength(3));
final PointerDownEvent down = events[0] as PointerDownEvent;
final PointerMoveEvent move = events[1] as PointerMoveEvent;
final PointerUpEvent up = events[2] as PointerUpEvent;
final Matrix4 expectedTransform = Matrix4.identity()
..scale(1 / scaleFactor, 1 / scaleFactor, 1.0);
expect(center, isNot(const Offset(50, 50)));
expect(down.localPosition, const Offset(50, 50));
expect(down.position, center);
expect(down.delta, Offset.zero);
expect(down.localDelta, Offset.zero);
expect(down.transform, expectedTransform);
expect(move.localPosition, const Offset(50, 50) + moved / scaleFactor);
expect(move.position, center + moved);
expect(move.delta, moved);
expect(move.localDelta, moved / scaleFactor);
expect(move.transform, expectedTransform);
expect(up.localPosition, const Offset(50, 50) + moved / scaleFactor);
expect(up.position, center + moved);
expect(up.delta, Offset.zero);
expect(up.localDelta, Offset.zero);
expect(up.transform, expectedTransform);
events.clear();
await scrollAt(center, tester);
expect(events.single.localPosition, const Offset(50, 50));
expect(events.single.position, center);
expect(events.single.delta, Offset.zero);
expect(events.single.localDelta, Offset.zero);
expect(events.single.transform, expectedTransform);
});
testWidgets('scaled and offset for touch/signal', (WidgetTester tester) async {
final List<PointerEvent> events = <PointerEvent>[];
final Key key = UniqueKey();
const double scaleFactor = 2;
await tester.pumpWidget(
Center(
child: Transform(
transform: Matrix4.identity()..scale(scaleFactor),
child: Listener(
onPointerDown: (PointerDownEvent event) {
events.add(event);
},
onPointerUp: (PointerUpEvent event) {
events.add(event);
},
onPointerMove: (PointerMoveEvent event) {
events.add(event);
},
onPointerSignal: (PointerSignalEvent event) {
events.add(event);
},
child: Container(
key: key,
color: Colors.red,
height: 100,
width: 100,
),
),
),
),
);
const Offset moved = Offset(20, 30);
final Offset center = tester.getCenter(find.byKey(key));
final Offset topLeft = tester.getTopLeft(find.byKey(key));
final TestGesture gesture = await tester.startGesture(center);
addTearDown(gesture.removePointer);
await gesture.moveBy(moved);
await gesture.up();
expect(events, hasLength(3));
final PointerDownEvent down = events[0] as PointerDownEvent;
final PointerMoveEvent move = events[1] as PointerMoveEvent;
final PointerUpEvent up = events[2] as PointerUpEvent;
final Matrix4 expectedTransform = Matrix4.identity()
..scale(1 / scaleFactor, 1 / scaleFactor, 1.0)
..translate(-topLeft.dx, -topLeft.dy);
expect(center, isNot(const Offset(50, 50)));
expect(down.localPosition, const Offset(50, 50));
expect(down.position, center);
expect(down.delta, Offset.zero);
expect(down.localDelta, Offset.zero);
expect(down.transform, expectedTransform);
expect(move.localPosition, const Offset(50, 50) + moved / scaleFactor);
expect(move.position, center + moved);
expect(move.delta, moved);
expect(move.localDelta, moved / scaleFactor);
expect(move.transform, expectedTransform);
expect(up.localPosition, const Offset(50, 50) + moved / scaleFactor);
expect(up.position, center + moved);
expect(up.delta, Offset.zero);
expect(up.localDelta, Offset.zero);
expect(up.transform, expectedTransform);
events.clear();
await scrollAt(center, tester);
expect(events.single.localPosition, const Offset(50, 50));
expect(events.single.position, center);
expect(events.single.delta, Offset.zero);
expect(events.single.localDelta, Offset.zero);
expect(events.single.transform, expectedTransform);
});
testWidgets('rotated for touch/signal', (WidgetTester tester) async {
final List<PointerEvent> events = <PointerEvent>[];
final Key key = UniqueKey();
await tester.pumpWidget(
Center(
child: Transform(
transform: Matrix4.identity()
..rotateZ(math.pi / 2), // 90 degrees clockwise around Container origin
child: Listener(
onPointerDown: (PointerDownEvent event) {
events.add(event);
},
onPointerUp: (PointerUpEvent event) {
events.add(event);
},
onPointerMove: (PointerMoveEvent event) {
events.add(event);
},
onPointerSignal: (PointerSignalEvent event) {
events.add(event);
},
child: Container(
key: key,
color: Colors.red,
height: 100,
width: 100,
),
),
),
),
);
const Offset moved = Offset(20, 30);
final Offset downPosition = tester.getCenter(find.byKey(key)) + const Offset(10, 5);
final TestGesture gesture = await tester.startGesture(downPosition);
addTearDown(gesture.removePointer);
await gesture.moveBy(moved);
await gesture.up();
expect(events, hasLength(3));
final PointerDownEvent down = events[0] as PointerDownEvent;
final PointerMoveEvent move = events[1] as PointerMoveEvent;
final PointerUpEvent up = events[2] as PointerUpEvent;
const Offset offset = Offset((800 - 100) / 2, (600 - 100) / 2);
final Matrix4 expectedTransform = Matrix4.identity()
..rotateZ(-math.pi / 2)
..translate(-offset.dx, -offset.dy);
final Offset localDownPosition = const Offset(50, 50) + const Offset(5, -10);
expect(down.localPosition, within(distance: 0.001, from: localDownPosition));
expect(down.position, downPosition);
expect(down.delta, Offset.zero);
expect(down.localDelta, Offset.zero);
expect(down.transform, expectedTransform);
const Offset localDelta = Offset(30, -20);
expect(move.localPosition, within(distance: 0.001, from: localDownPosition + localDelta));
expect(move.position, downPosition + moved);
expect(move.delta, moved);
expect(move.localDelta, localDelta);
expect(move.transform, expectedTransform);
expect(up.localPosition, within(distance: 0.001, from: localDownPosition + localDelta));
expect(up.position, downPosition + moved);
expect(up.delta, Offset.zero);
expect(up.localDelta, Offset.zero);
expect(up.transform, expectedTransform);
events.clear();
await scrollAt(downPosition, tester);
expect(events.single.localPosition, within(distance: 0.001, from: localDownPosition));
expect(events.single.position, downPosition);
expect(events.single.delta, Offset.zero);
expect(events.single.localDelta, Offset.zero);
expect(events.single.transform, expectedTransform);
});
});
testWidgets("RenderPointerListener's debugFillProperties when default", (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
RenderPointerListener().debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'parentData: MISSING',
'constraints: MISSING',
'size: MISSING',
'behavior: deferToChild',
'listeners: <none>',
]);
});
testWidgets("RenderPointerListener's debugFillProperties when full", (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
RenderPointerListener(
onPointerDown: (PointerDownEvent event) {},
onPointerUp: (PointerUpEvent event) {},
onPointerMove: (PointerMoveEvent event) {},
onPointerCancel: (PointerCancelEvent event) {},
onPointerSignal: (PointerSignalEvent event) {},
behavior: HitTestBehavior.opaque,
child: RenderErrorBox(),
).debugFillProperties(builder);
final List<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'parentData: MISSING',
'constraints: MISSING',
'size: MISSING',
'behavior: opaque',
'listeners: down, move, up, cancel, signal',
]);
});
}