Unverified Commit 77b41ba8 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Remove the FocusScopeNode in the navigator (#109702)

parent d4eaf01a
...@@ -13,6 +13,7 @@ import 'banner.dart'; ...@@ -13,6 +13,7 @@ import 'banner.dart';
import 'basic.dart'; import 'basic.dart';
import 'binding.dart'; import 'binding.dart';
import 'default_text_editing_shortcuts.dart'; import 'default_text_editing_shortcuts.dart';
import 'focus_scope.dart';
import 'focus_traversal.dart'; import 'focus_traversal.dart';
import 'framework.dart'; import 'framework.dart';
import 'localizations.dart'; import 'localizations.dart';
...@@ -1625,19 +1626,23 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { ...@@ -1625,19 +1626,23 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
); );
} else if (_usesNavigator) { } else if (_usesNavigator) {
assert(_navigator != null); assert(_navigator != null);
routing = Navigator( routing = FocusScope(
restorationScopeId: 'nav', debugLabel: 'Navigator Scope',
key: _navigator, autofocus: true,
initialRoute: _initialRouteName, child: Navigator(
onGenerateRoute: _onGenerateRoute, restorationScopeId: 'nav',
onGenerateInitialRoutes: widget.onGenerateInitialRoutes == null key: _navigator,
? Navigator.defaultGenerateInitialRoutes initialRoute: _initialRouteName,
: (NavigatorState navigator, String initialRouteName) { onGenerateRoute: _onGenerateRoute,
return widget.onGenerateInitialRoutes!(initialRouteName); onGenerateInitialRoutes: widget.onGenerateInitialRoutes == null
}, ? Navigator.defaultGenerateInitialRoutes
onUnknownRoute: _onUnknownRoute, : (NavigatorState navigator, String initialRouteName) {
observers: widget.navigatorObservers!, return widget.onGenerateInitialRoutes!(initialRouteName);
reportsRouteUpdateToEngine: true, },
onUnknownRoute: _onUnknownRoute,
observers: widget.navigatorObservers!,
reportsRouteUpdateToEngine: true,
),
); );
} else if (_usesRouterWithConfig) { } else if (_usesRouterWithConfig) {
routing = Router<Object>.withConfig( routing = Router<Object>.withConfig(
......
...@@ -17,6 +17,7 @@ import 'basic.dart'; ...@@ -17,6 +17,7 @@ import 'basic.dart';
import 'binding.dart'; import 'binding.dart';
import 'focus_manager.dart'; import 'focus_manager.dart';
import 'focus_scope.dart'; import 'focus_scope.dart';
import 'focus_traversal.dart';
import 'framework.dart'; import 'framework.dart';
import 'heroes.dart'; import 'heroes.dart';
import 'overlay.dart'; import 'overlay.dart';
...@@ -217,7 +218,7 @@ abstract class Route<T> { ...@@ -217,7 +218,7 @@ abstract class Route<T> {
TickerFuture didPush() { TickerFuture didPush() {
return TickerFuture.complete()..then<void>((void _) { return TickerFuture.complete()..then<void>((void _) {
if (navigator?.widget.requestFocus ?? false) { if (navigator?.widget.requestFocus ?? false) {
navigator!.focusScopeNode.requestFocus(); navigator!.focusNode.enclosingScope?.requestFocus();
} }
}); });
} }
...@@ -233,11 +234,11 @@ abstract class Route<T> { ...@@ -233,11 +234,11 @@ abstract class Route<T> {
@mustCallSuper @mustCallSuper
void didAdd() { void didAdd() {
if (navigator?.widget.requestFocus ?? false) { if (navigator?.widget.requestFocus ?? false) {
// This TickerFuture serves two purposes. First, we want to make sure // This TickerFuture serves two purposes. First, we want to make sure that
// that animations triggered by other operations will finish before focusing the // animations triggered by other operations will finish before focusing
// navigator. Second, navigator.focusScopeNode might acquire more focused // the navigator. Second, navigator.focusNode might acquire more focused
// children in Route.install asynchronously. This TickerFuture will wait for // children in Route.install asynchronously. This TickerFuture will wait
// it to finish first. // for it to finish first.
// //
// The later case can be found when subclasses manage their own focus scopes. // The later case can be found when subclasses manage their own focus scopes.
// For example, ModalRoute creates a focus scope in its overlay entries. The // For example, ModalRoute creates a focus scope in its overlay entries. The
...@@ -255,7 +256,7 @@ abstract class Route<T> { ...@@ -255,7 +256,7 @@ abstract class Route<T> {
// Since the reference to the navigator will be set to null after it is // Since the reference to the navigator will be set to null after it is
// disposed, we have to do a null-safe operation in case that happens // disposed, we have to do a null-safe operation in case that happens
// within the same frame when it is added. // within the same frame when it is added.
navigator?.focusScopeNode.requestFocus(); navigator?.focusNode.enclosingScope?.requestFocus();
}); });
} }
} }
...@@ -3207,8 +3208,15 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -3207,8 +3208,15 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
final Queue<_NavigatorObservation> _observedRouteAdditions = Queue<_NavigatorObservation>(); final Queue<_NavigatorObservation> _observedRouteAdditions = Queue<_NavigatorObservation>();
final Queue<_NavigatorObservation> _observedRouteDeletions = Queue<_NavigatorObservation>(); final Queue<_NavigatorObservation> _observedRouteDeletions = Queue<_NavigatorObservation>();
/// The [FocusScopeNode] for the [FocusScope] that encloses the routes. /// The [FocusScopeNode] for the [FocusScope] that encloses the topmost navigator.
final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'Navigator Scope'); @Deprecated(
'Use focusNode.enclosingScope! instead. '
'This feature was deprecated after v3.1.0-0.0.pre.'
)
FocusScopeNode get focusScopeNode => focusNode.enclosingScope!;
/// The [FocusNode] for the [Focus] that encloses the routes.
final FocusNode focusNode = FocusNode(debugLabel: 'Navigator');
bool _debugLocked = false; // used to prevent re-entrant calls to push, pop, and friends bool _debugLocked = false; // used to prevent re-entrant calls to push, pop, and friends
...@@ -3531,7 +3539,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -3531,7 +3539,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
return true; return true;
}()); }());
_updateHeroController(null); _updateHeroController(null);
focusScopeNode.dispose(); focusNode.dispose();
for (final _RouteEntry entry in _history) { for (final _RouteEntry entry in _history) {
entry.dispose(); entry.dispose();
} }
...@@ -5226,14 +5234,18 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -5226,14 +5234,18 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
onPointerCancel: _handlePointerUpOrCancel, onPointerCancel: _handlePointerUpOrCancel,
child: AbsorbPointer( child: AbsorbPointer(
absorbing: false, // it's mutated directly by _cancelActivePointers above absorbing: false, // it's mutated directly by _cancelActivePointers above
child: FocusScope( child: FocusTraversalGroup(
node: focusScopeNode, child: Focus(
autofocus: true, focusNode: focusNode,
child: UnmanagedRestorationScope( autofocus: true,
bucket: bucket, skipTraversal: true,
child: Overlay( includeSemantics: false,
key: _overlayKey, child: UnmanagedRestorationScope(
initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const <OverlayEntry>[], bucket: bucket,
child: Overlay(
key: _overlayKey,
initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const <OverlayEntry>[],
),
), ),
), ),
), ),
......
...@@ -819,7 +819,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> { ...@@ -819,7 +819,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
]; ];
_listenable = Listenable.merge(animations); _listenable = Listenable.merge(animations);
if (widget.route.isCurrent && _shouldRequestFocus) { if (widget.route.isCurrent && _shouldRequestFocus) {
widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode); widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode);
} }
} }
...@@ -828,7 +828,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> { ...@@ -828,7 +828,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
assert(widget.route == oldWidget.route); assert(widget.route == oldWidget.route);
if (widget.route.isCurrent && _shouldRequestFocus) { if (widget.route.isCurrent && _shouldRequestFocus) {
widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode); widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode);
} }
} }
...@@ -863,7 +863,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> { ...@@ -863,7 +863,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
// and route.offstage. // and route.offstage.
void _routeSetState(VoidCallback fn) { void _routeSetState(VoidCallback fn) {
if (widget.route.isCurrent && !_shouldIgnoreFocusRequest && _shouldRequestFocus) { if (widget.route.isCurrent && !_shouldIgnoreFocusRequest && _shouldRequestFocus) {
widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode); widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode);
} }
setState(fn); setState(fn);
} }
...@@ -1213,7 +1213,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -1213,7 +1213,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
@override @override
TickerFuture didPush() { TickerFuture didPush() {
if (_scopeKey.currentState != null && navigator!.widget.requestFocus) { if (_scopeKey.currentState != null && navigator!.widget.requestFocus) {
navigator!.focusScopeNode.setFirstFocus(_scopeKey.currentState!.focusScopeNode); navigator!.focusNode.enclosingScope?.setFirstFocus(_scopeKey.currentState!.focusScopeNode);
} }
return super.didPush(); return super.didPush();
} }
...@@ -1221,7 +1221,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ...@@ -1221,7 +1221,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
@override @override
void didAdd() { void didAdd() {
if (_scopeKey.currentState != null && navigator!.widget.requestFocus) { if (_scopeKey.currentState != null && navigator!.widget.requestFocus) {
navigator!.focusScopeNode.setFirstFocus(_scopeKey.currentState!.focusScopeNode); navigator!.focusNode.enclosingScope?.setFirstFocus(_scopeKey.currentState!.focusScopeNode);
} }
super.didAdd(); super.didAdd();
} }
......
...@@ -17,7 +17,7 @@ void main() { ...@@ -17,7 +17,7 @@ void main() {
log.add('build'); log.add('build');
expect(Theme.of(context).primaryColor, Colors.green); expect(Theme.of(context).primaryColor, Colors.green);
expect(Directionality.of(context), TextDirection.ltr); expect(Directionality.of(context), TextDirection.ltr);
expect(child, isA<Navigator>()); expect(child, isA<FocusScope>());
return const Placeholder(); return const Placeholder();
}, },
); );
......
...@@ -156,12 +156,18 @@ void main() { ...@@ -156,12 +156,18 @@ void main() {
' Overlay-[LabeledGlobalKey<OverlayState>#00000]\n' ' Overlay-[LabeledGlobalKey<OverlayState>#00000]\n'
' UnmanagedRestorationScope\n' ' UnmanagedRestorationScope\n'
' _FocusMarker\n' ' _FocusMarker\n'
' Semantics\n' ' Focus\n'
' FocusScope\n' ' _FocusMarker\n'
' Focus\n'
' _FocusTraversalGroupMarker\n'
' FocusTraversalGroup\n'
' AbsorbPointer\n' ' AbsorbPointer\n'
' Listener\n' ' Listener\n'
' HeroControllerScope\n' ' HeroControllerScope\n'
' Navigator-[GlobalObjectKey<NavigatorState> _WidgetsAppState#00000]\n' ' Navigator-[GlobalObjectKey<NavigatorState> _WidgetsAppState#00000]\n'
' _FocusMarker\n'
' Semantics\n'
' FocusScope\n'
' DefaultSelectionStyle\n' ' DefaultSelectionStyle\n'
' IconTheme\n' ' IconTheme\n'
' IconTheme\n' ' IconTheme\n'
......
...@@ -1326,53 +1326,49 @@ void main() { ...@@ -1326,53 +1326,49 @@ void main() {
TestSemantics.rootChild( TestSemantics.rootChild(
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics( TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.scopesRoute,
SemanticsFlag.namesRoute,
],
label: 'Popup menu',
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics( TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.scopesRoute,
SemanticsFlag.namesRoute,
],
label: 'Popup menu',
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics( TestSemantics(
flags: <SemanticsFlag>[
SemanticsFlag.hasImplicitScrolling,
],
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics( TestSemantics(
label: 'one',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[ flags: <SemanticsFlag>[
SemanticsFlag.hasImplicitScrolling, SemanticsFlag.isFocused,
], SemanticsFlag.isFocusable,
children: <TestSemantics>[
TestSemantics(
label: 'one',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[
SemanticsFlag.isFocused,
SemanticsFlag.isFocusable,
],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
TestSemantics(
label: 'two',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
TestSemantics(
label: 'three',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
TestSemantics(
label: 'four',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
], ],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
TestSemantics(
label: 'two',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
TestSemantics(
label: 'three',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
),
TestSemantics(
label: 'four',
textDirection: TextDirection.ltr,
flags: <SemanticsFlag>[SemanticsFlag.isFocusable],
tags: <SemanticsTag>[const SemanticsTag('RenderViewport.twoPane')],
actions: <SemanticsAction>[SemanticsAction.tap],
), ),
], ],
), ),
...@@ -1380,7 +1376,6 @@ void main() { ...@@ -1380,7 +1376,6 @@ void main() {
), ),
], ],
), ),
TestSemantics(),
], ],
), ),
], ],
......
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