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