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,7 +1626,10 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { ...@@ -1625,7 +1626,10 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
); );
} else if (_usesNavigator) { } else if (_usesNavigator) {
assert(_navigator != null); assert(_navigator != null);
routing = Navigator( routing = FocusScope(
debugLabel: 'Navigator Scope',
autofocus: true,
child: Navigator(
restorationScopeId: 'nav', restorationScopeId: 'nav',
key: _navigator, key: _navigator,
initialRoute: _initialRouteName, initialRoute: _initialRouteName,
...@@ -1638,6 +1642,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { ...@@ -1638,6 +1642,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
onUnknownRoute: _onUnknownRoute, onUnknownRoute: _onUnknownRoute,
observers: widget.navigatorObservers!, observers: widget.navigatorObservers!,
reportsRouteUpdateToEngine: true, 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,9 +5234,12 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -5226,9 +5234,12 @@ 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(
focusNode: focusNode,
autofocus: true, autofocus: true,
skipTraversal: true,
includeSemantics: false,
child: UnmanagedRestorationScope( child: UnmanagedRestorationScope(
bucket: bucket, bucket: bucket,
child: Overlay( child: Overlay(
...@@ -5239,6 +5250,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -5239,6 +5250,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
), ),
), ),
), ),
),
); );
} }
} }
......
...@@ -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'
......
...@@ -1324,8 +1324,6 @@ void main() { ...@@ -1324,8 +1324,6 @@ void main() {
expect(semantics, hasSemantics(TestSemantics.root( expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics.rootChild( TestSemantics.rootChild(
children: <TestSemantics>[
TestSemantics(
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics( TestSemantics(
flags: <SemanticsFlag>[ flags: <SemanticsFlag>[
...@@ -1380,9 +1378,6 @@ void main() { ...@@ -1380,9 +1378,6 @@ void main() {
), ),
], ],
), ),
TestSemantics(),
],
),
], ],
), ignoreId: true, ignoreRect: true, ignoreTransform: true)); ), ignoreId: true, ignoreRect: true, ignoreTransform: true));
semantics.dispose(); semantics.dispose();
......
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