Unverified Commit 2d0afe4d authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Add some new examples to Actions and Shortcuts (#72163)

Adds a couple of new examples to the Actions and Shortcuts widgets, and updates some documentation.
parent e7772d0e
......@@ -137,6 +137,10 @@ abstract class Action<T extends Intent> with Diagnosticable {
/// }
/// }
/// ```
///
/// To receive the result of invoking an action, it must be invoked using
/// [Actions.invoke], or by invoking it using an [ActionDispatcher]. An action
/// invoked via a [Shortcuts] widget will have its return value ignored.
@protected
Object? invoke(covariant T intent);
......@@ -519,6 +523,168 @@ class ActionDispatcher with Diagnosticable {
/// Actions are typically invoked using [Actions.invoke] with the context
/// containing the ambient [Actions] widget.
///
/// {@tool dartpad --template=stateful_widget_scaffold_center}
///
/// This example creates a custom [Action] subclass `ModifyAction` for modifying
/// a model, and another, `SaveAction` for saving it.
///
/// This example demonstrates passing arguments to the [Intent] to be carried to
/// the [Action]. Actions can get data either from their own construction (like
/// the `model` in this example), or from the intent passed to them when invoked
/// (like the increment `amount` in this example).
///
/// This example also demonstrates how to use Intents to limit a widget's
/// dependencies on its surroundings. The `SaveButton` widget defined in this
/// example can invoke actions defined in its ancestor widgets, which can be
/// customized to match the part of the widget tree that it is in. It doesn't
/// need to know about the `SaveAction` class, only the `SaveIntent`, and it
/// only needs to know about a value notifier, not the entire model.
///
/// ```dart preamble
/// // A simple model class that notifies listeners when it changes.
/// class Model {
/// ValueNotifier<bool> isDirty = ValueNotifier<bool>(false);
/// ValueNotifier<int> data = ValueNotifier<int>(0);
///
/// int save() {
/// if (isDirty.value) {
/// print('Saved Data: ${data.value}');
/// isDirty.value = false;
/// }
/// return data.value;
/// }
///
/// void setValue(int newValue) {
/// isDirty.value = data.value != newValue;
/// data.value = newValue;
/// }
/// }
///
/// class ModifyIntent extends Intent {
/// const ModifyIntent(this.value);
///
/// final int value;
/// }
///
/// // An Action that modifies the model by setting it to the value that it gets
/// // from the Intent passed to it when invoked.
/// class ModifyAction extends Action<ModifyIntent> {
/// ModifyAction(this.model);
///
/// final Model model;
///
/// @override
/// void invoke(covariant ModifyIntent intent) {
/// model.setValue(intent.value);
/// }
/// }
///
/// // An intent for saving data.
/// class SaveIntent extends Intent {
/// const SaveIntent();
/// }
///
/// // An Action that saves the data in the model it is created with.
/// class SaveAction extends Action<SaveIntent> {
/// SaveAction(this.model);
///
/// final Model model;
///
/// @override
/// int invoke(covariant SaveIntent intent) => model.save();
/// }
///
/// class SaveButton extends StatefulWidget {
/// const SaveButton(this.valueNotifier);
///
/// final ValueNotifier<bool> valueNotifier;
///
/// @override
/// _SaveButtonState createState() => _SaveButtonState();
/// }
///
/// class _SaveButtonState extends State<SaveButton> {
/// int savedValue = 0;
///
/// @override
/// Widget build(BuildContext context) {
/// return AnimatedBuilder(
/// animation: widget.valueNotifier,
/// builder: (BuildContext context, Widget? child) {
/// return TextButton.icon(
/// icon: const Icon(Icons.save),
/// label: Text('$savedValue'),
/// style: ButtonStyle(
/// foregroundColor: MaterialStateProperty.all<Color>(
/// widget.valueNotifier.value ? Colors.red : Colors.green,
/// ),
/// ),
/// onPressed: () {
/// setState(() {
/// savedValue = Actions.invoke(context, const SaveIntent()) as int;
/// });
/// },
/// );
/// },
/// );
/// }
/// }
/// ```
///
/// ```dart
/// Model model = Model();
/// int count = 0;
///
/// @override
/// Widget build(BuildContext context) {
/// return Actions(
/// actions: <Type, Action<Intent>>{
/// ModifyIntent: ModifyAction(model),
/// SaveIntent: SaveAction(model),
/// },
/// child: Builder(
/// builder: (BuildContext context) {
/// return Row(
/// mainAxisAlignment: MainAxisAlignment.spaceAround,
/// children: <Widget>[
/// const Spacer(),
/// Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// IconButton(
/// icon: const Icon(Icons.exposure_plus_1),
/// onPressed: () {
/// Actions.invoke(context, ModifyIntent(count++));
/// },
/// ),
/// AnimatedBuilder(
/// animation: model.data,
/// builder: (BuildContext context, Widget? child) {
/// return Padding(
/// padding: const EdgeInsets.all(8.0),
/// child: Text('${model.data.value}',
/// style: Theme.of(context).textTheme.headline4),
/// );
/// }),
/// IconButton(
/// icon: const Icon(Icons.exposure_minus_1),
/// onPressed: () {
/// Actions.invoke(context, ModifyIntent(count--));
/// },
/// ),
/// ],
/// ),
/// SaveButton(model.isDirty),
/// const Spacer(),
/// ],
/// );
/// },
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [ActionDispatcher], the object that this widget uses to manage actions.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment