Fix some Focus related documentation typos (#118576)
* Fix focus area documentation typos
* Restore intentional spaces that illustrate bigger buttons
diff --git a/packages/flutter/lib/src/widgets/actions.dart b/packages/flutter/lib/src/widgets/actions.dart
index e99e4ea..adf544a 100644
--- a/packages/flutter/lib/src/widgets/actions.dart
+++ b/packages/flutter/lib/src/widgets/actions.dart
@@ -954,7 +954,7 @@
final Action<T>? result = _castAction(actions, intent: intent);
if (result != null && result.isEnabled(intent)) {
// Invoke the action we found using the relevant dispatcher from the Actions
- // Element we found.
+ // element we found.
returnValue = _findDispatcher(element).invokeAction(result, intent, context);
}
return result != null;
@@ -1478,7 +1478,8 @@
/// * [WidgetsApp.shortcuts], which defines the shortcuts to use in an
/// application (and defaults to [WidgetsApp.defaultShortcuts]).
class ButtonActivateIntent extends Intent {
- /// Creates an intent that the currently focused control, if it's a button.
+ /// Creates an intent that activates the currently focused control,
+ /// if it's a button.
const ButtonActivateIntent();
}
@@ -1581,7 +1582,7 @@
bool debugAssertConsumeKeyMutuallyRecursive = false;
// The default action to invoke if an enabled override Action can't be found
- // using [lookupContext];
+ // using [lookupContext].
Action<T> get defaultAction;
// The [BuildContext] used to find the override of this [Action].
diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart
index 329f2e6..9973ab4 100644
--- a/packages/flutter/lib/src/widgets/focus_manager.dart
+++ b/packages/flutter/lib/src/widgets/focus_manager.dart
@@ -110,7 +110,7 @@
// The widget tree is responsible for calling reparent/detach on attached
// nodes to keep their parent/manager information up-to-date, so here we can
// safely check if the scope/node involved in each autofocus request is
- // still attached, and discard the ones are no longer attached to the
+ // still attached, and discard the ones which are no longer attached to the
// original manager.
void applyIfValid(FocusManager manager) {
final bool shouldApply = (scope.parent != null || identical(scope, manager.rootScope))
@@ -128,8 +128,8 @@
/// An attachment point for a [FocusNode].
///
-/// Using a [FocusAttachment] is rarely needed, unless you are building
-/// something akin to the [Focus] or [FocusScope] widgets from scratch.
+/// Using a [FocusAttachment] is rarely needed, unless building something
+/// akin to the [Focus] or [FocusScope] widgets from scratch.
///
/// Once created, a [FocusNode] must be attached to the widget tree by its
/// _host_ [StatefulWidget] via a [FocusAttachment] object. [FocusAttachment]s
@@ -261,8 +261,8 @@
///
/// _Please see the [Focus] and [FocusScope] widgets, which are utility widgets
/// that manage their own [FocusNode]s and [FocusScopeNode]s, respectively. If
-/// they aren't appropriate, [FocusNode]s can be managed directly, but doing
-/// this yourself is rare._
+/// they aren't appropriate, [FocusNode]s can be managed directly, but doing this
+/// is rare._
///
/// [FocusNode]s are persistent objects that form a _focus tree_ that is a
/// representation of the widgets in the hierarchy that are interested in focus.
@@ -1405,8 +1405,8 @@
/// The focus manager is responsible for tracking which [FocusNode] has the
/// primary input focus (the [primaryFocus]), holding the [FocusScopeNode] that
/// is the root of the focus tree (the [rootScope]), and what the current
-/// [highlightMode] is. It also distributes key events from [RawKeyboard] to the
-/// nodes in the focus tree.
+/// [highlightMode] is. It also distributes key events from [KeyEventManager]
+/// to the nodes in the focus tree.
///
/// The singleton [FocusManager] instance is held by the [WidgetsBinding] as
/// [WidgetsBinding.focusManager], and can be conveniently accessed using the
diff --git a/packages/flutter/lib/src/widgets/focus_scope.dart b/packages/flutter/lib/src/widgets/focus_scope.dart
index f908d32..ca5c8b4 100644
--- a/packages/flutter/lib/src/widgets/focus_scope.dart
+++ b/packages/flutter/lib/src/widgets/focus_scope.dart
@@ -195,7 +195,7 @@
/// {@endtemplate}
///
/// A non-null [focusNode] must be supplied if using the
- /// [Focus.withExternalFocusNode] constructor is used.
+ /// [Focus.withExternalFocusNode] constructor.
final FocusNode? focusNode;
/// {@template flutter.widgets.Focus.autofocus}
diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart
index 4bd503d..db9ec64 100644
--- a/packages/flutter/lib/src/widgets/focus_traversal.dart
+++ b/packages/flutter/lib/src/widgets/focus_traversal.dart
@@ -200,7 +200,7 @@
///
/// See also:
///
- /// * [previous], the function that is called to move the focus to the next node.
+ /// * [previous], the function that is called to move the focus to the previous node.
/// * [DirectionalFocusTraversalPolicyMixin.findFirstFocusInDirection], a
/// function that finds the first focusable widget in a particular direction.
FocusNode findLastFocus(FocusNode currentNode, {bool ignoreCurrentFocus = false}) {
@@ -1139,7 +1139,7 @@
// It has to have at least topmost in it if the topmost is not degenerate.
assert(topmost.rect.isEmpty || inBandOfTop.isNotEmpty);
- // The topmost rect in is in a band by itself, so just return that one.
+ // The topmost rect is in a band by itself, so just return that one.
if (inBandOfTop.length <= 1) {
return topmost;
}
diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart
index 1fba42b..543c7df 100644
--- a/packages/flutter/lib/src/widgets/shortcuts.dart
+++ b/packages/flutter/lib/src/widgets/shortcuts.dart
@@ -90,7 +90,6 @@
&& setEquals<T>(other._keys, _keys);
}
-
// Cached hash code value. Improves [hashCode] performance by 27%-900%,
// depending on key set size and read/write ratio.
@override
@@ -334,8 +333,8 @@
}
}
-/// A [DiagnosticsProperty] which handles formatting a `Map<LogicalKeySet,
-/// Intent>` (the same type as the [Shortcuts.shortcuts] property) so that its
+/// A [DiagnosticsProperty] which handles formatting a `Map<LogicalKeySet, Intent>`
+/// (the same type as the [Shortcuts.shortcuts] property) so that its
/// diagnostic output is human-readable.
class ShortcutMapProperty extends DiagnosticsProperty<Map<ShortcutActivator, Intent>> {
/// Create a diagnostics property for `Map<ShortcutActivator, Intent>` objects,
@@ -1183,7 +1182,7 @@
///
/// The registry may be listened to (with [addListener]/[removeListener]) for
/// change notifications when the registered shortcuts change. Change
-/// notifications take place after the the current frame is drawn, so that
+/// notifications take place after the current frame is drawn, so that
/// widgets that are not descendants of the registry can listen to it (e.g. in
/// overlays).
class ShortcutRegistry with ChangeNotifier {
diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart
index 36db3a3..044b046 100644
--- a/packages/flutter/test/widgets/actions_test.dart
+++ b/packages/flutter/test/widgets/actions_test.dart
@@ -74,6 +74,7 @@
expect(result, isTrue);
expect(invoked, isTrue);
});
+
testWidgets('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async {
final GlobalKey containerKey = GlobalKey();
bool invoked = false;
@@ -1083,6 +1084,7 @@
action._testInvoke(intent);
expect(passedIntent, equals(intent));
});
+
testWidgets('VoidCallbackAction', (WidgetTester tester) async {
bool called = false;
void testCallback() {
@@ -1121,6 +1123,7 @@
expect(description, isEmpty);
});
+
testWidgets('default Actions debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
@@ -1146,6 +1149,7 @@
]),
);
});
+
testWidgets('Actions implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
diff --git a/packages/flutter/test/widgets/focus_scope_test.dart b/packages/flutter/test/widgets/focus_scope_test.dart
index 08943d3..3edaeb8 100644
--- a/packages/flutter/test/widgets/focus_scope_test.dart
+++ b/packages/flutter/test/widgets/focus_scope_test.dart
@@ -420,7 +420,7 @@
expect(find.text('b'), findsOneWidget);
});
- testWidgets('Adding a new FocusScope attaches the child it to its parent.', (WidgetTester tester) async {
+ testWidgets('Adding a new FocusScope attaches the child to its parent.', (WidgetTester tester) async {
final GlobalKey<TestFocusState> keyA = GlobalKey();
final FocusScopeNode parentFocusScope = FocusScopeNode(debugLabel: 'Parent Scope Node');
final FocusScopeNode childFocusScope = FocusScopeNode(debugLabel: 'Child Scope Node');
@@ -540,24 +540,24 @@
await tester.pumpWidget(
FocusScope.withExternalFocusNode(
- focusScopeNode: topNode,
- child: Column(
- children: <Widget>[
- FocusScope.withExternalFocusNode(
- focusScopeNode: parentNode,
- child: const SizedBox(),
+ focusScopeNode: topNode,
+ child: Column(
+ children: <Widget>[
+ FocusScope.withExternalFocusNode(
+ focusScopeNode: parentNode,
+ child: const SizedBox(),
+ ),
+ FocusScope.withExternalFocusNode(
+ focusScopeNode: childNode,
+ parentNode: parentNode,
+ child: const Focus(
+ autofocus: true,
+ child: SizedBox(),
),
- FocusScope.withExternalFocusNode(
- focusScopeNode: childNode,
- parentNode: parentNode,
- child: const Focus(
- autofocus: true,
- child: SizedBox(),
- ),
- )
- ],
- ),
+ )
+ ],
),
+ ),
);
await tester.pump();
@@ -568,27 +568,27 @@
// Check that inserting a Focus in between doesn't reparent the child.
await tester.pumpWidget(
FocusScope.withExternalFocusNode(
- focusScopeNode: topNode,
- child: Column(
- children: <Widget>[
- FocusScope.withExternalFocusNode(
- focusScopeNode: parentNode,
- child: const SizedBox(),
- ),
- FocusScope.withExternalFocusNode(
- focusScopeNode: insertedNode,
- child: FocusScope.withExternalFocusNode(
- focusScopeNode: childNode,
- parentNode: parentNode,
- child: const Focus(
+ focusScopeNode: topNode,
+ child: Column(
+ children: <Widget>[
+ FocusScope.withExternalFocusNode(
+ focusScopeNode: parentNode,
+ child: const SizedBox(),
+ ),
+ FocusScope.withExternalFocusNode(
+ focusScopeNode: insertedNode,
+ child: FocusScope.withExternalFocusNode(
+ focusScopeNode: childNode,
+ parentNode: parentNode,
+ child: const Focus(
autofocus: true,
child: SizedBox(),
),
- ),
- )
- ],
- ),
+ ),
+ )
+ ],
),
+ ),
);
await tester.pump();
@@ -1673,6 +1673,7 @@
await pumpTest(traverseScope1: true);
expect(scope1.traversalDescendants, equals(<FocusNode>[focus2, focus1, scope2]));
});
+
testWidgets('descendantsAreFocusable works as expected.', (WidgetTester tester) async {
final GlobalKey key1 = GlobalKey(debugLabel: '1');
final GlobalKey key2 = GlobalKey(debugLabel: '2');
@@ -1756,13 +1757,11 @@
final GlobalKey key1 = GlobalKey(debugLabel: '1');
final FocusNode focusNode = FocusNode();
bool? keyEventHandled;
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyCallback handleCallback = (FocusNode node, RawKeyEvent event) {
+ KeyEventResult handleCallback(FocusNode node, RawKeyEvent event) {
keyEventHandled = true;
return KeyEventResult.handled;
- };
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyCallback ignoreCallback = (FocusNode node, RawKeyEvent event) => KeyEventResult.ignored;
+ }
+ KeyEventResult ignoreCallback(FocusNode node, RawKeyEvent event) => KeyEventResult.ignored;
Focus focusWidget = Focus(
onKey: ignoreCallback, // This one does nothing.
focusNode: focusNode,
@@ -1807,13 +1806,11 @@
final GlobalKey key1 = GlobalKey(debugLabel: '1');
final FocusNode focusNode = FocusNode();
bool? keyEventHandled;
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyEventCallback handleEventCallback = (FocusNode node, KeyEvent event) {
+ KeyEventResult handleEventCallback(FocusNode node, KeyEvent event) {
keyEventHandled = true;
return KeyEventResult.handled;
- };
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyEventCallback ignoreEventCallback = (FocusNode node, KeyEvent event) => KeyEventResult.ignored;
+ }
+ KeyEventResult ignoreEventCallback(FocusNode node, KeyEvent event) => KeyEventResult.ignored;
Focus focusWidget = Focus(
onKeyEvent: ignoreEventCallback, // This one does nothing.
focusNode: focusNode,
@@ -1858,20 +1855,16 @@
final GlobalKey key1 = GlobalKey(debugLabel: '1');
final FocusNode focusNode = FocusNode();
bool? keyEventHandled;
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyCallback handleCallback = (FocusNode node, RawKeyEvent event) {
+ KeyEventResult handleCallback(FocusNode node, RawKeyEvent event) {
keyEventHandled = true;
return KeyEventResult.handled;
- };
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyEventCallback handleEventCallback = (FocusNode node, KeyEvent event) {
+ }
+ KeyEventResult handleEventCallback(FocusNode node, KeyEvent event) {
keyEventHandled = true;
return KeyEventResult.handled;
- };
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyCallback ignoreCallback = (FocusNode node, RawKeyEvent event) => KeyEventResult.ignored;
- // ignore: prefer_function_declarations_over_variables
- final FocusOnKeyEventCallback ignoreEventCallback = (FocusNode node, KeyEvent event) => KeyEventResult.ignored;
+ }
+ KeyEventResult ignoreCallback(FocusNode node, RawKeyEvent event) => KeyEventResult.ignored;
+ KeyEventResult ignoreEventCallback(FocusNode node, KeyEvent event) => KeyEventResult.ignored;
focusNode.onKey = ignoreCallback;
focusNode.onKeyEvent = ignoreEventCallback;
focusNode.descendantsAreFocusable = false;
@@ -1974,6 +1967,7 @@
expect(containerNode.hasFocus, isFalse);
expect(unfocusableNode.hasFocus, isFalse);
});
+
// Regression test for https://github.com/flutter/flutter/issues/61700
testWidgets("ExcludeFocus doesn't transfer focus to another descendant.", (WidgetTester tester) async {
final FocusNode parentFocusNode = FocusNode(debugLabel: 'group');
diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart
index 99979c4..30494f2 100644
--- a/packages/flutter/test/widgets/focus_traversal_test.dart
+++ b/packages/flutter/test/widgets/focus_traversal_test.dart
@@ -2153,6 +2153,7 @@
expect(events.length, 2);
}, variant: KeySimulatorTransitModeVariant.all());
});
+
group(FocusTraversalGroup, () {
testWidgets("Focus traversal group doesn't introduce a Semantics node", (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
@@ -2381,11 +2382,11 @@
final SemanticsTester semantics = SemanticsTester(tester);
final FocusNode focusNode = FocusNode();
await tester.pumpWidget(
- RawKeyboardListener(
- focusNode: focusNode,
- includeSemantics: false,
- child: Container(),
- ),
+ RawKeyboardListener(
+ focusNode: focusNode,
+ includeSemantics: false,
+ child: Container(),
+ ),
);
final TestSemantics expectedSemantics = TestSemantics.root();
expect(semantics, hasSemantics(expectedSemantics));
diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart
index 4c314c1..1075354 100644
--- a/packages/flutter/test/widgets/shortcuts_test.dart
+++ b/packages/flutter/test/widgets/shortcuts_test.dart
@@ -72,6 +72,7 @@
}),
);
});
+
test('LogicalKeySet works as a map key.', () {
final LogicalKeySet set1 = LogicalKeySet(LogicalKeyboardKey.keyA);
final LogicalKeySet set2 = LogicalKeySet(
@@ -109,6 +110,7 @@
})),
);
});
+
testWidgets('handles two keys', (WidgetTester tester) async {
int invoked = 0;
await tester.pumpWidget(activatorTester(
@@ -537,6 +539,7 @@
expect(shortcuts.shortcuts, isNotNull);
expect(shortcuts.shortcuts, isEmpty);
});
+
testWidgets('Default constructed Shortcuts.manager has empty shortcuts', (WidgetTester tester) async {
final ShortcutManager manager = ShortcutManager();
expect(manager.shortcuts, isNotNull);
@@ -546,9 +549,10 @@
expect(shortcuts.shortcuts, isNotNull);
expect(shortcuts.shortcuts, isEmpty);
});
+
testWidgets('Shortcuts.manager passes on shortcuts', (WidgetTester tester) async {
final Map<LogicalKeySet, Intent> testShortcuts = <LogicalKeySet, Intent>{
- LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(),
+ LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(),
};
final ShortcutManager manager = ShortcutManager(shortcuts: testShortcuts);
expect(manager.shortcuts, isNotNull);
@@ -558,6 +562,7 @@
expect(shortcuts.shortcuts, isNotNull);
expect(shortcuts.shortcuts, equals(testShortcuts));
});
+
testWidgets('ShortcutManager handles shortcuts', (WidgetTester tester) async {
final GlobalKey containerKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -592,6 +597,7 @@
expect(invoked, isTrue);
expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.shiftLeft]));
});
+
testWidgets('Shortcuts.manager lets manager handle shortcuts', (WidgetTester tester) async {
final GlobalKey containerKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -633,6 +639,7 @@
expect(shortcutsSet, isFalse);
expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.shiftLeft]));
});
+
testWidgets('ShortcutManager ignores key presses with no primary focus', (WidgetTester tester) async {
final GlobalKey containerKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -665,6 +672,7 @@
expect(invoked, isFalse);
expect(pressedKeys, isEmpty);
});
+
testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async {
final GlobalKey containerKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -704,6 +712,7 @@
expect(invoked, isTrue);
expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.shiftLeft]));
});
+
testWidgets('Shortcuts can disable a shortcut with Intent.doNothing', (WidgetTester tester) async {
final GlobalKey containerKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -745,6 +754,7 @@
expect(invoked, isFalse);
expect(pressedKeys, isEmpty);
});
+
testWidgets("Shortcuts that aren't bound to an action don't absorb keys meant for text fields", (WidgetTester tester) async {
final GlobalKey textFieldKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -769,6 +779,7 @@
expect(handled, isFalse);
expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.keyA]));
});
+
testWidgets('Shortcuts that are bound to an action do override text fields', (WidgetTester tester) async {
final GlobalKey textFieldKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -805,6 +816,7 @@
expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.keyA]));
expect(invoked, isTrue);
});
+
testWidgets('Shortcuts can override intents that apply to text fields', (WidgetTester tester) async {
final GlobalKey textFieldKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -845,6 +857,7 @@
expect(result, isFalse);
expect(invoked, isFalse);
});
+
testWidgets('Shortcuts can override intents that apply to text fields with DoNothingAndStopPropagationIntent', (WidgetTester tester) async {
final GlobalKey textFieldKey = GlobalKey();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -885,6 +898,7 @@
expect(result, isFalse);
expect(invoked, isFalse);
});
+
test('Shortcuts diagnostics work.', () {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
@@ -914,6 +928,7 @@
),
);
});
+
test('Shortcuts diagnostics work when debugLabel specified.', () {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
@@ -935,6 +950,7 @@
expect(description.length, equals(1));
expect(description[0], equals('shortcuts: <Debug Label>'));
});
+
test('Shortcuts diagnostics work when manager not specified.', () {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
@@ -955,6 +971,7 @@
expect(description.length, equals(1));
expect(description[0], equalsIgnoringHashCodes('shortcuts: {{Key A + Key B}: ActivateIntent#00000}'));
});
+
test('Shortcuts diagnostics work when manager specified.', () {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[];
@@ -981,6 +998,7 @@
expect(description[0], equalsIgnoringHashCodes('manager: TestShortcutManager#00000(shortcuts: {LogicalKeySet#00000(keys: Key A + Key B): ActivateIntent#00000})'));
expect(description[1], equalsIgnoringHashCodes('shortcuts: {{Key A + Key B}: ActivateIntent#00000}'));
});
+
testWidgets('Shortcuts support multiple intents', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
bool? value = true;
@@ -1952,11 +1970,11 @@
}
Widget activatorTester(
- ShortcutActivator activator,
- ValueSetter<Intent> onInvoke, [
- ShortcutActivator? activator2,
- ValueSetter<Intent>? onInvoke2,
- ]) {
+ ShortcutActivator activator,
+ ValueSetter<Intent> onInvoke, [
+ ShortcutActivator? activator2,
+ ValueSetter<Intent>? onInvoke2,
+]) {
final bool hasSecond = activator2 != null && onInvoke2 != null;
return Actions(
key: GlobalKey(),