// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flutter code sample for [Actions]. import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); static const String _title = 'Flutter Code Sample'; @override Widget build(BuildContext context) { return MaterialApp( title: _title, home: Scaffold( appBar: AppBar(title: const Text(_title)), body: const Center( child: MyStatefulWidget(), ), ), ); } } // A simple model class that notifies listeners when it changes. class Model { ValueNotifier isDirty = ValueNotifier(false); ValueNotifier data = ValueNotifier(0); int save() { if (isDirty.value) { debugPrint('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 { 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 { SaveAction(this.model); final Model model; @override int invoke(covariant SaveIntent intent) => model.save(); } class SaveButton extends StatefulWidget { const SaveButton(this.valueNotifier, {super.key}); final ValueNotifier valueNotifier; @override State createState() => _SaveButtonState(); } class _SaveButtonState extends State { 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: MaterialStatePropertyAll( widget.valueNotifier.value ? Colors.red : Colors.green, ), ), onPressed: () { setState(() { savedValue = Actions.invoke(context, const SaveIntent())! as int; }); }, ); }, ); } } class MyStatefulWidget extends StatefulWidget { const MyStatefulWidget({super.key}); @override State createState() => _MyStatefulWidgetState(); } class _MyStatefulWidgetState extends State { Model model = Model(); int count = 0; @override Widget build(BuildContext context) { return Actions( actions: >{ ModifyIntent: ModifyAction(model), SaveIntent: SaveAction(model), }, child: Builder( builder: (BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ const Spacer(), Column( mainAxisAlignment: MainAxisAlignment.center, children: [ 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.headlineMedium), ); }), IconButton( icon: const Icon(Icons.exposure_minus_1), onPressed: () { Actions.invoke(context, ModifyIntent(--count)); }, ), ], ), SaveButton(model.isDirty), const Spacer(), ], ); }, ), ); } }