mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Flutter 3.29 beta (#2571)
This commit is contained in:
@@ -7,10 +7,7 @@ import 'context_menu_region.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class AnywherePage extends StatelessWidget {
|
||||
AnywherePage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
AnywherePage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'anywhere';
|
||||
static const String title = 'Context Menu Anywhere Example';
|
||||
@@ -36,9 +33,7 @@ class AnywherePage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(AnywherePage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
|
||||
@@ -10,10 +10,7 @@ import 'platform_selector.dart';
|
||||
// https://master-api.flutter.dev/flutter/material/MenuBar-class.html
|
||||
|
||||
class CascadingMenuPage extends StatelessWidget {
|
||||
const CascadingMenuPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
const CascadingMenuPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'cascading';
|
||||
static const String title = 'Cascading Menu Example';
|
||||
@@ -29,9 +26,7 @@ class CascadingMenuPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(CascadingMenuPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -117,7 +112,8 @@ class _MyContextMenuRegionState extends State<_MyContextMenuRegion> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_lastSelection != null ? 'Last Selected: $_lastSelection' : ''),
|
||||
_lastSelection != null ? 'Last Selected: $_lastSelection' : '',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -130,10 +126,15 @@ class _MyContextMenuRegionState extends State<_MyContextMenuRegion> {
|
||||
/// This sort of class is not required, but illustrates one way that defining
|
||||
/// menus could be done.
|
||||
class MenuEntry {
|
||||
const MenuEntry(
|
||||
{required this.label, this.shortcut, this.onPressed, this.menuChildren})
|
||||
: assert(menuChildren == null || onPressed == null,
|
||||
'onPressed is ignored if menuChildren are provided');
|
||||
const MenuEntry({
|
||||
required this.label,
|
||||
this.shortcut,
|
||||
this.onPressed,
|
||||
this.menuChildren,
|
||||
}) : assert(
|
||||
menuChildren == null || onPressed == null,
|
||||
'onPressed is ignored if menuChildren are provided',
|
||||
);
|
||||
final String label;
|
||||
|
||||
final MenuSerializableShortcut? shortcut;
|
||||
@@ -159,7 +160,8 @@ class MenuEntry {
|
||||
}
|
||||
|
||||
static Map<MenuSerializableShortcut, Intent> shortcuts(
|
||||
List<MenuEntry> selections) {
|
||||
List<MenuEntry> selections,
|
||||
) {
|
||||
final Map<MenuSerializableShortcut, Intent> result =
|
||||
<MenuSerializableShortcut, Intent>{};
|
||||
for (final MenuEntry selection in selections) {
|
||||
@@ -167,8 +169,9 @@ class MenuEntry {
|
||||
result.addAll(MenuEntry.shortcuts(selection.menuChildren!));
|
||||
} else {
|
||||
if (selection.shortcut != null && selection.onPressed != null) {
|
||||
result[selection.shortcut!] =
|
||||
VoidCallbackIntent(selection.onPressed!);
|
||||
result[selection.shortcut!] = VoidCallbackIntent(
|
||||
selection.onPressed!,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,7 +224,8 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
widget.onChangeSelection(
|
||||
widget.showingMessage ? 'Hide Message' : 'Show Message');
|
||||
widget.showingMessage ? 'Hide Message' : 'Show Message',
|
||||
);
|
||||
widget.onToggleMessageVisibility();
|
||||
},
|
||||
shortcut: const SingleActivator(LogicalKeyboardKey.keyS, control: true),
|
||||
@@ -230,13 +234,14 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
|
||||
// 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(
|
||||
@@ -249,8 +254,10 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
|
||||
widget.onChangeSelection('Red Background');
|
||||
widget.onChangeBackgroundColor(Colors.red);
|
||||
},
|
||||
shortcut:
|
||||
const SingleActivator(LogicalKeyboardKey.keyR, control: true),
|
||||
shortcut: const SingleActivator(
|
||||
LogicalKeyboardKey.keyR,
|
||||
control: true,
|
||||
),
|
||||
),
|
||||
MenuEntry(
|
||||
label: 'Green',
|
||||
@@ -259,8 +266,10 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
|
||||
widget.onChangeSelection('Green Background');
|
||||
widget.onChangeBackgroundColor(Colors.green);
|
||||
},
|
||||
shortcut:
|
||||
const SingleActivator(LogicalKeyboardKey.keyG, control: true),
|
||||
shortcut: const SingleActivator(
|
||||
LogicalKeyboardKey.keyG,
|
||||
control: true,
|
||||
),
|
||||
),
|
||||
MenuEntry(
|
||||
label: 'Blue',
|
||||
@@ -269,8 +278,10 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
|
||||
widget.onChangeSelection('Blue Background');
|
||||
widget.onChangeBackgroundColor(Colors.blue);
|
||||
},
|
||||
shortcut:
|
||||
const SingleActivator(LogicalKeyboardKey.keyB, control: true),
|
||||
shortcut: const SingleActivator(
|
||||
LogicalKeyboardKey.keyB,
|
||||
control: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -278,8 +289,9 @@ class _MyCascadingContextMenuState extends State<_MyCascadingContextMenu> {
|
||||
// (Re-)register the shortcuts with the ShortcutRegistry so that they are
|
||||
// available to the entire application, and update them if they've changed.
|
||||
_shortcutsEntry?.dispose();
|
||||
_shortcutsEntry =
|
||||
ShortcutRegistry.of(context).addAll(MenuEntry.shortcuts(result));
|
||||
_shortcutsEntry = ShortcutRegistry.of(
|
||||
context,
|
||||
).addAll(MenuEntry.shortcuts(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef ContextMenuBuilder = Widget Function(
|
||||
BuildContext context, Offset offset);
|
||||
typedef ContextMenuBuilder =
|
||||
Widget Function(BuildContext context, Offset offset);
|
||||
|
||||
/// Shows and hides the context menu based on user gestures.
|
||||
///
|
||||
|
||||
@@ -6,10 +6,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class CustomButtonsPage extends StatelessWidget {
|
||||
CustomButtonsPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
CustomButtonsPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'custom-buttons';
|
||||
static const String title = 'Custom Buttons';
|
||||
@@ -31,9 +28,7 @@ class CustomButtonsPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(CustomButtonsPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -59,22 +54,24 @@ class CustomButtonsPage extends StatelessWidget {
|
||||
// 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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
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(),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -5,10 +5,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class CustomMenuPage extends StatelessWidget {
|
||||
CustomMenuPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
CustomMenuPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'custom-menu';
|
||||
static const String title = 'Custom Menu';
|
||||
@@ -29,9 +26,7 @@ class CustomMenuPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(CustomMenuPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -52,10 +47,11 @@ 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(),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -66,10 +62,7 @@ class CustomMenuPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _MyContextMenu extends StatelessWidget {
|
||||
const _MyContextMenu({
|
||||
required this.anchor,
|
||||
required this.children,
|
||||
});
|
||||
const _MyContextMenu({required this.anchor, required this.children});
|
||||
|
||||
final Offset anchor;
|
||||
final List<Widget> children;
|
||||
@@ -85,9 +78,7 @@ class _MyContextMenu extends StatelessWidget {
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
color: Colors.amberAccent,
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
child: Column(children: children),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -5,10 +5,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class DefaultValuesPage extends StatelessWidget {
|
||||
DefaultValuesPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
DefaultValuesPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'default-values';
|
||||
static const String title = 'Default API Values Example';
|
||||
@@ -44,9 +41,7 @@ class DefaultValuesPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(DefaultValuesPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -66,14 +61,8 @@ class DefaultValuesPage extends StatelessWidget {
|
||||
const Text(
|
||||
'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,
|
||||
),
|
||||
const SizedBox(height: 40.0),
|
||||
TextField(maxLines: 2, minLines: 2, controller: _controllerNone),
|
||||
TextField(
|
||||
maxLines: 2,
|
||||
minLines: 2,
|
||||
@@ -92,8 +81,12 @@ class DefaultValuesPage extends StatelessWidget {
|
||||
label: 'Custom button',
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
Navigator.of(context).push(_showDialog(
|
||||
context, 'You clicked the custom button.'));
|
||||
Navigator.of(context).push(
|
||||
_showDialog(
|
||||
context,
|
||||
'You clicked the custom button.',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
...editableTextState.contextMenuButtonItems,
|
||||
|
||||
@@ -6,10 +6,7 @@ import 'is_valid_email.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class EmailButtonPage extends StatelessWidget {
|
||||
EmailButtonPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
EmailButtonPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'email-button';
|
||||
static const String title = 'Email Button';
|
||||
@@ -25,8 +22,9 @@ 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!')),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,9 +34,7 @@ class EmailButtonPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(EmailButtonPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -70,14 +66,15 @@ class EmailButtonPage extends StatelessWidget {
|
||||
editableTextState.contextMenuButtonItems;
|
||||
if (isValidEmail(value.selection.textInside(value.text))) {
|
||||
buttonItems.insert(
|
||||
0,
|
||||
ContextMenuButtonItem(
|
||||
label: 'Send email',
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
Navigator.of(context).push(_showDialog(context));
|
||||
},
|
||||
));
|
||||
0,
|
||||
ContextMenuButtonItem(
|
||||
label: 'Send email',
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
Navigator.of(context).push(_showDialog(context));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: editableTextState.contextMenuAnchors,
|
||||
|
||||
@@ -6,10 +6,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class FieldTypesPage extends StatelessWidget {
|
||||
FieldTypesPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
FieldTypesPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'field-types';
|
||||
static const String title = 'The Context Menu in Different Field Types';
|
||||
@@ -36,8 +33,9 @@ class FieldTypesPage extends StatelessWidget {
|
||||
|
||||
final TextEditingController _cupertinoControllerForced =
|
||||
TextEditingController(
|
||||
text: 'Or forced to always show a specific menu (Material desktop menu).',
|
||||
);
|
||||
text:
|
||||
'Or forced to always show a specific menu (Material desktop menu).',
|
||||
);
|
||||
|
||||
final TextEditingController _editableController = TextEditingController(
|
||||
text:
|
||||
@@ -50,9 +48,7 @@ class FieldTypesPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(FieldTypesPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -69,15 +65,9 @@ class FieldTypesPage extends StatelessWidget {
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 20.0),
|
||||
TextField(
|
||||
maxLines: 3,
|
||||
controller: _controller,
|
||||
),
|
||||
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,
|
||||
@@ -95,10 +85,11 @@ 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(),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -8,10 +8,7 @@ import 'is_valid_email.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class FullPage extends StatelessWidget {
|
||||
FullPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
FullPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'full';
|
||||
static const String title = 'Combined Example';
|
||||
@@ -38,9 +35,7 @@ class FullPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(FullPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -54,9 +49,7 @@ class FullPage extends StatelessWidget {
|
||||
body: ContextMenuRegion(
|
||||
contextMenuBuilder: (context, offset) {
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: TextSelectionToolbarAnchors(
|
||||
primaryAnchor: offset,
|
||||
),
|
||||
anchors: TextSelectionToolbarAnchors(primaryAnchor: offset),
|
||||
buttonItems: <ContextMenuButtonItem>[
|
||||
ContextMenuButtonItem(
|
||||
onPressed: () {
|
||||
@@ -77,9 +70,7 @@ class FullPage extends StatelessWidget {
|
||||
const Text(
|
||||
'This example simply shows how many of the previous examples can be combined in a single app.',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 60.0,
|
||||
),
|
||||
const SizedBox(height: 60.0),
|
||||
ContextMenuRegion(
|
||||
contextMenuBuilder: (context, offset) {
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
@@ -90,8 +81,12 @@ class FullPage extends StatelessWidget {
|
||||
ContextMenuButtonItem(
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
Navigator.of(context).push(_showDialog(
|
||||
context, 'Image saved! (not really though)'));
|
||||
Navigator.of(context).push(
|
||||
_showDialog(
|
||||
context,
|
||||
'Image saved! (not really though)',
|
||||
),
|
||||
);
|
||||
},
|
||||
label: 'Save',
|
||||
),
|
||||
@@ -114,38 +109,43 @@ class FullPage extends StatelessWidget {
|
||||
editableTextState.contextMenuButtonItems;
|
||||
if (isValidEmail(value.selection.textInside(value.text))) {
|
||||
buttonItems.insert(
|
||||
0,
|
||||
ContextMenuButtonItem(
|
||||
label: 'Send email',
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
Navigator.of(context).push(_showDialog(
|
||||
context, 'You clicked send email'));
|
||||
},
|
||||
));
|
||||
0,
|
||||
ContextMenuButtonItem(
|
||||
label: 'Send email',
|
||||
onPressed: () {
|
||||
ContextMenuController.removeAny();
|
||||
Navigator.of(context).push(
|
||||
_showDialog(context, 'You clicked send email'),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return AdaptiveTextSelectionToolbar(
|
||||
anchors: editableTextState.contextMenuAnchors,
|
||||
// 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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
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(),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -5,10 +5,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class GlobalSelectionPage extends StatelessWidget {
|
||||
GlobalSelectionPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
GlobalSelectionPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'global-selection';
|
||||
static const String title = 'Global Selection Example';
|
||||
@@ -43,9 +40,7 @@ class GlobalSelectionPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(GlobalSelectionPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -69,7 +64,8 @@ class GlobalSelectionPage extends StatelessWidget {
|
||||
TextField(controller: _controller),
|
||||
const SizedBox(height: 40.0),
|
||||
const SelectableText(
|
||||
'SelectableText also shows its own separate context menu.'),
|
||||
'SelectableText also shows its own separate context menu.',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -6,10 +6,7 @@ import 'context_menu_region.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class ImagePage extends StatelessWidget {
|
||||
const ImagePage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
const ImagePage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'image';
|
||||
static const String title = 'ContextMenu on an Image';
|
||||
@@ -22,8 +19,10 @@ 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)'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,9 +32,7 @@ class ImagePage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(ImagePage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -52,9 +49,7 @@ class ImagePage extends StatelessWidget {
|
||||
ContextMenuRegion(
|
||||
contextMenuBuilder: (context, offset) {
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: TextSelectionToolbarAnchors(
|
||||
primaryAnchor: offset,
|
||||
),
|
||||
anchors: TextSelectionToolbarAnchors(primaryAnchor: offset),
|
||||
buttonItems: <ContextMenuButtonItem>[
|
||||
ContextMenuButtonItem(
|
||||
onPressed: () {
|
||||
|
||||
@@ -21,9 +21,7 @@ void main() {
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({
|
||||
super.key,
|
||||
});
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
@@ -66,40 +64,43 @@ 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),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatelessWidget {
|
||||
const MyHomePage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
const MyHomePage({super.key, required this.onChangedPlatform});
|
||||
|
||||
final PlatformCallback onChangedPlatform;
|
||||
|
||||
@@ -109,9 +110,7 @@ class MyHomePage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text('Context Menu Demos'),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
],
|
||||
),
|
||||
body: ListView(
|
||||
@@ -203,10 +202,7 @@ class _MyListItem extends StatelessWidget {
|
||||
margin: const EdgeInsets.all(12.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: ListTile(
|
||||
title: Text(title),
|
||||
subtitle: Text(subtitle),
|
||||
),
|
||||
child: ListTile(title: Text(title), subtitle: Text(subtitle)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -5,10 +5,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class ModifiedActionPage extends StatelessWidget {
|
||||
ModifiedActionPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
ModifiedActionPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'modified-action';
|
||||
static const String title = 'Modified Action';
|
||||
@@ -25,8 +22,10 @@ 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.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,9 +35,7 @@ class ModifiedActionPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(ModifiedActionPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -58,20 +55,18 @@ class ModifiedActionPage extends StatelessWidget {
|
||||
const Text(
|
||||
'This example shows adding to the behavior of a default button.',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30.0,
|
||||
),
|
||||
const SizedBox(height: 30.0),
|
||||
TextField(
|
||||
controller: _controller,
|
||||
contextMenuBuilder: (context, editableTextState) {
|
||||
final List<ContextMenuButtonItem> buttonItems =
|
||||
editableTextState.contextMenuButtonItems;
|
||||
// Modify the copy buttonItem to show a dialog after copying.
|
||||
final int copyButtonIndex = buttonItems.indexWhere(
|
||||
(buttonItem) {
|
||||
return buttonItem.type == ContextMenuButtonType.copy;
|
||||
},
|
||||
);
|
||||
final int copyButtonIndex = buttonItems.indexWhere((
|
||||
buttonItem,
|
||||
) {
|
||||
return buttonItem.type == ContextMenuButtonType.copy;
|
||||
});
|
||||
if (copyButtonIndex >= 0) {
|
||||
final ContextMenuButtonItem copyButtonItem =
|
||||
buttonItems[copyButtonIndex];
|
||||
|
||||
@@ -4,10 +4,7 @@ import 'package:flutter/material.dart';
|
||||
typedef PlatformCallback = void Function(TargetPlatform platform);
|
||||
|
||||
class PlatformSelector extends StatefulWidget {
|
||||
const PlatformSelector({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
const PlatformSelector({super.key, required this.onChangedPlatform});
|
||||
|
||||
final PlatformCallback onChangedPlatform;
|
||||
|
||||
@@ -40,21 +37,19 @@ 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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ import 'constants.dart';
|
||||
import 'platform_selector.dart';
|
||||
|
||||
class ReorderedButtonsPage extends StatelessWidget {
|
||||
ReorderedButtonsPage({
|
||||
super.key,
|
||||
required this.onChangedPlatform,
|
||||
});
|
||||
ReorderedButtonsPage({super.key, required this.onChangedPlatform});
|
||||
|
||||
static const String route = 'reordered-buttons';
|
||||
static const String title = 'Reordered Buttons';
|
||||
@@ -33,9 +30,7 @@ class ReorderedButtonsPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: const Text(ReorderedButtonsPage.title),
|
||||
actions: <Widget>[
|
||||
PlatformSelector(
|
||||
onChangedPlatform: onChangedPlatform,
|
||||
),
|
||||
PlatformSelector(onChangedPlatform: onChangedPlatform),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.code),
|
||||
onPressed: () async {
|
||||
@@ -52,10 +47,7 @@ class ReorderedButtonsPage extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
TextField(
|
||||
maxLines: 2,
|
||||
controller: _controllerNormal,
|
||||
),
|
||||
TextField(maxLines: 2, controller: _controllerNormal),
|
||||
const SizedBox(height: 20.0),
|
||||
TextField(
|
||||
controller: _controllerReordered,
|
||||
@@ -63,16 +55,17 @@ class ReorderedButtonsPage extends StatelessWidget {
|
||||
contextMenuBuilder: (context, editableTextState) {
|
||||
// Reorder the button datas by type.
|
||||
final HashMap<ContextMenuButtonType, ContextMenuButtonItem>
|
||||
buttonItemsMap =
|
||||
buttonItemsMap =
|
||||
HashMap<ContextMenuButtonType, ContextMenuButtonItem>();
|
||||
for (ContextMenuButtonItem buttonItem
|
||||
in editableTextState.contextMenuButtonItems) {
|
||||
buttonItemsMap[buttonItem.type] = buttonItem;
|
||||
}
|
||||
final List<ContextMenuButtonItem> reorderedButtonItems =
|
||||
<ContextMenuButtonItem>[
|
||||
if (buttonItemsMap
|
||||
.containsKey(ContextMenuButtonType.selectAll))
|
||||
final List<ContextMenuButtonItem>
|
||||
reorderedButtonItems = <ContextMenuButtonItem>[
|
||||
if (buttonItemsMap.containsKey(
|
||||
ContextMenuButtonType.selectAll,
|
||||
))
|
||||
buttonItemsMap[ContextMenuButtonType.selectAll]!,
|
||||
if (buttonItemsMap.containsKey(ContextMenuButtonType.paste))
|
||||
buttonItemsMap[ContextMenuButtonType.paste]!,
|
||||
|
||||
Reference in New Issue
Block a user