Unverified Commit f6c3ee31 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Add ShortcutsRegistry (#103456)

This adds a ShortcutsRegistry for ShortcutActivator to Intent mappings that can be modified from its descendants.

This is so that descendants can make shortcuts dynamically available to a larger portion of the app than just their descendants. This is a precursor needed by the new MenuBar, for instance, so that the menu bar itself can be placed where it likes, but the shortcuts it defines can be in effect for most, if not all, of the UI surface in the app. For example, the "Ctrl-Q" quit binding would need to work even if the focused widget wasn't a child of the MenuBar.

This just provides the shortcut to intent mapping, the actions activated by the intent are described in the context where they make sense. For example, defining a "Ctrl-C" shortcut mapped to a "CopyIntent" should perform different functions if it happens while a TextField has focus vs when a drawing has focus, so those different areas would need to define different actions mapped to "CopyIntent". A hypothetical "QuitIntent" would probably be active for the entire app, so would be mapped in an Actions widget near the top of the hierarchy.
parent d2ba83d4
......@@ -119,7 +119,24 @@ class ChangeNotifier implements Listenable {
int _reentrantlyRemovedListeners = 0;
bool _debugDisposed = false;
bool _debugAssertNotDisposed() {
/// Used by subclasses to assert that the [ChangeNotifier] has not yet been
/// disposed.
///
/// {@tool snippet}
/// The `debugAssertNotDisposed` function should only be called inside of an
/// assert, as in this example.
///
/// ```dart
/// class MyNotifier with ChangeNotifier {
/// void doUpdate() {
/// assert(debugAssertNotDisposed());
/// // ...
/// }
/// }
/// ```
/// {@end-tool}
@protected
bool debugAssertNotDisposed() {
assert(() {
if (_debugDisposed) {
throw FlutterError(
......@@ -149,7 +166,7 @@ class ChangeNotifier implements Listenable {
/// so, stopping that same work.
@protected
bool get hasListeners {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
return _count > 0;
}
......@@ -181,7 +198,7 @@ class ChangeNotifier implements Listenable {
/// the list of closures that are notified when the object changes.
@override
void addListener(VoidCallback listener) {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
if (_count == _listeners.length) {
if (_count == 0) {
_listeners = List<VoidCallback?>.filled(1, null);
......@@ -273,7 +290,7 @@ class ChangeNotifier implements Listenable {
/// This method should only be called by the object's owner.
@mustCallSuper
void dispose() {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
assert(() {
_debugDisposed = true;
return true;
......@@ -301,7 +318,7 @@ class ChangeNotifier implements Listenable {
@visibleForTesting
@pragma('vm:notify-debugger-on-exception')
void notifyListeners() {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
if (_count == 0)
return;
......
......@@ -473,7 +473,7 @@ abstract class RestorableProperty<T> extends ChangeNotifier {
@override
void dispose() {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed()); // FYI, This uses ChangeNotifier's _debugDisposed, not _disposed.
_owner?._unregister(this);
super.dispose();
_disposed = true;
......@@ -483,14 +483,14 @@ abstract class RestorableProperty<T> extends ChangeNotifier {
String? _restorationId;
RestorationMixin? _owner;
void _register(String restorationId, RestorationMixin owner) {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
assert(restorationId != null);
assert(owner != null);
_restorationId = restorationId;
_owner = owner;
}
void _unregister() {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
assert(_restorationId != null);
assert(_owner != null);
_restorationId = null;
......@@ -503,29 +503,16 @@ abstract class RestorableProperty<T> extends ChangeNotifier {
@protected
State get state {
assert(isRegistered);
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
return _owner!;
}
/// Whether this property is currently registered with a [RestorationMixin].
@protected
bool get isRegistered {
assert(_debugAssertNotDisposed());
assert(debugAssertNotDisposed());
return _restorationId != null;
}
bool _debugAssertNotDisposed() {
assert(() {
if (_disposed) {
throw FlutterError(
'A $runtimeType was used after being disposed.\n'
'Once you have called dispose() on a $runtimeType, it can no longer be used.',
);
}
return true;
}());
return true;
}
}
/// Manages the restoration data for a [State] object of a [StatefulWidget].
......
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