1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 13:58:47 +00:00

Dart 3.9 / Flutter 3.35 [first LLM release] (#2714)

I got carried away with Gemini and basically rewrote CI and the release
process for the new LLM reality. This work was largely completed by
Gemini.

- Bump all SDK versions to the current beta (3.9.0-0)
- Run `flutter channel beta`
- Wrote `ci_script.dart` to replace the bash scripts
- Converted repository to pub workspace #2499 
- Added llm.md and release.md
- Added redirect for deprecated Samples Index

## Pre-launch Checklist

- [x] I read the [Flutter Style Guide] _recently_, and have followed its
advice.
- [x] I signed the [CLA].
- [x] I read the [Contributors Guide].
- [x] I have added sample code updates to the [changelog].
- [x] I updated/added relevant documentation (doc comments with `///`).
This commit is contained in:
Eric Windmill
2025-08-14 12:26:24 -07:00
committed by GitHub
parent 0aa5415d5e
commit 2999d738b8
410 changed files with 28166 additions and 27661 deletions

View File

@@ -228,20 +228,22 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
);
widget.onToggleMessageVisibility();
},
shortcut: const SingleActivator(LogicalKeyboardKey.keyS, control: true),
shortcut: const SingleActivator(
LogicalKeyboardKey.keyS,
control: true,
),
),
// Hides the message, but is only enabled if the message isn't
// already hidden.
MenuEntry(
label: 'Reset',
onPressed:
widget.showingMessage
? () {
ContextMenuController.removeAny();
widget.onChangeSelection('Reset');
widget.onToggleMessageVisibility();
}
: null,
onPressed: widget.showingMessage
? () {
ContextMenuController.removeAny();
widget.onChangeSelection('Reset');
widget.onToggleMessageVisibility();
}
: null,
shortcut: const SingleActivator(LogicalKeyboardKey.escape),
),
MenuEntry(

View File

@@ -52,26 +52,27 @@ class CustomButtonsPage extends StatelessWidget {
// Build the default buttons, but make them look custom.
// Note that in a real project you may want to build
// different buttons depending on the platform.
children:
editableTextState.contextMenuButtonItems.map((buttonItem) {
return CupertinoButton(
borderRadius: null,
color: const Color(0xffaaaa00),
disabledColor: const Color(0xffaaaaff),
onPressed: buttonItem.onPressed,
padding: const EdgeInsets.all(10.0),
pressedOpacity: 0.7,
child: SizedBox(
width: 200.0,
child: Text(
CupertinoTextSelectionToolbarButton.getButtonLabel(
context,
buttonItem,
),
),
children: editableTextState.contextMenuButtonItems.map((
buttonItem,
) {
return CupertinoButton(
borderRadius: null,
color: const Color(0xffaaaa00),
disabledColor: const Color(0xffaaaaff),
onPressed: buttonItem.onPressed,
padding: const EdgeInsets.all(10.0),
pressedOpacity: 0.7,
child: SizedBox(
width: 200.0,
child: Text(
CupertinoTextSelectionToolbarButton.getButtonLabel(
context,
buttonItem,
),
);
}).toList(),
),
),
);
}).toList(),
);
},
),

View File

@@ -47,11 +47,10 @@ class CustomMenuPage extends StatelessWidget {
contextMenuBuilder: (context, editableTextState) {
return _MyContextMenu(
anchor: editableTextState.contextMenuAnchors.primaryAnchor,
children:
AdaptiveTextSelectionToolbar.getAdaptiveButtons(
context,
editableTextState.contextMenuButtonItems,
).toList(),
children: AdaptiveTextSelectionToolbar.getAdaptiveButtons(
context,
editableTextState.contextMenuButtonItems,
).toList(),
);
},
),

View File

