Unverified Commit 3f1f0aa5 authored by Anindya Chatterjee's avatar Anindya Chatterjee Committed by GitHub

Enable TapRegion to detect all mouse button click (#136799)

With this PR, TapRegion would be able to detect any kind of mouse button
events. Earlier, TapRegion used to detect only left mouse button event.

Fixes #136706

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
parent 0f67c992
......@@ -234,7 +234,7 @@ class RenderTapRegionSurface extends RenderProxyBoxWithHitTestBehavior implement
return true;
}(), 'A RenderTapRegion was registered when it was disabled.');
if (event is! PointerDownEvent || event.buttons != kPrimaryButton) {
if (event is! PointerDownEvent) {
return;
}
......
......@@ -480,4 +480,578 @@ void main() {
]));
tappedOutside.clear();
});
testWidgetsWithLeakTracking('TapRegionSurface detects outside right click', (WidgetTester tester) async {
final Set<String> tappedOutside = <String>{};
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
const Text('Outside Surface'),
TapRegionSurface(
child: Row(
children: <Widget>[
const Text('Outside'),
TapRegion(
onTapOutside: (PointerEvent event) {
tappedOutside.add('No Group');
},
child: const Text('No Group'),
),
TapRegion(
groupId: 1,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 A');
},
child: const Text('Group 1 A'),
),
TapRegion(
groupId: 1,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 B');
},
child: const Text('Group 1 B'),
),
],
),
),
],
),
),
);
await tester.pump();
Future<void> click(Finder finder) async {
final TestGesture gesture = await tester.startGesture(
tester.getCenter(finder),
kind: PointerDeviceKind.mouse,
buttons: kSecondaryButton,
);
await gesture.up();
await gesture.removePointer();
}
expect(tappedOutside, isEmpty);
await click(find.text('No Group'));
expect(
tappedOutside,
unorderedEquals(<String>{
'Group 1 A',
'Group 1 B',
}));
tappedOutside.clear();
await click(find.text('Group 1 A'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
tappedOutside.clear();
await click(find.text('Group 1 B'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
tappedOutside.clear();
await click(find.text('Outside'));
expect(
tappedOutside,
unorderedEquals(<String>{
'No Group',
'Group 1 A',
'Group 1 B',
}));
tappedOutside.clear();
await click(find.text('Outside Surface'));
expect(tappedOutside, isEmpty);
});
testWidgetsWithLeakTracking('TapRegionSurface detects outside middle click', (WidgetTester tester) async {
final Set<String> tappedOutside = <String>{};
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
const Text('Outside Surface'),
TapRegionSurface(
child: Row(
children: <Widget>[
const Text('Outside'),
TapRegion(
onTapOutside: (PointerEvent event) {
tappedOutside.add('No Group');
},
child: const Text('No Group'),
),
TapRegion(
groupId: 1,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 A');
},
child: const Text('Group 1 A'),
),
TapRegion(
groupId: 1,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 B');
},
child: const Text('Group 1 B'),
),
],
),
),
],
),
),
);
await tester.pump();
Future<void> click(Finder finder) async {
final TestGesture gesture = await tester.startGesture(
tester.getCenter(finder),
kind: PointerDeviceKind.mouse,
buttons: kTertiaryButton,
);
await gesture.up();
await gesture.removePointer();
}
expect(tappedOutside, isEmpty);
await click(find.text('No Group'));
expect(
tappedOutside,
unorderedEquals(<String>{
'Group 1 A',
'Group 1 B',
}));
tappedOutside.clear();
await click(find.text('Group 1 A'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
tappedOutside.clear();
await click(find.text('Group 1 B'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
tappedOutside.clear();
await click(find.text('Outside'));
expect(
tappedOutside,
unorderedEquals(<String>{
'No Group',
'Group 1 A',
'Group 1 B',
}));
tappedOutside.clear();
await click(find.text('Outside Surface'));
expect(tappedOutside, isEmpty);
});
testWidgetsWithLeakTracking('TapRegionSurface consumes outside right click when asked', (WidgetTester tester) async {
final Set<String> tappedOutside = <String>{};
int propagatedTaps = 0;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
const Text('Outside Surface'),
TapRegionSurface(
child: Row(
children: <Widget>[
GestureDetector(
onTap: () {
propagatedTaps += 1;
},
child: const Text('Outside'),
),
TapRegion(
consumeOutsideTaps: true,
onTapOutside: (PointerEvent event) {
tappedOutside.add('No Group');
},
child: const Text('No Group'),
),
TapRegion(
groupId: 1,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 A');
},
child: const Text('Group 1 A'),
),
TapRegion(
groupId: 1,
consumeOutsideTaps: true,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 B');
},
child: const Text('Group 1 B'),
),
],
),
),
],
),
),
);
await tester.pump();
Future<void> click(Finder finder) async {
final TestGesture gesture = await tester.startGesture(
tester.getCenter(finder),
kind: PointerDeviceKind.mouse,
buttons: kSecondaryButton
);
await gesture.up();
await gesture.removePointer();
}
expect(tappedOutside, isEmpty);
expect(propagatedTaps, equals(0));
await click(find.text('No Group'));
expect(
tappedOutside,
unorderedEquals(<String>{
'Group 1 A',
'Group 1 B',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Group 1 A'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Group 1 B'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Outside'));
expect(
tappedOutside,
unorderedEquals(<String>{
'No Group',
'Group 1 A',
'Group 1 B',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Outside Surface'));
expect(tappedOutside, isEmpty);
});
testWidgetsWithLeakTracking('TapRegionSurface consumes outside middle click when asked', (WidgetTester tester) async {
final Set<String> tappedOutside = <String>{};
int propagatedTaps = 0;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
const Text('Outside Surface'),
TapRegionSurface(
child: Row(
children: <Widget>[
GestureDetector(
onTap: () {
propagatedTaps += 1;
},
child: const Text('Outside'),
),
TapRegion(
consumeOutsideTaps: true,
onTapOutside: (PointerEvent event) {
tappedOutside.add('No Group');
},
child: const Text('No Group'),
),
TapRegion(
groupId: 1,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 A');
},
child: const Text('Group 1 A'),
),
TapRegion(
groupId: 1,
consumeOutsideTaps: true,
onTapOutside: (PointerEvent event) {
tappedOutside.add('Group 1 B');
},
child: const Text('Group 1 B'),
),
],
),
),
],
),
),
);
await tester.pump();
Future<void> click(Finder finder) async {
final TestGesture gesture = await tester.startGesture(
tester.getCenter(finder),
kind: PointerDeviceKind.mouse,
buttons: kTertiaryButton,
);
await gesture.up();
await gesture.removePointer();
}
expect(tappedOutside, isEmpty);
expect(propagatedTaps, equals(0));
await click(find.text('No Group'));
expect(
tappedOutside,
unorderedEquals(<String>{
'Group 1 A',
'Group 1 B',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Group 1 A'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Group 1 B'));
expect(
tappedOutside,
equals(<String>{
'No Group',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Outside'));
expect(
tappedOutside,
unorderedEquals(<String>{
'No Group',
'Group 1 A',
'Group 1 B',
}));
expect(propagatedTaps, equals(0));
tappedOutside.clear();
await click(find.text('Outside Surface'));
expect(tappedOutside, isEmpty);
});
testWidgetsWithLeakTracking('TapRegionSurface detects inside right click', (WidgetTester tester) async {
final Set<String> tappedInside = <String>{};
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
const Text('Outside Surface'),
TapRegionSurface(
child: Row(
children: <Widget>[
const Text('Outside'),
TapRegion(
onTapInside: (PointerEvent event) {
tappedInside.add('No Group');
},
child: const Text('No Group'),
),
TapRegion(
groupId: 1,
onTapInside: (PointerEvent event) {
tappedInside.add('Group 1 A');
},
child: const Text('Group 1 A'),
),
TapRegion(
groupId: 1,
onTapInside: (PointerEvent event) {
tappedInside.add('Group 1 B');
},
child: const Text('Group 1 B'),
),
],
),
),
],
),
),
);
await tester.pump();
Future<void> click(Finder finder) async {
final TestGesture gesture = await tester.startGesture(
tester.getCenter(finder),
kind: PointerDeviceKind.mouse,
buttons: kSecondaryButton,
);
await gesture.up();
await gesture.removePointer();
}
expect(tappedInside, isEmpty);
await click(find.text('No Group'));
expect(
tappedInside,
unorderedEquals(<String>{
'No Group',
}));
tappedInside.clear();
await click(find.text('Group 1 A'));
expect(
tappedInside,
equals(<String>{
'Group 1 A',
'Group 1 B',
}));
tappedInside.clear();
await click(find.text('Group 1 B'));
expect(
tappedInside,
equals(<String>{
'Group 1 A',
'Group 1 B',
}));
tappedInside.clear();
await click(find.text('Outside'));
expect(tappedInside, isEmpty);
tappedInside.clear();
await click(find.text('Outside Surface'));
expect(tappedInside, isEmpty);
});
testWidgetsWithLeakTracking('TapRegionSurface detects inside middle click', (WidgetTester tester) async {
final Set<String> tappedInside = <String>{};
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Column(
children: <Widget>[
const Text('Outside Surface'),
TapRegionSurface(
child: Row(
children: <Widget>[
const Text('Outside'),
TapRegion(
onTapInside: (PointerEvent event) {
tappedInside.add('No Group');
},
child: const Text('No Group'),
),
TapRegion(
groupId: 1,
onTapInside: (PointerEvent event) {
tappedInside.add('Group 1 A');
},
child: const Text('Group 1 A'),
),
TapRegion(
groupId: 1,
onTapInside: (PointerEvent event) {
tappedInside.add('Group 1 B');
},
child: const Text('Group 1 B'),
),
],
),
),
],
),
),
);
await tester.pump();
Future<void> click(Finder finder) async {
final TestGesture gesture = await tester.startGesture(
tester.getCenter(finder),
kind: PointerDeviceKind.mouse,
buttons: kTertiaryButton,
);
await gesture.up();
await gesture.removePointer();
}
expect(tappedInside, isEmpty);
await click(find.text('No Group'));
expect(
tappedInside,
unorderedEquals(<String>{
'No Group',
}));
tappedInside.clear();
await click(find.text('Group 1 A'));
expect(
tappedInside,
equals(<String>{
'Group 1 A',
'Group 1 B',
}));
tappedInside.clear();
await click(find.text('Group 1 B'));
expect(
tappedInside,
equals(<String>{
'Group 1 A',
'Group 1 B',
}));
tappedInside.clear();
await click(find.text('Outside'));
expect(tappedInside, isEmpty);
tappedInside.clear();
await click(find.text('Outside Surface'));
expect(tappedInside, isEmpty);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment