From c98978ae36dd3e68984ce5b34b5004a32590bec0 Mon Sep 17 00:00:00 2001 From: hangyu Date: Thu, 15 Dec 2022 14:30:21 -0800 Subject: [PATCH] Update Navigator updatePages() (#116945) * Update navigator.dart * Update navigator.dart * Add test * Update navigator.dart * lint * Update packages/flutter/test/widgets/navigator_test.dart Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> * Update packages/flutter/test/widgets/navigator_test.dart Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> --- .../flutter/lib/src/widgets/navigator.dart | 21 ++++--- .../flutter/test/widgets/navigator_test.dart | 55 +++++++++++++++++++ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 2fe21397ad2d..8a855ed87b1d 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -3687,15 +3687,14 @@ class NavigatorState extends State with TickerProviderStateMixin, Res oldEntriesBottom += 1; } - int pagelessRoutesToSkip = 0; + final List<_RouteEntry> unattachedPagelessRoutes=<_RouteEntry>[]; // Scans the top of the list until we found a page-based route that cannot be // updated. while ((oldEntriesBottom <= oldEntriesTop) && (newPagesBottom <= newPagesTop)) { final _RouteEntry oldEntry = _history[oldEntriesTop]; assert(oldEntry != null && oldEntry.currentState != _RouteLifecycle.disposed); if (!oldEntry.pageBased) { - // This route might need to be skipped if we can not find a page above. - pagelessRoutesToSkip += 1; + unattachedPagelessRoutes.add(oldEntry); oldEntriesTop -= 1; continue; } @@ -3703,14 +3702,22 @@ class NavigatorState extends State with TickerProviderStateMixin, Res if (!oldEntry.canUpdateFrom(newPage)) { break; } - // We found the page for all the consecutive pageless routes below. Those - // pageless routes do not need to be skipped. - pagelessRoutesToSkip = 0; + + // We found the page for all the consecutive pageless routes below. Attach these + // pageless routes to the page. + if(unattachedPagelessRoutes.isNotEmpty) { + pageRouteToPagelessRoutes.putIfAbsent( + oldEntry, + () => List<_RouteEntry>.from(unattachedPagelessRoutes), + ); + unattachedPagelessRoutes.clear(); + } + oldEntriesTop -= 1; newPagesTop -= 1; } // Reverts the pageless routes that cannot be updated. - oldEntriesTop += pagelessRoutesToSkip; + oldEntriesTop += unattachedPagelessRoutes.length; // Scans middle of the old entries and records the page key to old entry map. int oldEntriesBottomToScan = oldEntriesBottom; diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index fc51821090bb..d581037aba02 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -3342,6 +3342,61 @@ void main() { expect(find.text('forth'), findsOneWidget); }); + //Regression test for https://github.com/flutter/flutter/issues/115887 + testWidgets('Complex case 2', (WidgetTester tester) async { + final GlobalKey navigator = GlobalKey(); + List myPages = [ + const TestPage(key: ValueKey('1'), name:'initial'), + const TestPage(key: ValueKey('2'), name:'second'), + ]; + + bool onPopPage(Route route, dynamic result) { + myPages.removeWhere((Page page) => route.settings == page); + return route.didPop(result); + } + + await tester.pumpWidget( + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), + ); + expect(find.text('second'), findsOneWidget); + expect(find.text('initial'), findsNothing); + // Push pageless route to second page route + navigator.currentState!.push( + MaterialPageRoute( + builder: (BuildContext context) => const Text('second-pageless1'), + ), + ); + + await tester.pumpAndSettle(); + // Now the history should look like [initial, second, second-pageless1]. + expect(find.text('initial'), findsNothing); + expect(find.text('second'), findsNothing); + expect(find.text('second-pageless1'), findsOneWidget); + expect(myPages.length, 2); + + myPages = [ + const TestPage(key: ValueKey('2'), name:'second'), + ]; + await tester.pumpWidget( + buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator), + ); + await tester.pumpAndSettle(); + + // Now the history should look like [second, second-pageless1]. + expect(find.text('initial'), findsNothing); + expect(find.text('second'), findsNothing); + expect(find.text('second-pageless1'), findsOneWidget); + expect(myPages.length, 1); + + // Pop the pageless route. + navigator.currentState!.pop(); + await tester.pumpAndSettle(); + expect(myPages.length, 1); + expect(find.text('initial'), findsNothing); + expect(find.text('second'), findsOneWidget); + expect(find.text('second-pageless1'), findsNothing); + }); + testWidgets('complex case 1 - with always remove transition delegate', (WidgetTester tester) async { final GlobalKey navigator = GlobalKey(); final AlwaysRemoveTransitionDelegate transitionDelegate = AlwaysRemoveTransitionDelegate();