blob: 043c2448f37aa3e83a505674ee829f784c909ebb [file] [log] [blame]
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/gallery_localizations.dart';
import 'package:gallery/demos/material/material_demo_types.dart';
enum SimpleValue {
one,
two,
three,
}
enum CheckedValue {
one,
two,
three,
four,
}
class MenuDemo extends StatefulWidget {
const MenuDemo({super.key, required this.type});
final MenuDemoType type;
@override
State<MenuDemo> createState() => _MenuDemoState();
}
class _MenuDemoState extends State<MenuDemo> {
void showInSnackBar(String value) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(value),
));
}
@override
Widget build(BuildContext context) {
Widget demo;
switch (widget.type) {
case MenuDemoType.contextMenu:
demo = _ContextMenuDemo(showInSnackBar: showInSnackBar);
break;
case MenuDemoType.sectionedMenu:
demo = _SectionedMenuDemo(showInSnackBar: showInSnackBar);
break;
case MenuDemoType.simpleMenu:
demo = _SimpleMenuDemo(showInSnackBar: showInSnackBar);
break;
case MenuDemoType.checklistMenu:
demo = _ChecklistMenuDemo(showInSnackBar: showInSnackBar);
break;
}
return Scaffold(
appBar: AppBar(
title: Text(GalleryLocalizations.of(context)!.demoMenuTitle),
automaticallyImplyLeading: false,
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: demo,
),
),
);
}
}
// BEGIN menuDemoContext
// Pressing the PopupMenuButton on the right of this item shows
// a simple menu with one disabled item. Typically the contents
// of this "contextual menu" would reflect the app's state.
class _ContextMenuDemo extends StatelessWidget {
const _ContextMenuDemo({required this.showInSnackBar});
final void Function(String value) showInSnackBar;
@override
Widget build(BuildContext context) {
final localizations = GalleryLocalizations.of(context)!;
return ListTile(
title: Text(localizations.demoMenuAnItemWithAContextMenuButton),
trailing: PopupMenuButton<String>(
padding: EdgeInsets.zero,
onSelected: (value) => showInSnackBar(
localizations.demoMenuSelected(value),
),
itemBuilder: (context) => <PopupMenuItem<String>>[
PopupMenuItem<String>(
value: localizations.demoMenuContextMenuItemOne,
child: Text(
localizations.demoMenuContextMenuItemOne,
),
),
PopupMenuItem<String>(
enabled: false,
child: Text(
localizations.demoMenuADisabledMenuItem,
),
),
PopupMenuItem<String>(
value: localizations.demoMenuContextMenuItemThree,
child: Text(
localizations.demoMenuContextMenuItemThree,
),
),
],
),
);
}
}
// END
// BEGIN menuDemoSectioned
// Pressing the PopupMenuButton on the right of this item shows
// a menu whose items have text labels and icons and a divider
// That separates the first three items from the last one.
class _SectionedMenuDemo extends StatelessWidget {
const _SectionedMenuDemo({required this.showInSnackBar});
final void Function(String value) showInSnackBar;
@override
Widget build(BuildContext context) {
final localizations = GalleryLocalizations.of(context)!;
return ListTile(
title: Text(localizations.demoMenuAnItemWithASectionedMenu),
trailing: PopupMenuButton<String>(
padding: EdgeInsets.zero,
onSelected: (value) =>
showInSnackBar(localizations.demoMenuSelected(value)),
itemBuilder: (context) => <PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: localizations.demoMenuPreview,
child: ListTile(
leading: const Icon(Icons.visibility),
title: Text(
localizations.demoMenuPreview,
),
),
),
PopupMenuItem<String>(
value: localizations.demoMenuShare,
child: ListTile(
leading: const Icon(Icons.person_add),
title: Text(
localizations.demoMenuShare,
),
),
),
PopupMenuItem<String>(
value: localizations.demoMenuGetLink,
child: ListTile(
leading: const Icon(Icons.link),
title: Text(
localizations.demoMenuGetLink,
),
),
),
const PopupMenuDivider(),
PopupMenuItem<String>(
value: localizations.demoMenuRemove,
child: ListTile(
leading: const Icon(Icons.delete),
title: Text(
localizations.demoMenuRemove,
),
),
),
],
),
);
}
}
// END
// BEGIN menuDemoSimple
// This entire list item is a PopupMenuButton. Tapping anywhere shows
// a menu whose current value is highlighted and aligned over the
// list item's center line.
class _SimpleMenuDemo extends StatefulWidget {
const _SimpleMenuDemo({required this.showInSnackBar});
final void Function(String value) showInSnackBar;
@override
_SimpleMenuDemoState createState() => _SimpleMenuDemoState();
}
class _SimpleMenuDemoState extends State<_SimpleMenuDemo> {
late SimpleValue _simpleValue;
void showAndSetMenuSelection(BuildContext context, SimpleValue value) {
setState(() {
_simpleValue = value;
});
widget.showInSnackBar(
GalleryLocalizations.of(context)!
.demoMenuSelected(simpleValueToString(context, value)),
);
}
String simpleValueToString(BuildContext context, SimpleValue value) {
final localizations = GalleryLocalizations.of(context)!;
return {
SimpleValue.one: localizations.demoMenuItemValueOne,
SimpleValue.two: localizations.demoMenuItemValueTwo,
SimpleValue.three: localizations.demoMenuItemValueThree,
}[value]!;
}
@override
void initState() {
super.initState();
_simpleValue = SimpleValue.two;
}
@override
Widget build(BuildContext context) {
return PopupMenuButton<SimpleValue>(
padding: EdgeInsets.zero,
initialValue: _simpleValue,
onSelected: (value) => showAndSetMenuSelection(context, value),
itemBuilder: (context) => <PopupMenuItem<SimpleValue>>[
PopupMenuItem<SimpleValue>(
value: SimpleValue.one,
child: Text(simpleValueToString(
context,
SimpleValue.one,
)),
),
PopupMenuItem<SimpleValue>(
value: SimpleValue.two,
child: Text(simpleValueToString(
context,
SimpleValue.two,
)),
),
PopupMenuItem<SimpleValue>(
value: SimpleValue.three,
child: Text(simpleValueToString(
context,
SimpleValue.three,
)),
),
],
child: ListTile(
title: Text(
GalleryLocalizations.of(context)!.demoMenuAnItemWithASimpleMenu),
subtitle: Text(simpleValueToString(context, _simpleValue)),
),
);
}
}
// END
// BEGIN menuDemoChecklist
// Pressing the PopupMenuButton on the right of this item shows a menu
// whose items have checked icons that reflect this app's state.
class _ChecklistMenuDemo extends StatefulWidget {
const _ChecklistMenuDemo({required this.showInSnackBar});
final void Function(String value) showInSnackBar;
@override
_ChecklistMenuDemoState createState() => _ChecklistMenuDemoState();
}
class _RestorableCheckedValues extends RestorableProperty<Set<CheckedValue>> {
Set<CheckedValue> _checked = <CheckedValue>{};
void check(CheckedValue value) {
_checked.add(value);
notifyListeners();
}
void uncheck(CheckedValue value) {
_checked.remove(value);
notifyListeners();
}
bool isChecked(CheckedValue value) => _checked.contains(value);
Iterable<String> checkedValuesToString(BuildContext context) {
final localizations = GalleryLocalizations.of(context)!;
return _checked.map((value) {
return {
CheckedValue.one: localizations.demoMenuOne,
CheckedValue.two: localizations.demoMenuTwo,
CheckedValue.three: localizations.demoMenuThree,
CheckedValue.four: localizations.demoMenuFour,
}[value]!;
});
}
@override
Set<CheckedValue> createDefaultValue() => _checked;
@override
Set<CheckedValue> initWithValue(Set<CheckedValue> a) {
_checked = a;
return _checked;
}
@override
Object toPrimitives() => _checked.map((value) => value.index).toList();
@override
Set<CheckedValue> fromPrimitives(Object? data) {
final checkedValues = data as List<dynamic>;
return Set.from(checkedValues.map<CheckedValue>((dynamic id) {
return CheckedValue.values[id as int];
}));
}
}
class _ChecklistMenuDemoState extends State<_ChecklistMenuDemo>
with RestorationMixin {
final _RestorableCheckedValues _checkedValues = _RestorableCheckedValues()
..check(CheckedValue.three);
@override
String get restorationId => 'checklist_menu_demo';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_checkedValues, 'checked_values');
}
void showCheckedMenuSelections(BuildContext context, CheckedValue value) {
if (_checkedValues.isChecked(value)) {
setState(() {
_checkedValues.uncheck(value);
});
} else {
setState(() {
_checkedValues.check(value);
});
}
widget.showInSnackBar(
GalleryLocalizations.of(context)!.demoMenuChecked(
_checkedValues.checkedValuesToString(context),
),
);
}
String checkedValueToString(BuildContext context, CheckedValue value) {
final localizations = GalleryLocalizations.of(context)!;
return {
CheckedValue.one: localizations.demoMenuOne,
CheckedValue.two: localizations.demoMenuTwo,
CheckedValue.three: localizations.demoMenuThree,
CheckedValue.four: localizations.demoMenuFour,
}[value]!;
}
@override
void dispose() {
_checkedValues.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(
GalleryLocalizations.of(context)!.demoMenuAnItemWithAChecklistMenu,
),
trailing: PopupMenuButton<CheckedValue>(
padding: EdgeInsets.zero,
onSelected: (value) => showCheckedMenuSelections(context, value),
itemBuilder: (context) => <PopupMenuItem<CheckedValue>>[
CheckedPopupMenuItem<CheckedValue>(
value: CheckedValue.one,
checked: _checkedValues.isChecked(CheckedValue.one),
child: Text(
checkedValueToString(context, CheckedValue.one),
),
),
CheckedPopupMenuItem<CheckedValue>(
value: CheckedValue.two,
enabled: false,
checked: _checkedValues.isChecked(CheckedValue.two),
child: Text(
checkedValueToString(context, CheckedValue.two),
),
),
CheckedPopupMenuItem<CheckedValue>(
value: CheckedValue.three,
checked: _checkedValues.isChecked(CheckedValue.three),
child: Text(
checkedValueToString(context, CheckedValue.three),
),
),
CheckedPopupMenuItem<CheckedValue>(
value: CheckedValue.four,
checked: _checkedValues.isChecked(CheckedValue.four),
child: Text(
checkedValueToString(context, CheckedValue.four),
),
),
],
),
);
}
}
// END