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,