@@ -62,7 +62,11 @@ class DefaultValuesPage extends StatelessWidget {
'This example simply shows what happens when contextMenuBuilder is given null, a custom value, or omitted altogether.',
),
const SizedBox(height: 40.0),
TextField(maxLines: 2, minLines: 2, controller: _controllerNone),
TextField(
maxLines: 2,
minLines: 2,
controller: _controllerNone,
),
TextField(
maxLines: 2,
minLines: 2,

View File

@@ -22,9 +22,8 @@ class EmailButtonPage extends StatelessWidget {
DialogRoute _showDialog(BuildContext context) {
return DialogRoute<void>(
context: context,
builder:
(context) =>
const AlertDialog(title: Text('You clicked send email!')),
builder: (context) =>
const AlertDialog(title: Text('You clicked send email!')),
);
}
@@ -64,7 +63,9 @@ class EmailButtonPage extends StatelessWidget {
editableTextState.textEditingValue;
final List<ContextMenuButtonItem> buttonItems =
editableTextState.contextMenuButtonItems;
if (isValidEmail(value.selection.textInside(value.text))) {
if (isValidEmail(
value.selection.textInside(value.text),
)) {
buttonItems.insert(
0,
ContextMenuButtonItem(

View File

@@ -26,16 +26,16 @@ class FieldTypesPage extends StatelessWidget {
"CupertinoTextField can't show Material menus by default. On non-Apple platforms, you'll still see a Cupertino menu here.",
);
final TextEditingController _cupertinoControllerFixed = TextEditingController(
final TextEditingController
_cupertinoControllerFixed = TextEditingController(
text:
"But CupertinoTextField can be made to adaptively show any menu. You'll see the correct menu for your platform here.",
);
final TextEditingController _cupertinoControllerForced =
TextEditingController(
text:
'Or forced to always show a specific menu (Material desktop menu).',
);
final TextEditingController
_cupertinoControllerForced = TextEditingController(
text: 'Or forced to always show a specific menu (Material desktop menu).',
);
final TextEditingController _editableController = TextEditingController(
text:
@@ -67,7 +67,10 @@ class FieldTypesPage extends StatelessWidget {
const SizedBox(height: 20.0),
TextField(maxLines: 3, controller: _controller),
const SizedBox(height: 60.0),
CupertinoTextField(maxLines: 3, controller: _cupertinoController),
CupertinoTextField(
maxLines: 3,
controller: _cupertinoController,
),
const SizedBox(height: 20.0),
CupertinoTextField(
maxLines: 3,
@@ -85,11 +88,10 @@ class FieldTypesPage extends StatelessWidget {
contextMenuBuilder: (context, editableTextState) {
return DesktopTextSelectionToolbar(
anchor: editableTextState.contextMenuAnchors.primaryAnchor,
children:
AdaptiveTextSelectionToolbar.getAdaptiveButtons(
context,
editableTextState.contextMenuButtonItems,
).toList(),
children: AdaptiveTextSelectionToolbar.getAdaptiveButtons(
context,
editableTextState.contextMenuButtonItems,
).toList(),
);
},
),

View File

@@ -107,7 +107,9 @@ class FullPage extends StatelessWidget {
editableTextState.textEditingValue;
final List<ContextMenuButtonItem> buttonItems =
editableTextState.contextMenuButtonItems;
if (isValidEmail(value.selection.textInside(value.text))) {
if (isValidEmail(
value.selection.textInside(value.text),
)) {
buttonItems.insert(
0,
ContextMenuButtonItem(
@@ -115,7 +117,10 @@ class FullPage extends StatelessWidget {
onPressed: () {
ContextMenuController.removeAny();
Navigator.of(context).push(
_showDialog(context, 'You clicked send email'),
_showDialog(
context,
'You clicked send email',
),
);
},
),
@@ -126,26 +131,25 @@ class FullPage extends StatelessWidget {
// Build the default buttons, but make them look crazy.
// Note that in a real project you may want to build
// different buttons depending on the platform.
children:
buttonItems.map((buttonItem) {
return CupertinoButton(
borderRadius: null,
color: const Color(0xffaaaa00),
disabledColor: const Color(0xffaaaaff),
onPressed: buttonItem.onPressed,
padding: const EdgeInsets.all(10.0),
pressedOpacity: 0.7,
child: SizedBox(
width: 200.0,
child: Text(
CupertinoTextSelectionToolbarButton.getButtonLabel(
context,
buttonItem,
),
),
children: buttonItems.map((buttonItem) {
return CupertinoButton(
borderRadius: null,
color: const Color(0xffaaaa00),
disabledColor: const Color(0xffaaaaff),
onPressed: buttonItem.onPressed,
padding: const EdgeInsets.all(10.0),
pressedOpacity: 0.7,
child: SizedBox(
width: 200.0,
child: Text(
CupertinoTextSelectionToolbarButton.getButtonLabel(
context,
buttonItem,
),
);
}).toList(),
),
),
);
}).toList(),
);
},
),

View File

@@ -9,7 +9,8 @@ class GlobalSelectionPage extends StatelessWidget {
static const String route = 'global-selection';
static const String title = 'Global Selection Example';
static const String subtitle = 'Context menus in and out of global selection';
static const String subtitle =
'Context menus in and out of global selection';
static const String url = '$kCodeUrl/global_selection_page.dart';
final PlatformCallback onChangedPlatform;

View File

@@ -19,10 +19,9 @@ class ImagePage extends StatelessWidget {
DialogRoute _showDialog(BuildContext context) {
return DialogRoute<void>(
context: context,
builder:
(context) => const AlertDialog(
title: Text('Image saved! (not really though)'),
),
builder: (context) => const AlertDialog(
title: Text('Image saved! (not really though)'),
),
);
}
@@ -49,7 +48,9 @@ class ImagePage extends StatelessWidget {
ContextMenuRegion(
contextMenuBuilder: (context, offset) {
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: TextSelectionToolbarAnchors(primaryAnchor: offset),
anchors: TextSelectionToolbarAnchors(
primaryAnchor: offset,
),
buttonItems: <ContextMenuButtonItem>[
ContextMenuButtonItem(
onPressed: () {

View File

@@ -64,36 +64,30 @@ class _MyAppState extends State<MyApp> {
initialRoute: '/',
routes: <String, Widget Function(BuildContext)>{
'/': (context) => MyHomePage(onChangedPlatform: onChangedPlatform),
AnywherePage.route:
(context) => AnywherePage(onChangedPlatform: onChangedPlatform),
CustomButtonsPage.route:
(context) =>
CustomButtonsPage(onChangedPlatform: onChangedPlatform),
CustomMenuPage.route:
(context) => CustomMenuPage(onChangedPlatform: onChangedPlatform),
ReorderedButtonsPage.route:
(context) =>
ReorderedButtonsPage(onChangedPlatform: onChangedPlatform),
EmailButtonPage.route:
(context) => EmailButtonPage(onChangedPlatform: onChangedPlatform),
ImagePage.route:
(context) => ImagePage(onChangedPlatform: onChangedPlatform),
FieldTypesPage.route:
(context) => FieldTypesPage(onChangedPlatform: onChangedPlatform),
FullPage.route:
(context) => FullPage(onChangedPlatform: onChangedPlatform),
ModifiedActionPage.route:
(context) =>
ModifiedActionPage(onChangedPlatform: onChangedPlatform),
GlobalSelectionPage.route:
(context) =>
GlobalSelectionPage(onChangedPlatform: onChangedPlatform),
DefaultValuesPage.route:
(context) =>
DefaultValuesPage(onChangedPlatform: onChangedPlatform),
CascadingMenuPage.route:
(context) =>
CascadingMenuPage(onChangedPlatform: onChangedPlatform),
AnywherePage.route: (context) =>
AnywherePage(onChangedPlatform: onChangedPlatform),
CustomButtonsPage.route: (context) =>
CustomButtonsPage(onChangedPlatform: onChangedPlatform),
CustomMenuPage.route: (context) =>
CustomMenuPage(onChangedPlatform: onChangedPlatform),
ReorderedButtonsPage.route: (context) =>
ReorderedButtonsPage(onChangedPlatform: onChangedPlatform),
EmailButtonPage.route: (context) =>
EmailButtonPage(onChangedPlatform: onChangedPlatform),
ImagePage.route: (context) =>
ImagePage(onChangedPlatform: onChangedPlatform),
FieldTypesPage.route: (context) =>
FieldTypesPage(onChangedPlatform: onChangedPlatform),
FullPage.route: (context) =>
FullPage(onChangedPlatform: onChangedPlatform),
ModifiedActionPage.route: (context) =>
ModifiedActionPage(onChangedPlatform: onChangedPlatform),
GlobalSelectionPage.route: (context) =>
GlobalSelectionPage(onChangedPlatform: onChangedPlatform),
DefaultValuesPage.route: (context) =>
DefaultValuesPage(onChangedPlatform: onChangedPlatform),
CascadingMenuPage.route: (context) =>
CascadingMenuPage(onChangedPlatform: onChangedPlatform),
},
);
}

View File

@@ -22,10 +22,9 @@ class ModifiedActionPage extends StatelessWidget {
DialogRoute _showDialog(BuildContext context) {
return DialogRoute<void>(
context: context,
builder:
(context) => const AlertDialog(
title: Text('Copied, but also showed this dialog.'),
),
builder: (context) => const AlertDialog(
title: Text('Copied, but also showed this dialog.'),
),
);
}

View File

@@ -37,19 +37,18 @@ class _PlatformSelectorState extends State<PlatformSelector> {
widget.onChangedPlatform(value);
setState(() {});
},
items:
TargetPlatform.values.map((platform) {
return DropdownMenuItem<TargetPlatform>(
value: platform,
child: Row(
children: <Widget>[
if (platform == originaPlatform)
const Icon(Icons.home, color: Color(0xff616161)),
Text(_platformToString(platform)),
],
),
);
}).toList(),
items: TargetPlatform.values.map((platform) {
return DropdownMenuItem<TargetPlatform>(
value: platform,
child: Row(
children: <Widget>[
if (platform == originaPlatform)
const Icon(Icons.home, color: Color(0xff616161)),
Text(_platformToString(platform)),
],
),
);
}).toList(),
),
);
}

View File

@@ -11,7 +11,8 @@ class ReorderedButtonsPage extends StatelessWidget {
static const String route = 'reordered-buttons';
static const String title = 'Reordered Buttons';
static const String subtitle = 'The usual buttons, but in a different order.';
static const String subtitle =
'The usual buttons, but in a different order.';
static const String url = '$kCodeUrl/reordered_buttons_page.dart';
final PlatformCallback onChangedPlatform;
@@ -61,19 +62,25 @@ class ReorderedButtonsPage extends StatelessWidget {
in editableTextState.contextMenuButtonItems) {
buttonItemsMap[buttonItem.type] = buttonItem;
}
final List<ContextMenuButtonItem>
reorderedButtonItems = <ContextMenuButtonItem>[
if (buttonItemsMap.containsKey(
ContextMenuButtonType.selectAll,
))
buttonItemsMap[ContextMenuButtonType.selectAll]!,
if (buttonItemsMap.containsKey(ContextMenuButtonType.paste))
buttonItemsMap[ContextMenuButtonType.paste]!,
if (buttonItemsMap.containsKey(ContextMenuButtonType.copy))
buttonItemsMap[ContextMenuButtonType.copy]!,
if (buttonItemsMap.containsKey(ContextMenuButtonType.cut))
buttonItemsMap[ContextMenuButtonType.cut]!,
];
final List<ContextMenuButtonItem> reorderedButtonItems =
<ContextMenuButtonItem>[
if (buttonItemsMap.containsKey(
ContextMenuButtonType.selectAll,
))
buttonItemsMap[ContextMenuButtonType.selectAll]!,
if (buttonItemsMap.containsKey(
ContextMenuButtonType.paste,
))
buttonItemsMap[ContextMenuButtonType.paste]!,
if (buttonItemsMap.containsKey(
ContextMenuButtonType.copy,
))
buttonItemsMap[ContextMenuButtonType.copy]!,
if (buttonItemsMap.containsKey(
ContextMenuButtonType.cut,
))
buttonItemsMap[ContextMenuButtonType.cut]!,
];
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: editableTextState.contextMenuAnchors,
buttonItems: reorderedButtonItems,

View File

@@ -1,5 +1,7 @@
name: context_menus
description: A new Flutter project.
version: 1.0.0+1
resolution: workspace
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
@@ -17,10 +19,10 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.7.0-0
sdk: ^3.9.0-0
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
@@ -32,7 +34,6 @@ dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
@@ -44,7 +45,6 @@ dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

View File

@@ -37,7 +37,10 @@ void main() {
expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNothing);
expect(
find.byType(CupertinoTextSelectionToolbarButton),
findsNothing,
);
expect(find.byType(CupertinoButton), findsNWidgets(2));
case TargetPlatform.macOS:
expect(find.byType(CupertinoButton), findsNWidgets(2));
@@ -52,7 +55,10 @@ void main() {
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.byType(CupertinoButton), findsNWidgets(1));
expect(find.byType(DesktopTextSelectionToolbarButton), findsNothing);
expect(
find.byType(DesktopTextSelectionToolbarButton),
findsNothing,
);
}
});
}

View File

@@ -7,7 +7,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Shows default buttons in a custom context menu', (tester) async {
testWidgets('Shows default buttons in a custom context menu', (
tester,
) async {
await tester.pumpWidget(const MyApp());
// Navigate to the CustomMenuPage example.
@@ -33,7 +35,10 @@ void main() {
// A custom context menu is shown, and the buttons are the default ones.
expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing);
expect(
find.byType(CupertinoAdaptiveTextSelectionToolbar),
findsNothing,
);
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
expect(
@@ -47,7 +52,10 @@ void main() {
);
case TargetPlatform.android:
case TargetPlatform.fuchsia:
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(1));
expect(
find.byType(TextSelectionToolbarTextButton),
findsNWidgets(1),
);
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(

View File

@@ -55,7 +55,10 @@ void main() {
);
case TargetPlatform.android:
case TargetPlatform.fuchsia:
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(1));
expect(
find.byType(TextSelectionToolbarTextButton),
findsNWidgets(1),
);
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(

View File

@@ -61,7 +61,10 @@ void main() {
);
case TargetPlatform.android:
case TargetPlatform.fuchsia:
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(3));
expect(
find.byType(TextSelectionToolbarTextButton),
findsNWidgets(3),
);
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(
@@ -111,7 +114,10 @@ void main() {
);
case TargetPlatform.android:
case TargetPlatform.fuchsia:
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(4));
expect(
find.byType(TextSelectionToolbarTextButton),
findsNWidgets(4),
);
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(

View File

@@ -44,7 +44,10 @@ void main() {
expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget);
expect(
find.byType(CupertinoTextSelectionToolbar),
findsOneWidget,
);
case TargetPlatform.android:
expect(find.byType(TextSelectionToolbar), findsOneWidget);
case TargetPlatform.fuchsia:
@@ -83,7 +86,10 @@ void main() {
case TargetPlatform.iOS:
case TargetPlatform.android:
case TargetPlatform.fuchsia:
expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget);
expect(
find.byType(CupertinoTextSelectionToolbar),
findsOneWidget,
);
case TargetPlatform.macOS:
case TargetPlatform.linux:
case TargetPlatform.windows:
@@ -96,7 +102,10 @@ void main() {
// Tap the next field to hide the context menu.
await tester.tap(find.byType(CupertinoTextField).at(1));
await tester.pumpAndSettle();
expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing);
expect(
find.byType(CupertinoAdaptiveTextSelectionToolbar),
findsNothing,
);
// Right click on the fixed CupertinoTextField.
gesture = await tester.startGesture(
@@ -113,7 +122,10 @@ void main() {
expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget);
expect(
find.byType(CupertinoTextSelectionToolbar),
findsOneWidget,
);
case TargetPlatform.android:
expect(find.byType(TextSelectionToolbar), findsOneWidget);
case TargetPlatform.fuchsia:
@@ -145,7 +157,10 @@ void main() {
// The DesktopTextSelectionToolbar is shown for all platforms.
expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing);
expect(
find.byType(CupertinoAdaptiveTextSelectionToolbar),
findsNothing,
);
expect(find.byType(DesktopTextSelectionToolbar), findsOneWidget);
// Tap the next field to hide the context menu.
@@ -168,7 +183,10 @@ void main() {
expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
switch (defaultTargetPlatform) {
case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbar), findsOneWidget);
expect(
find.byType(CupertinoTextSelectionToolbar),
findsOneWidget,
);
case TargetPlatform.android:
expect(find.byType(TextSelectionToolbar), findsOneWidget);
case TargetPlatform.fuchsia:

View File

@@ -5,43 +5,49 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Gives correct behavior for all values of contextMenuBuilder', (
tester,
) async {
await tester.pumpWidget(const MyApp());
testWidgets(
'Gives correct behavior for all values of contextMenuBuilder',
(
tester,
) async {
await tester.pumpWidget(const MyApp());
// Navigate to the GlobalSelectionPage example.
await tester.dragUntilVisible(
find.text(GlobalSelectionPage.title),
find.byType(ListView),
const Offset(0.0, -100.0),
);
await tester.pumpAndSettle();
await tester.tap(find.text(GlobalSelectionPage.title));
await tester.pumpAndSettle();
expect(
find.descendant(
of: find.byType(AppBar),
matching: find.text(GlobalSelectionPage.title),
),
findsOneWidget,
);
// Navigate to the GlobalSelectionPage example.
await tester.dragUntilVisible(
find.text(GlobalSelectionPage.title),
find.byType(ListView),
const Offset(0.0, -100.0),
);
await tester.pumpAndSettle();
await tester.tap(find.text(GlobalSelectionPage.title));
await tester.pumpAndSettle();
expect(
find.descendant(
of: find.byType(AppBar),
matching: find.text(GlobalSelectionPage.title),
),
findsOneWidget,
);
// Right click on the plain Text widget.
TestGesture gesture = await tester.startGesture(
tester.getCenter(
find.descendant(of: find.byType(ListView), matching: find.byType(Text)),
),
kind: PointerDeviceKind.mouse,
buttons: kSecondaryMouseButton,
);
await tester.pump();
await gesture.up();
await gesture.removePointer();
await tester.pumpAndSettle();
// Right click on the plain Text widget.
TestGesture gesture = await tester.startGesture(
tester.getCenter(
find.descendant(
of: find.byType(ListView),
matching: find.byType(Text),
),
),
kind: PointerDeviceKind.mouse,
buttons: kSecondaryMouseButton,
);
await tester.pump();
await gesture.up();
await gesture.removePointer();
await tester.pumpAndSettle();
// The default context menu is shown with a custom button.
expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
expect(find.text('Back'), findsOneWidget);
});
// The default context menu is shown with a custom button.
expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget);
expect(find.text('Back'), findsOneWidget);
},
);
}

View File

@@ -40,6 +40,9 @@ List<TextSelectionPoint> globalize(
RenderBox box,
) {
return points.map<TextSelectionPoint>((point) {
return TextSelectionPoint(box.localToGlobal(point.point), point.direction);
return TextSelectionPoint(
box.localToGlobal(point.point),
point.direction,
);
}).toList();
}