fix route annoucement for first route and last route (#57339)

This commit is contained in:
chunhtai 2020-05-28 11:18:05 -07:00 committed by GitHub
parent e05a67f068
commit 7e2f555d1b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 3 deletions

View file

@ -2293,6 +2293,12 @@ enum _RouteLifecycle {
typedef _RouteEntryPredicate = bool Function(_RouteEntry entry);
class _NotAnnounced extends Route<void> {
// A placeholder for the lastAnnouncedPreviousRoute, the
// lastAnnouncedPoppedNextRoute, and the lastAnnouncedNextRoute before any
// change has been announced.
}
class _RouteEntry extends RouteTransitionRecord {
_RouteEntry(
this.route, {
@ -2311,10 +2317,12 @@ class _RouteEntry extends RouteTransitionRecord {
@override
final Route<dynamic> route;
static Route<dynamic> notAnnounced = _NotAnnounced();
_RouteLifecycle currentState;
Route<dynamic> lastAnnouncedPreviousRoute; // last argument to Route.didChangePrevious
Route<dynamic> lastAnnouncedPoppedNextRoute; // last argument to Route.didPopNext
Route<dynamic> lastAnnouncedNextRoute; // last argument to Route.didChangeNext
Route<dynamic> lastAnnouncedPreviousRoute = notAnnounced; // last argument to Route.didChangePrevious
Route<dynamic> lastAnnouncedPoppedNextRoute = notAnnounced; // last argument to Route.didPopNext
Route<dynamic> lastAnnouncedNextRoute = notAnnounced; // last argument to Route.didChangeNext
bool get hasPage => route.settings is Page;

View file

@ -1840,6 +1840,57 @@ void main() {
expect(tickCount, 4);
});
testWidgets('Route annouce correctly for first route and last route', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/57133.
Route<void> previousOfFirst = NotAnnounced();
Route<void> nextOfFirst = NotAnnounced();
Route<void> popNextOfFirst = NotAnnounced();
Route<void> firstRoute;
Route<void> previousOfSecond = NotAnnounced();
Route<void> nextOfSecond = NotAnnounced();
Route<void> popNextOfSecond = NotAnnounced();
Route<void> secondRoute;
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
await tester.pumpWidget(
MaterialApp(
navigatorKey: navigator,
initialRoute: '/second',
onGenerateRoute: (RouteSettings settings) {
if (settings.name == '/') {
firstRoute = RouteAnnouncementSpy(
onDidChangeNext: (Route<void> next) => nextOfFirst = next,
onDidChangePrevious: (Route<void> previous) => previousOfFirst = previous,
onDidPopNext: (Route<void> next) => popNextOfFirst = next,
settings: settings,
);
return firstRoute;
}
secondRoute = RouteAnnouncementSpy(
onDidChangeNext: (Route<void> next) => nextOfSecond = next,
onDidChangePrevious: (Route<void> previous) => previousOfSecond = previous,
onDidPopNext: (Route<void> next) => popNextOfSecond = next,
settings: settings,
);
return secondRoute;
},
),
);
await tester.pumpAndSettle();
expect(previousOfFirst, isNull);
expect(nextOfFirst, secondRoute);
expect(popNextOfFirst, isA<NotAnnounced>());
expect(previousOfSecond, firstRoute);
expect(nextOfSecond, isNull);
expect(popNextOfSecond, isA<NotAnnounced>());
navigator.currentState.pop();
expect(popNextOfFirst, secondRoute);
});
group('Page api', (){
Widget buildNavigator(
List<Page<dynamic>> pages,
@ -2561,6 +2612,50 @@ void main() {
});
}
typedef AnnouncementCallBack = void Function(Route<dynamic>);
class NotAnnounced extends Route<void> {/* A place holder for not announced route*/}
class RouteAnnouncementSpy extends Route<void> {
RouteAnnouncementSpy({
this.onDidChangePrevious,
this.onDidChangeNext,
this.onDidPopNext,
RouteSettings settings,
}) : super(settings: settings);
final AnnouncementCallBack onDidChangePrevious;
final AnnouncementCallBack onDidChangeNext;
final AnnouncementCallBack onDidPopNext;
@override
List<OverlayEntry> get overlayEntries => <OverlayEntry>[
OverlayEntry(
builder: (BuildContext context) => const Placeholder(),
)
];
@override
void didChangeNext(Route<dynamic> nextRoute) {
super.didChangeNext(nextRoute);
if (onDidChangeNext != null)
onDidChangeNext(nextRoute);
}
@override
void didChangePrevious(Route<dynamic> previousRoute) {
super.didChangePrevious(previousRoute);
if (onDidChangePrevious != null)
onDidChangePrevious(previousRoute);
}
@override
void didPopNext(Route<dynamic> nextRoute) {
super.didPopNext(nextRoute);
if (onDidPopNext != null)
onDidPopNext(nextRoute);
}
}
class _TickingWidget extends StatefulWidget {
const _TickingWidget({this.onTick});