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';
import 'basic.dart';
import 'binding.dart';
import 'default_text_editing_shortcuts.dart';
import 'focus_scope.dart';
import 'focus_traversal.dart';
import 'framework.dart';
import 'localizations.dart';
......@@ -1625,7 +1626,10 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
);
} else if (_usesNavigator) {
assert(_navigator != null);
routing = Navigator(
routing = FocusScope(
debugLabel: 'Navigator Scope',
autofocus: true,
child: Navigator(
restorationScopeId: 'nav',
key: _navigator,
initialRoute: _initialRouteName,
......@@ -1638,6 +1642,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
onUnknownRoute: _onUnknownRoute,
observers: widget.navigatorObservers!,
reportsRouteUpdateToEngine: true,
),
);
} else if (_usesRouterWithConfig) {
routing = Router<Object>.withConfig(
......
......@@ -17,6 +17,7 @@ import 'basic.dart';
import 'binding.dart';
import 'focus_manager.dart';
import 'focus_scope.dart';
import 'focus_traversal.dart';
import 'framework.dart';
import 'heroes.dart';
import 'overlay.dart';
......@@ -217,7 +218,7 @@ abstract class Route<T> {
TickerFuture didPush() {
return TickerFuture.complete()..then<void>((void _) {
if (navigator?.widget.requestFocus ?? false) {
navigator!.focusScopeNode.requestFocus();
navigator!.focusNode.enclosingScope?.requestFocus();
}
});
}
......@@ -233,11 +234,11 @@ abstract class Route<T> {
@mustCallSuper
void didAdd() {
if (navigator?.widget.requestFocus ?? false) {
// This TickerFuture serves two purposes. First, we want to make sure
// that animations triggered by other operations will finish before focusing the
// navigator. Second, navigator.focusScopeNode might acquire more focused
// children in Route.install asynchronously. This TickerFuture will wait for
// it to finish first.
// This TickerFuture serves two purposes. First, we want to make sure that
// animations triggered by other operations will finish before focusing
// the navigator. Second, navigator.focusNode might acquire more focused
// children in Route.install asynchronously. This TickerFuture will wait
// for it to finish first.
//
// 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
......@@ -255,7 +256,7 @@ abstract class Route<T> {
// 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
// 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
final Queue<_NavigatorObservation> _observedRouteAdditions = Queue<_NavigatorObservation>();
final Queue<_NavigatorObservation> _observedRouteDeletions = Queue<_NavigatorObservation>();
/// The [FocusScopeNode] for the [FocusScope] that encloses the routes.
final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'Navigator Scope');
/// The [FocusScopeNode] for the [FocusScope] that encloses the topmost navigator.
@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
......@@ -3531,7 +3539,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
return true;
}());
_updateHeroController(null);
focusScopeNode.dispose();
focusNode.dispose();
for (final _RouteEntry entry in _history) {
entry.dispose();
}
......@@ -5226,9 +5234,12 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
onPointerCancel: _handlePointerUpOrCancel,
child: AbsorbPointer(
absorbing: false, // it's mutated directly by _cancelActivePointers above
child: FocusScope(
node: focusScopeNode,
child: FocusTraversalGroup(
child: Focus(
focusNode: focusNode,
autofocus: true,
skipTraversal: true,
includeSemantics: false,
child: UnmanagedRestorationScope(
bucket: bucket,
child: Overlay(
......@@ -5239,6 +5250,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
),
),
),
),
);
}
}
......
......@@ -819,7 +819,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
];
_listenable = Listenable.merge(animations);
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>> {
super.didUpdateWidget(oldWidget);
assert(widget.route == oldWidget.route);
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>> {
// and route.offstage.
void _routeSetState(VoidCallback fn) {
if (widget.route.isCurrent && !_shouldIgnoreFocusRequest && _shouldRequestFocus) {
widget.route.navigator!.focusScopeNode.setFirstFocus(focusScopeNode);
widget.route.navigator!.focusNode.enclosingScope?.setFirstFocus(focusScopeNode);
}
setState(fn);
}
......@@ -1213,7 +1213,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
@override
TickerFuture didPush() {
if (_scopeKey.currentState != null && navigator!.widget.requestFocus) {
navigator!.focusScopeNode.setFirstFocus(_scopeKey.currentState!.focusScopeNode);
navigator!.focusNode.enclosingScope?.setFirstFocus(_scopeKey.currentState!.focusScopeNode);
}
return super.didPush();
}
......@@ -1221,7 +1221,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
@override
void didAdd() {
if (_scopeKey.currentState != null && navigator!.widget.requestFocus) {
navigator!.focusScopeNode.setFirstFocus(_scopeKey.currentState!.focusScopeNode);
navigator!.focusNode.enclosingScope?.setFirstFocus(_scopeKey.currentState!.focusScopeNode);
}
super.didAdd();
}
......
......@@ -17,7 +17,7 @@ void main() {
log.add('build');
expect(Theme.of(context).primaryColor, Colors.green);
expect(Directionality.of(context), TextDirection.ltr);
expect(child, isA<Navigator>());
expect(child, isA<FocusScope>());
return const Placeholder();
},
);
......
......@@ -156,12 +156,18 @@ void main() {
' Overlay-[LabeledGlobalKey<OverlayState>#00000]\n'
' UnmanagedRestorationScope\n'
' _FocusMarker\n'
' Semantics\n'
' FocusScope\n'
' Focus\n'
' _FocusMarker\n'
' Focus\n'
' _FocusTraversalGroupMarker\n'
' FocusTraversalGroup\n'
' AbsorbPointer\n'
' Listener\n'
' HeroControllerScope\n'
' Navigator-[GlobalObjectKey<NavigatorState> _WidgetsAppState#00000]\n'
' _FocusMarker\n'
' Semantics\n'
' FocusScope\n'
' DefaultSelectionStyle\n'
' IconTheme\n'
' IconTheme\n'
......
......@@ -1324,8 +1324,6 @@ void main() {
expect(semantics, hasSemantics(TestSemantics.root(
children: <TestSemantics>[
TestSemantics.rootChild(
children: <TestSemantics>[
TestSemantics(
children: <TestSemantics>[
TestSemantics(
flags: <SemanticsFlag>[
......@@ -1380,9 +1378,6 @@ void main() {
),
],
),
TestSemantics(),
],
),
],
), ignoreId: true, ignoreRect: true, ignoreTransform: true));
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