@@ -636,13 +636,15 @@ class _ActivatorIntentPair with Diagnosticable {
636636 }
637637}
638638
639- /// A manager of keyboard shortcut bindings.
640- ///
641- /// A `ShortcutManager` is obtained by calling [Shortcuts.of] on the context of
642- /// the widget that you want to find a manager for.
639+ /// A manager of keyboard shortcut bindings used by [Shortcuts] to handle key
640+ /// events.
643641///
644642/// The manager may be listened to (with [addListener] /[removeListener] ) for
645643/// change notifications when the shortcuts change.
644+ ///
645+ /// Typically, a [Shortcuts] widget supplies its own manager, but in uncommon
646+ /// cases where overriding the usual shortcut manager behavior is desired, a
647+ /// subclassed [ShortcutManager] may be supplied.
646648class ShortcutManager with Diagnosticable , ChangeNotifier {
647649 /// Constructs a [ShortcutManager] .
648650 ShortcutManager ({
@@ -773,6 +775,10 @@ class ShortcutManager with Diagnosticable, ChangeNotifier {
773775/// when invoking an [Action] via a keyboard key combination that maps to an
774776/// [Intent] .
775777///
778+ /// See the article on [Using Actions and
779+ /// Shortcuts](https://docs.flutter.dev/development/ui/advanced/actions_and_shortcuts)
780+ /// for a detailed explanation.
781+ ///
776782/// {@tool dartpad}
777783/// Here, we will use the [Shortcuts] and [Actions] widgets to add and subtract
778784/// from a counter. When the child widget has keyboard focus, and a user presses
@@ -810,35 +816,61 @@ class ShortcutManager with Diagnosticable, ChangeNotifier {
810816/// * [Action] , a class for defining an invocation of a user action.
811817/// * [CallbackAction] , a class for creating an action from a callback.
812818class Shortcuts extends StatefulWidget {
813- /// Creates a const [Shortcuts] widget.
819+ /// Creates a const [Shortcuts] widget that owns the map of shortcuts and
820+ /// creates its own manager.
821+ ///
822+ /// When using this constructor, [manager] will return null.
814823 ///
815824 /// The [child] and [shortcuts] arguments are required.
825+ ///
826+ /// See also:
827+ ///
828+ /// * [Shortcuts.manager] , a constructor that uses a [ShortcutManager] to
829+ /// manage the shortcuts list instead.
816830 const Shortcuts ({
817831 super .key,
818- this .manager,
819- required this .shortcuts,
832+ required Map <ShortcutActivator , Intent > shortcuts,
833+ required this .child,
834+ this .debugLabel,
835+ }) : _shortcuts = shortcuts,
836+ manager = null ,
837+ assert (shortcuts != null ),
838+ assert (child != null );
839+
840+ /// Creates a const [Shortcuts] widget that uses the [manager] to
841+ /// manage the map of shortcuts.
842+ ///
843+ /// If this constructor is used, [shortcuts] will return the contents of
844+ /// [ShortcutManager.shortcuts] .
845+ ///
846+ /// The [child] and [manager] arguments are required.
847+ const Shortcuts .manager ({
848+ super .key,
849+ required ShortcutManager this .manager,
820850 required this .child,
821851 this .debugLabel,
822- }) : assert (shortcuts != null ),
852+ }) : _shortcuts = const < ShortcutActivator , Intent > {},
853+ assert (manager != null ),
823854 assert (child != null );
824855
825856 /// The [ShortcutManager] that will manage the mapping between key
826857 /// combinations and [Action] s.
827858 ///
828- /// If not specified, uses a default-constructed [ShortcutManager] .
829- ///
830- /// This manager will be given new [shortcuts] to manage whenever the
831- /// [shortcuts] change materially .
859+ /// If this widget was created with [Shortcuts.manager] , then
860+ /// [ShortcutManager.shortcuts] will be used as the source for shortcuts. If
861+ /// the unnamed constructor is used, this manager will be null, and a
862+ /// default-constructed `ShortcutsManager` will be used .
832863 final ShortcutManager ? manager;
833864
834865 /// {@template flutter.widgets.shortcuts.shortcuts}
835- /// The map of shortcuts that the [ShortcutManager] will be given to manage.
836- ///
837- /// For performance reasons, it is recommended that a pre-built map is passed
838- /// in here (e.g. a final variable from your widget class) instead of defining
839- /// it inline in the build function.
866+ /// The map of shortcuts that describes the mapping between a key sequence
867+ /// defined by a [ShortcutActivator] and the [Intent] that will be emitted
868+ /// when that key sequence is pressed.
840869 /// {@endtemplate}
841- final Map <ShortcutActivator , Intent > shortcuts;
870+ Map <ShortcutActivator , Intent > get shortcuts {
871+ return manager == null ? _shortcuts : manager! .shortcuts;
872+ }
873+ final Map <ShortcutActivator , Intent > _shortcuts;
842874
843875 /// The child widget for this [Shortcuts] widget.
844876 ///
@@ -854,52 +886,6 @@ class Shortcuts extends StatefulWidget {
854886 /// unnecessarily with large default shortcut maps.
855887 final String ? debugLabel;
856888
857- /// Returns the [ShortcutManager] that most tightly encloses the given
858- /// [BuildContext] .
859- ///
860- /// If no [Shortcuts] widget encloses the context given, will assert in debug
861- /// mode and throw an exception in release mode.
862- ///
863- /// See also:
864- ///
865- /// * [maybeOf] , which is similar to this function, but will return null if
866- /// it doesn't find a [Shortcuts] ancestor.
867- static ShortcutManager of (BuildContext context) {
868- assert (context != null );
869- final _ShortcutsMarker ? inherited = context.dependOnInheritedWidgetOfExactType <_ShortcutsMarker >();
870- assert (() {
871- if (inherited == null ) {
872- throw FlutterError (
873- 'Unable to find a $Shortcuts widget in the context.\n '
874- '$Shortcuts .of() was called with a context that does not contain a '
875- '$Shortcuts widget.\n '
876- 'No $Shortcuts ancestor could be found starting from the context that was '
877- 'passed to $Shortcuts .of().\n '
878- 'The context used was:\n '
879- ' $context ' ,
880- );
881- }
882- return true ;
883- }());
884- return inherited! .manager;
885- }
886-
887- /// Returns the [ShortcutManager] that most tightly encloses the given
888- /// [BuildContext] .
889- ///
890- /// If no [Shortcuts] widget encloses the context given, will return null.
891- ///
892- /// See also:
893- ///
894- /// * [of] , which is similar to this function, but returns a non-nullable
895- /// result, and will throw an exception if it doesn't find a [Shortcuts]
896- /// ancestor.
897- static ShortcutManager ? maybeOf (BuildContext context) {
898- assert (context != null );
899- final _ShortcutsMarker ? inherited = context.dependOnInheritedWidgetOfExactType <_ShortcutsMarker >();
900- return inherited? .manager;
901- }
902-
903889 @override
904890 State <Shortcuts > createState () => _ShortcutsState ();
905891
@@ -926,8 +912,8 @@ class _ShortcutsState extends State<Shortcuts> {
926912 super .initState ();
927913 if (widget.manager == null ) {
928914 _internalManager = ShortcutManager ();
915+ _internalManager! .shortcuts = widget.shortcuts;
929916 }
930- manager.shortcuts = widget.shortcuts;
931917 }
932918
933919 @override
@@ -941,7 +927,7 @@ class _ShortcutsState extends State<Shortcuts> {
941927 _internalManager ?? = ShortcutManager ();
942928 }
943929 }
944- manager .shortcuts = widget.shortcuts;
930+ _internalManager ? .shortcuts = widget.shortcuts;
945931 }
946932
947933 KeyEventResult _handleOnKey (FocusNode node, RawKeyEvent event) {
@@ -1331,8 +1317,7 @@ class _ShortcutRegistrarState extends State<ShortcutRegistrar> {
13311317
13321318 @override
13331319 Widget build (BuildContext context) {
1334- return Shortcuts (
1335- shortcuts: registry.shortcuts,
1320+ return Shortcuts .manager (
13361321 manager: manager,
13371322 child: _ShortcutRegistrarMarker (
13381323 registry: registry,
0 commit comments