Skip to content

Commit 36f73cf

Browse files
authored
Disable context menu (#128365)
## Description Changes the context menu example for `MenuAnchor` so that it uses right-click, or (on macOS and iOS only) ctrl-left-click, for the context menu. Also disables the browser context menu on web platforms. ## Tests - Updated test to reflect new triggers.
1 parent 5328bd9 commit 36f73cf

File tree

2 files changed

+56
-11
lines changed

2 files changed

+56
-11
lines changed

examples/api/lib/material/menu_anchor/menu_anchor.1.dart

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:flutter/foundation.dart';
56
import 'package:flutter/material.dart';
67
import 'package:flutter/services.dart';
78

@@ -41,6 +42,7 @@ class _MyContextMenuState extends State<MyContextMenu> {
4142
final FocusNode _buttonFocusNode = FocusNode(debugLabel: 'Menu Button');
4243
final MenuController _menuController = MenuController();
4344
ShortcutRegistryEntry? _shortcutsEntry;
45+
bool _menuWasEnabled = false;
4446

4547
Color get backgroundColor => _backgroundColor;
4648
Color _backgroundColor = Colors.red;
@@ -62,6 +64,12 @@ class _MyContextMenuState extends State<MyContextMenu> {
6264
}
6365
}
6466

67+
@override
68+
void initState() {
69+
super.initState();
70+
_disableContextMenu();
71+
}
72+
6573
@override
6674
void didChangeDependencies() {
6775
super.didChangeDependencies();
@@ -84,15 +92,38 @@ class _MyContextMenuState extends State<MyContextMenu> {
8492
void dispose() {
8593
_shortcutsEntry?.dispose();
8694
_buttonFocusNode.dispose();
95+
_reenableContextMenu();
8796
super.dispose();
8897
}
8998

99+
Future<void> _disableContextMenu() async {
100+
if (!kIsWeb) {
101+
// Does nothing on non-web platforms.
102+
return;
103+
}
104+
_menuWasEnabled = BrowserContextMenu.enabled;
105+
if (_menuWasEnabled) {
106+
await BrowserContextMenu.disableContextMenu();
107+
}
108+
}
109+
110+
void _reenableContextMenu() {
111+
if (!kIsWeb) {
112+
// Does nothing on non-web platforms.
113+
return;
114+
}
115+
if (_menuWasEnabled && !BrowserContextMenu.enabled) {
116+
BrowserContextMenu.enableContextMenu();
117+
}
118+
}
119+
90120
@override
91121
Widget build(BuildContext context) {
92122
return Padding(
93123
padding: const EdgeInsets.all(50),
94124
child: GestureDetector(
95125
onTapDown: _handleTapDown,
126+
onSecondaryTapDown: _handleSecondaryTapDown,
96127
child: MenuAnchor(
97128
controller: _menuController,
98129
anchorTapClosesMenu: true,
@@ -142,7 +173,7 @@ class _MyContextMenuState extends State<MyContextMenu> {
142173
children: <Widget>[
143174
const Padding(
144175
padding: EdgeInsets.all(8.0),
145-
child: Text('Ctrl-click anywhere on the background to show the menu.'),
176+
child: Text('Right-click anywhere on the background to show the menu.'),
146177
),
147178
Padding(
148179
padding: const EdgeInsets.all(12.0),
@@ -185,12 +216,28 @@ class _MyContextMenuState extends State<MyContextMenu> {
185216
}
186217
}
187218

219+
void _handleSecondaryTapDown(TapDownDetails details) {
220+
_menuController.open(position: details.localPosition);
221+
}
222+
188223
void _handleTapDown(TapDownDetails details) {
189-
if (!HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlLeft) &&
190-
!HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlRight)) {
191-
return;
224+
switch (defaultTargetPlatform) {
225+
case TargetPlatform.android:
226+
case TargetPlatform.fuchsia:
227+
case TargetPlatform.linux:
228+
case TargetPlatform.windows:
229+
// Don't open the menu on these platforms with a Ctrl-tap (or a
230+
// tap).
231+
break;
232+
case TargetPlatform.iOS:
233+
case TargetPlatform.macOS:
234+
// Only open the menu on these platforms if the control button is down
235+
// when the tap occurs.
236+
if (HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlLeft) ||
237+
HardwareKeyboard.instance.logicalKeysPressed.contains(LogicalKeyboardKey.controlRight)) {
238+
_menuController.open(position: details.localPosition);
239+
}
192240
}
193-
_menuController.open(position: details.localPosition);
194241
}
195242
}
196243

examples/api/test/material/menu_anchor/menu_anchor.1_test.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:flutter/gestures.dart';
56
import 'package:flutter/material.dart';
67
import 'package:flutter/services.dart';
78
import 'package:flutter_api_samples/material/menu_anchor/menu_anchor.1.dart' as example;
@@ -18,15 +19,13 @@ void main() {
1819

1920
await tester.pumpWidget(const example.ContextMenuApp());
2021

21-
await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight);
22-
await tester.tapAt(const Offset(100, 200));
22+
await tester.tapAt(const Offset(100, 200), buttons: kSecondaryButton);
2323
await tester.pump();
2424
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 433.0, 360.0)));
2525

2626
// Make sure tapping in a different place causes the menu to move.
27-
await tester.tapAt(const Offset(200, 100));
27+
await tester.tapAt(const Offset(200, 100), buttons: kSecondaryButton);
2828
await tester.pump();
29-
await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight);
3029

3130
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(200.0, 100.0, 533.0, 260.0)));
3231

@@ -67,8 +66,7 @@ void main() {
6766
);
6867

6968
// Open the menu so we can look for state changes reflected in the menu.
70-
await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight);
71-
await tester.tapAt(const Offset(100, 200));
69+
await tester.tapAt(const Offset(100, 200), buttons: kSecondaryButton);
7270
await tester.pump();
7371

7472
expect(find.text(example.MenuEntry.showMessage.label), findsOneWidget);

0 commit comments

Comments
 (0)