Unverified Commit 08e61631 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Allow Navigator to inherit traversal policy from parent. (#110818)

parent 8f9a5195
...@@ -5235,6 +5235,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -5235,6 +5235,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
child: AbsorbPointer( child: AbsorbPointer(
absorbing: false, // it's mutated directly by _cancelActivePointers above absorbing: false, // it's mutated directly by _cancelActivePointers above
child: FocusTraversalGroup( child: FocusTraversalGroup(
policy: FocusTraversalGroup.maybeOf(context),
child: Focus( child: Focus(
focusNode: focusNode, focusNode: focusNode,
autofocus: true, autofocus: true,
......
...@@ -3775,72 +3775,71 @@ void main() { ...@@ -3775,72 +3775,71 @@ void main() {
expect(focusNode.hasFocus, true); expect(focusNode.hasFocus, true);
}); });
testWidgets('Navigator does not request focus if requestFocus is false', testWidgets('Navigator does not request focus if requestFocus is false', (WidgetTester tester) async {
(WidgetTester tester) async { final GlobalKey navigatorKey = GlobalKey();
final GlobalKey navigatorKey = GlobalKey(); final GlobalKey innerKey = GlobalKey();
final GlobalKey innerKey = GlobalKey(); final Map<String, Widget> routes = <String, Widget>{
final Map<String, Widget> routes = <String, Widget>{ '/': const Text('A'),
'/': const Text('A'), '/second': Text('B', key: innerKey),
'/second': Text('B', key: innerKey), };
}; late final NavigatorState navigator =
late final NavigatorState navigator = navigatorKey.currentState! as NavigatorState;
navigatorKey.currentState! as NavigatorState; final FocusScopeNode focusNode = FocusScopeNode();
final FocusScopeNode focusNode = FocusScopeNode();
await tester.pumpWidget(Column( await tester.pumpWidget(Column(
children: <Widget>[ children: <Widget>[
FocusScope(node: focusNode, child: Container()), FocusScope(node: focusNode, child: Container()),
Expanded( Expanded(
child: MaterialApp( child: MaterialApp(
home: Navigator( home: Navigator(
key: navigatorKey, key: navigatorKey,
onGenerateRoute: (RouteSettings settings) { onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<void>( return PageRouteBuilder<void>(
settings: settings, settings: settings,
pageBuilder: (BuildContext _, Animation<double> __, pageBuilder: (BuildContext _, Animation<double> __,
Animation<double> ___) { Animation<double> ___) {
return routes[settings.name!]!; return routes[settings.name!]!;
},
);
}, },
requestFocus: false, );
), },
), requestFocus: false,
), ),
], ),
)); ),
expect(find.text('A'), findsOneWidget); ],
expect(find.text('B', skipOffstage: false), findsNothing); ));
expect(focusNode.hasFocus, false); expect(find.text('A'), findsOneWidget);
expect(find.text('B', skipOffstage: false), findsNothing);
focusNode.requestFocus(); expect(focusNode.hasFocus, false);
await tester.pumpAndSettle();
expect(focusNode.hasFocus, true); focusNode.requestFocus();
await tester.pumpAndSettle();
navigator.pushNamed('/second'); expect(focusNode.hasFocus, true);
await tester.pumpAndSettle();
expect(find.text('A', skipOffstage: false), findsOneWidget); navigator.pushNamed('/second');
expect(find.text('B'), findsOneWidget); await tester.pumpAndSettle();
expect(focusNode.hasFocus, true); expect(find.text('A', skipOffstage: false), findsOneWidget);
expect(find.text('B'), findsOneWidget);
navigator.pop(); expect(focusNode.hasFocus, true);
await tester.pumpAndSettle();
expect(find.text('A'), findsOneWidget); navigator.pop();
expect(find.text('B', skipOffstage: false), findsNothing); await tester.pumpAndSettle();
expect(focusNode.hasFocus, true); expect(find.text('A'), findsOneWidget);
expect(find.text('B', skipOffstage: false), findsNothing);
navigator.pushReplacementNamed('/second'); expect(focusNode.hasFocus, true);
await tester.pumpAndSettle();
expect(find.text('A', skipOffstage: false), findsNothing); navigator.pushReplacementNamed('/second');
expect(find.text('B'), findsOneWidget); await tester.pumpAndSettle();
expect(focusNode.hasFocus, true); expect(find.text('A', skipOffstage: false), findsNothing);
expect(find.text('B'), findsOneWidget);
ModalRoute.of(innerKey.currentContext!)!.addLocalHistoryEntry( expect(focusNode.hasFocus, true);
LocalHistoryEntry(),
); ModalRoute.of(innerKey.currentContext!)!.addLocalHistoryEntry(
await tester.pumpAndSettle(); LocalHistoryEntry(),
expect(focusNode.hasFocus, true); );
}); await tester.pumpAndSettle();
expect(focusNode.hasFocus, true);
});
testWidgets('class implementing NavigatorObserver can be used without problems', (WidgetTester tester) async { testWidgets('class implementing NavigatorObserver can be used without problems', (WidgetTester tester) async {
final _MockNavigatorObserver observer = _MockNavigatorObserver(); final _MockNavigatorObserver observer = _MockNavigatorObserver();
...@@ -3873,6 +3872,49 @@ void main() { ...@@ -3873,6 +3872,49 @@ void main() {
await tester.pumpWidget(Container(child: build(key))); await tester.pumpWidget(Container(child: build(key)));
observer._checkInvocations(<Symbol>[#navigator, #navigator]); observer._checkInvocations(<Symbol>[#navigator, #navigator]);
}); });
testWidgets("Navigator doesn't override FocusTraversalPolicy of ancestors", (WidgetTester tester) async {
FocusTraversalPolicy? policy;
await tester.pumpWidget(
TestDependencies(
child: FocusTraversalGroup(
policy: WidgetOrderTraversalPolicy(),
child: Navigator(
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<void>(
settings: settings,
pageBuilder: (BuildContext context, Animation<double> __, Animation<double> ___) {
policy = FocusTraversalGroup.of(context);
return const SizedBox();
},
);
},
),
),
),
);
expect(policy, isA<WidgetOrderTraversalPolicy>());
});
testWidgets('Navigator inserts ReadingOrderTraversalPolicy if no ancestor has a policy', (WidgetTester tester) async {
FocusTraversalPolicy? policy;
await tester.pumpWidget(
TestDependencies(
child: Navigator(
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<void>(
settings: settings,
pageBuilder: (BuildContext context, Animation<double> __, Animation<double> ___) {
policy = FocusTraversalGroup.of(context);
return const SizedBox();
},
);
},
),
),
);
expect(policy, isA<ReadingOrderTraversalPolicy>());
});
} }
typedef AnnouncementCallBack = void Function(Route<dynamic>?); typedef AnnouncementCallBack = void Function(Route<dynamic>?);
......
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