From 65f232fd76af41b19932fed058f3ca2214eefda1 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Fri, 19 Mar 2021 15:32:31 -0700 Subject: [PATCH] Add restorationId to Material/CupertinoPage (#78450) --- packages/flutter/lib/src/cupertino/route.dart | 3 +- packages/flutter/lib/src/material/page.dart | 3 +- .../flutter/test/cupertino/page_test.dart | 101 ++++++++++++++++++ packages/flutter/test/material/page_test.dart | 98 +++++++++++++++++ 4 files changed, 203 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index 5193748285..4ce6764766 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -401,10 +401,11 @@ class CupertinoPage extends Page { LocalKey? key, String? name, Object? arguments, + String? restorationId, }) : assert(child != null), assert(maintainState != null), assert(fullscreenDialog != null), - super(key: key, name: name, arguments: arguments); + super(key: key, name: name, arguments: arguments, restorationId: restorationId); /// The content to be shown in the [Route] created by this page. final Widget child; diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index c1bcb43b40..d1a1cf9e5b 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -156,10 +156,11 @@ class MaterialPage extends Page { LocalKey? key, String? name, Object? arguments, + String? restorationId, }) : assert(child != null), assert(maintainState != null), assert(fullscreenDialog != null), - super(key: key, name: name, arguments: arguments); + super(key: key, name: name, arguments: arguments, restorationId: restorationId); /// The content to be shown in the [Route] created by this page. final Widget child; diff --git a/packages/flutter/test/cupertino/page_test.dart b/packages/flutter/test/cupertino/page_test.dart index b515e33391..de6761925d 100644 --- a/packages/flutter/test/cupertino/page_test.dart +++ b/packages/flutter/test/cupertino/page_test.dart @@ -475,6 +475,68 @@ void main() { expect(find.text('subpage'), findsOneWidget); expect(find.text('home'), findsOneWidget); }); + + testWidgets('CupertinoPage restores its state', (WidgetTester tester) async { + await tester.pumpWidget( + RootRestorationScope( + restorationId: 'root', + child: MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: Navigator( + onPopPage: (Route route, dynamic result) { return false; }, + pages: const >[ + CupertinoPage( + restorationId: 'p1', + child: TestRestorableWidget(restorationId: 'p1'), + ), + ], + restorationScopeId: 'nav', + onGenerateRoute: (RouteSettings settings) { + return CupertinoPageRoute( + settings: settings, + builder: (BuildContext context) { + return TestRestorableWidget(restorationId: settings.name!); + }, + ); + }, + ), + ), + ), + ), + ); + + expect(find.text('p1'), findsOneWidget); + expect(find.text('count: 0'), findsOneWidget); + + await tester.tap(find.text('increment')); + await tester.pump(); + expect(find.text('count: 1'), findsOneWidget); + + tester.state(find.byType(Navigator)).restorablePushNamed('p2'); + await tester.pumpAndSettle(); + + expect(find.text('p1'), findsNothing); + expect(find.text('p2'), findsOneWidget); + + await tester.tap(find.text('increment')); + await tester.pump(); + await tester.tap(find.text('increment')); + await tester.pump(); + expect(find.text('count: 2'), findsOneWidget); + + await tester.restartAndRestore(); + + expect(find.text('p2'), findsOneWidget); + expect(find.text('count: 2'), findsOneWidget); + + tester.state(find.byType(Navigator)).pop(); + await tester.pumpAndSettle(); + + expect(find.text('p1'), findsOneWidget); + expect(find.text('count: 1'), findsOneWidget); + }); } class RtlOverrideWidgetsDelegate extends LocalizationsDelegate { @@ -527,3 +589,42 @@ class _KeepsStateTestWidgetState extends State { ); } } + +class TestRestorableWidget extends StatefulWidget { + const TestRestorableWidget({Key? key, required this.restorationId}) : super(key: key); + + final String restorationId; + + @override + State createState() => _TestRestorableWidgetState(); +} + +class _TestRestorableWidgetState extends State with RestorationMixin { + @override + String? get restorationId => widget.restorationId; + + final RestorableInt counter = RestorableInt(0); + + @override + void restoreState(RestorationBucket? oldBucket, bool initialRestore) { + registerForRestoration(counter, 'counter'); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text(widget.restorationId), + Text('count: ${counter.value}'), + CupertinoButton( + onPressed: () { + setState(() { + counter.value++; + }); + }, + child: const Text('increment'), + ), + ], + ); + } +} diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index d51bc90bd3..d7e93c0cc8 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -913,6 +913,65 @@ void main() { expect(find.text('subpage'), findsOneWidget); expect(find.text('home'), findsOneWidget); }); + + testWidgets('MaterialPage restores its state', (WidgetTester tester) async { + await tester.pumpWidget( + RootRestorationScope( + restorationId: 'root', + child: Directionality( + textDirection: TextDirection.ltr, + child: Navigator( + onPopPage: (Route route, dynamic result) { return false; }, + pages: const >[ + MaterialPage( + restorationId: 'p1', + child: TestRestorableWidget(restorationId: 'p1'), + ), + ], + restorationScopeId: 'nav', + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + return TestRestorableWidget(restorationId: settings.name!); + }, + ); + }, + ), + ), + ), + ); + + expect(find.text('p1'), findsOneWidget); + expect(find.text('count: 0'), findsOneWidget); + + await tester.tap(find.text('increment')); + await tester.pump(); + expect(find.text('count: 1'), findsOneWidget); + + tester.state(find.byType(Navigator)).restorablePushNamed('p2'); + await tester.pumpAndSettle(); + + expect(find.text('p1'), findsNothing); + expect(find.text('p2'), findsOneWidget); + + await tester.tap(find.text('increment')); + await tester.pump(); + await tester.tap(find.text('increment')); + await tester.pump(); + expect(find.text('count: 2'), findsOneWidget); + + await tester.restartAndRestore(); + + expect(find.text('p2'), findsOneWidget); + expect(find.text('count: 2'), findsOneWidget); + + tester.state(find.byType(Navigator)).pop(); + await tester.pumpAndSettle(); + + expect(find.text('p1'), findsOneWidget); + expect(find.text('count: 1'), findsOneWidget); + }); } class TransitionDetector extends DefaultTransitionDelegate { @@ -993,3 +1052,42 @@ class _KeepsStateTestWidgetState extends State { ); } } + +class TestRestorableWidget extends StatefulWidget { + const TestRestorableWidget({Key? key, required this.restorationId}) : super(key: key); + + final String restorationId; + + @override + State createState() => _TestRestorableWidgetState(); +} + +class _TestRestorableWidgetState extends State with RestorationMixin { + @override + String? get restorationId => widget.restorationId; + + final RestorableInt counter = RestorableInt(0); + + @override + void restoreState(RestorationBucket? oldBucket, bool initialRestore) { + registerForRestoration(counter, 'counter'); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Text(widget.restorationId), + Text('count: ${counter.value}'), + ElevatedButton( + onPressed: () { + setState(() { + counter.value++; + }); + }, + child: const Text('increment'), + ), + ], + ); + } +}