Skip to content

Commit

Permalink
Add convenience accessor for primaryFocus (flutter#43859)
Browse files Browse the repository at this point in the history
This adds accessors for WidgetsBinding.instance.focusManager and WidgetsBinding.instance.focusManager.primaryFocus so that they can be more easily found in IDEs and accessed.

This adds a top level getter for WidgetsBinding.instance.focusManager.primaryFocus called primaryFocus, and a static accessor FocusManager.instance that returns WidgetsBinding.instance.focusManager.
  • Loading branch information
gspencergoog authored and Inconnu08 committed Nov 5, 2019
1 parent ac7edbf commit abafca9
Show file tree
Hide file tree
Showing 15 changed files with 78 additions and 68 deletions.
10 changes: 5 additions & 5 deletions dev/manual_tests/lib/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class UndoableActionDispatcher extends ActionDispatcher implements Listenable {
bool get canUndo {
if (_completedActions.isNotEmpty) {
final Intent lastIntent = _completedActions.last.invocationIntent;
return lastIntent.isEnabled(WidgetsBinding.instance.focusManager.primaryFocus.context);
return lastIntent.isEnabled(primaryFocus.context);
}
return false;
}
Expand All @@ -110,7 +110,7 @@ class UndoableActionDispatcher extends ActionDispatcher implements Listenable {
bool get canRedo {
if (_undoneActions.isNotEmpty) {
final Intent lastIntent = _undoneActions.last.invocationIntent;
return lastIntent.isEnabled(WidgetsBinding.instance.focusManager.primaryFocus?.context);
return lastIntent.isEnabled(primaryFocus?.context);
}
return false;
}
Expand Down Expand Up @@ -255,14 +255,14 @@ class UndoableFocusActionBase extends UndoableAction {
@override
void invoke(FocusNode node, Intent intent) {
super.invoke(node, intent);
_previousFocus = WidgetsBinding.instance.focusManager.primaryFocus;
_previousFocus = primaryFocus;
node.requestFocus();
}

@override
void undo() {
if (_previousFocus == null) {
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
primaryFocus?.unfocus();
return;
}
if (_previousFocus is FocusScopeNode) {
Expand All @@ -272,7 +272,7 @@ class UndoableFocusActionBase extends UndoableAction {

// Unfocus the current node to remove it from the focused child list of
// the scope.
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
primaryFocus?.unfocus();
// and then let the scope node be focused...
}
_previousFocus.requestFocus();
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter/lib/src/material/checkbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin {
SelectAction.key: _createAction,
if (!kIsWeb) ActivateAction.key: _createAction,
};
_updateHighlightMode(WidgetsBinding.instance.focusManager.highlightMode);
WidgetsBinding.instance.focusManager.addHighlightModeListener(_handleFocusHighlightModeChange);
_updateHighlightMode(FocusManager.instance.highlightMode);
FocusManager.instance.addHighlightModeListener(_handleFocusHighlightModeChange);
}

void _actionHandler(FocusNode node, Intent intent){
Expand Down Expand Up @@ -198,7 +198,7 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin {
}

void _updateHighlightMode(FocusHighlightMode mode) {
switch (WidgetsBinding.instance.focusManager.highlightMode) {
switch (FocusManager.instance.highlightMode) {
case FocusHighlightMode.touch:
_showHighlight = false;
break;
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter/lib/src/material/ink_well.dart
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe
SelectAction.key: _createAction,
if (!kIsWeb) ActivateAction.key: _createAction,
};
WidgetsBinding.instance.focusManager.addHighlightModeListener(_handleFocusHighlightModeChange);
FocusManager.instance.addHighlightModeListener(_handleFocusHighlightModeChange);
}

@override
Expand All @@ -522,7 +522,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe

@override
void dispose() {
WidgetsBinding.instance.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChange);
FocusManager.instance.removeHighlightModeListener(_handleFocusHighlightModeChange);
super.dispose();
}

Expand Down Expand Up @@ -650,7 +650,7 @@ class _InkResponseState<T extends InkResponse> extends State<T> with AutomaticKe

void _updateFocusHighlights() {
bool showFocus;
switch (WidgetsBinding.instance.focusManager.highlightMode) {
switch (FocusManager.instance.highlightMode) {
case FocusHighlightMode.touch:
showFocus = false;
break;
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter/lib/src/material/radio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin {
SelectAction.key: _createAction,
if (!kIsWeb) ActivateAction.key: _createAction,
};
_updateHighlightMode(WidgetsBinding.instance.focusManager.highlightMode);
WidgetsBinding.instance.focusManager.addHighlightModeListener(_handleFocusHighlightModeChange);
_updateHighlightMode(FocusManager.instance.highlightMode);
FocusManager.instance.addHighlightModeListener(_handleFocusHighlightModeChange);
}

void _actionHandler(FocusNode node, Intent intent){
Expand All @@ -216,7 +216,7 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin {
}

void _updateHighlightMode(FocusHighlightMode mode) {
switch (WidgetsBinding.instance.focusManager.highlightMode) {
switch (FocusManager.instance.highlightMode) {
case FocusHighlightMode.touch:
_showHighlight = false;
break;
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter/lib/src/material/switch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin {
SelectAction.key: _createAction,
if (!kIsWeb) ActivateAction.key: _createAction,
};
_updateHighlightMode(WidgetsBinding.instance.focusManager.highlightMode);
WidgetsBinding.instance.focusManager.addHighlightModeListener(_handleFocusHighlightModeChange);
_updateHighlightMode(FocusManager.instance.highlightMode);
FocusManager.instance.addHighlightModeListener(_handleFocusHighlightModeChange);
}

void _actionHandler(FocusNode node, Intent intent){
Expand All @@ -243,7 +243,7 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin {
}

void _updateHighlightMode(FocusHighlightMode mode) {
switch (WidgetsBinding.instance.focusManager.highlightMode) {
switch (FocusManager.instance.highlightMode) {
case FocusHighlightMode.touch:
_showHighlight = false;
break;
Expand Down
3 changes: 1 addition & 2 deletions packages/flutter/lib/src/widgets/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import 'package:flutter/foundation.dart';

import 'binding.dart';
import 'focus_manager.dart';
import 'framework.dart';

Expand Down Expand Up @@ -153,7 +152,7 @@ class ActionDispatcher extends Diagnosticable {
bool invokeAction(Action action, Intent intent, {FocusNode focusNode}) {
assert(action != null);
assert(intent != null);
focusNode ??= WidgetsBinding.instance.focusManager.primaryFocus;
focusNode ??= primaryFocus;
if (action != null && intent.isEnabled(focusNode.context)) {
action.invoke(focusNode, intent);
return true;
Expand Down
34 changes: 24 additions & 10 deletions packages/flutter/lib/src/widgets/focus_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
bool get hasPrimaryFocus => _manager?.primaryFocus == this;

/// Returns the [FocusHighlightMode] that is currently in effect for this node.
FocusHighlightMode get highlightMode => WidgetsBinding.instance.focusManager.highlightMode;
FocusHighlightMode get highlightMode => FocusManager.instance.highlightMode;

/// Returns the nearest enclosing scope node above this node, including
/// this node, if it's a scope.
Expand Down Expand Up @@ -1111,15 +1111,18 @@ enum FocusHighlightStrategy {
/// focus.
///
/// The [FocusManager] is held by the [WidgetsBinding] as
/// [WidgetsBinding.focusManager]. The [FocusManager] is rarely accessed
/// directly. Instead, to find the [FocusScopeNode] for a given [BuildContext],
/// use [FocusScope.of].
/// [WidgetsBinding.focusManager], and can be conveniently accessed using the
/// [focusManager] global accessor.
///
/// To find the [FocusScopeNode] for a given [BuildContext], use
/// [FocusScope.of].
///
/// The [FocusManager] knows nothing about [FocusNode]s other than the one that
/// is currently focused. If a [FocusScopeNode] is removed, then the
/// [FocusManager] will attempt to focus the next [FocusScopeNode] in the focus
/// tree that it maintains, but if the current focus in that [FocusScopeNode] is
/// null, it will stop there, and no [FocusNode] will have focus.
/// is currently focused (accessible via the [primaryFocus] global accessor). If
/// a [FocusScopeNode] is removed, then the [FocusManager] will attempt to focus
/// the next [FocusScopeNode] in the focus tree that it maintains, but if the
/// current focus in that [FocusScopeNode] is null, it will stop there, and no
/// [FocusNode] will have focus.
///
/// See also:
///
Expand All @@ -1130,17 +1133,24 @@ enum FocusHighlightStrategy {
/// [BuildContext].
/// * [FocusScope.of], which provides the nearest ancestor [FocusScopeNode] for
/// a given [BuildContext].
/// * The [focusManager] and [primaryFocus] global accessors, for convenient
/// access from anywhere to the current focus manager state.
class FocusManager with DiagnosticableTreeMixin {
/// Creates an object that manages the focus tree.
///
/// This constructor is rarely called directly. To access the [FocusManager],
/// consider using [WidgetsBinding.focusManager] instead.
/// consider using the [focusManager] accessor instead (which gets it from the
/// [WidgetsBinding] singleton).
FocusManager() {
rootScope._manager = this;
RawKeyboard.instance.addListener(_handleRawKeyEvent);
GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent);
}

/// Provides convenient access to the current [FocusManager] singleton from
/// the [WidgetsBinding] instance.
static FocusManager get instance => WidgetsBinding.instance.focusManager;

bool _lastInteractionWasTouch = true;

/// Sets the strategy by which [highlightMode] is determined.
Expand Down Expand Up @@ -1418,6 +1428,10 @@ class FocusManager with DiagnosticableTreeMixin {
}
}

/// Provides convenient access to the current [FocusManager.primaryFocus] from the
/// [WidgetsBinding] instance.
FocusNode get primaryFocus => WidgetsBinding.instance.focusManager.primaryFocus;

/// Returns a text representation of the current focus tree, along with the
/// current attributes on each node.
///
Expand All @@ -1426,7 +1440,7 @@ String debugDescribeFocusTree() {
assert(WidgetsBinding.instance != null);
String result;
assert(() {
result = WidgetsBinding.instance.focusManager.toStringDeep();
result = FocusManager.instance.toStringDeep();
return true;
}());
return result ?? '';
Expand Down
5 changes: 2 additions & 3 deletions packages/flutter/lib/src/widgets/focus_traversal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'package:flutter/painting.dart';

import 'actions.dart';
import 'basic.dart';
import 'binding.dart';
import 'editable_text.dart';
import 'focus_manager.dart';
import 'framework.dart';
Expand Down Expand Up @@ -623,7 +622,7 @@ class ReadingOrderTraversalPolicy extends FocusTraversalPolicy with DirectionalF
// If we still didn't find any candidate, use the current node as a
// fallback.
candidate ??= currentNode;
candidate ??= WidgetsBinding.instance.focusManager.rootScope;
candidate ??= FocusManager.instance.rootScope;
return candidate;
}

Expand Down Expand Up @@ -807,7 +806,7 @@ class _RequestFocusActionBase extends Action {

@override
void invoke(FocusNode node, Intent intent) {
_previousFocus = WidgetsBinding.instance.focusManager.primaryFocus;
_previousFocus = primaryFocus;
node.requestFocus();
}

Expand Down
3 changes: 1 addition & 2 deletions packages/flutter/lib/src/widgets/shortcuts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

import 'actions.dart';
import 'binding.dart';
import 'focus_manager.dart';
import 'focus_scope.dart';
import 'framework.dart';
Expand Down Expand Up @@ -209,7 +208,7 @@ class ShortcutManager extends ChangeNotifier with DiagnosticableMixin {
matchedIntent = _shortcuts[LogicalKeySet.fromSet(pseudoKeys)];
}
if (matchedIntent != null) {
final BuildContext primaryContext = WidgetsBinding.instance.focusManager.primaryFocus?.context;
final BuildContext primaryContext = primaryFocus?.context;
if (primaryContext == null) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter/test/material/buttons_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ void main() {
),
);

WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
focusNode.requestFocus();
await tester.pumpAndSettle();

Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/test/material/ink_well_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ void main() {
});

testWidgets('ink response changes color on focus', (WidgetTester tester) async {
WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus');
await tester.pumpWidget(
Material(
Expand Down Expand Up @@ -156,7 +156,7 @@ void main() {
});

testWidgets("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async {
WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTouch;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch;
final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus');
await tester.pumpWidget(Material(
child: Directionality(
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/test/material/material_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void main() {
),
);

WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
focusNode.requestFocus();
await tester.pumpAndSettle();

Expand Down Expand Up @@ -174,7 +174,7 @@ void main() {
),
);
await tester.pumpAndSettle();
WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;

// Base elevation
Material material = tester.widget<Material>(rawButtonMaterial);
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/test/material/raw_material_button_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ void main() {
const Key key = Key('test');
const Color focusColor = Color(0xff00ff00);

WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
await tester.pumpWidget(
MaterialApp(
home: Center(
Expand Down Expand Up @@ -410,7 +410,7 @@ void main() {
const Key key = Key('test');
const Color hoverColor = Color(0xff00ff00);

WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
await tester.pumpWidget(
MaterialApp(
home: Center(
Expand Down
25 changes: 12 additions & 13 deletions packages/flutter/test/widgets/focus_manager_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -585,39 +585,38 @@ void main() {
callCount++;
}

final FocusManager focusManager = WidgetsBinding.instance.focusManager;
focusManager.addHighlightModeListener(handleModeChange);
addTearDown(() => focusManager.removeHighlightModeListener(handleModeChange));
FocusManager.instance.addHighlightModeListener(handleModeChange);
addTearDown(() => FocusManager.instance.removeHighlightModeListener(handleModeChange));
expect(callCount, equals(0));
expect(lastMode, isNull);
focusManager.highlightStrategy = FocusHighlightStrategy.automatic;
expect(focusManager.highlightMode, equals(FocusHighlightMode.touch));
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.automatic;
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.touch));
await tester.sendKeyEvent(LogicalKeyboardKey.metaLeft, platform: 'fuchsia');
expect(callCount, equals(1));
expect(lastMode, FocusHighlightMode.traditional);
expect(focusManager.highlightMode, equals(FocusHighlightMode.traditional));
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional));
await tester.tap(find.byType(Container));
expect(callCount, equals(2));
expect(lastMode, FocusHighlightMode.touch);
expect(focusManager.highlightMode, equals(FocusHighlightMode.touch));
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.touch));
final TestGesture gesture = await tester.startGesture(Offset.zero, kind: PointerDeviceKind.mouse);
addTearDown(gesture.removePointer);
await gesture.up();
expect(callCount, equals(3));
expect(lastMode, FocusHighlightMode.traditional);
expect(focusManager.highlightMode, equals(FocusHighlightMode.traditional));
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional));
await tester.tap(find.byType(Container));
expect(callCount, equals(4));
expect(lastMode, FocusHighlightMode.touch);
expect(focusManager.highlightMode, equals(FocusHighlightMode.touch));
focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.touch));
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
expect(callCount, equals(5));
expect(lastMode, FocusHighlightMode.traditional);
expect(focusManager.highlightMode, equals(FocusHighlightMode.traditional));
focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTouch;
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional));
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch;
expect(callCount, equals(6));
expect(lastMode, FocusHighlightMode.touch);
expect(focusManager.highlightMode, equals(FocusHighlightMode.touch));
expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.touch));
});
testWidgets('implements debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
Expand Down
Loading

0 comments on commit abafca9

Please sign in to comment.