mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
This reverts commit aee9e94c21
.
This commit is contained in:
parent
a1f6c173ba
commit
a206bf7e2f
File diff suppressed because it is too large
Load diff
|
@ -1708,6 +1708,666 @@ void main() {
|
||||||
await tester.pump(const Duration(seconds: 1));
|
await tester.pump(const Duration(seconds: 1));
|
||||||
expect(tickCount, 4);
|
expect(tickCount, 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('Page api', (){
|
||||||
|
Widget buildNavigator(
|
||||||
|
List<Page<dynamic>> pages,
|
||||||
|
PopPageCallback onPopPage, [
|
||||||
|
GlobalKey<NavigatorState> key,
|
||||||
|
TransitionDelegate<dynamic> transitionDelegate
|
||||||
|
]) {
|
||||||
|
return MediaQuery(
|
||||||
|
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
|
||||||
|
child: Localizations(
|
||||||
|
locale: const Locale('en', 'US'),
|
||||||
|
delegates: const <LocalizationsDelegate<dynamic>>[
|
||||||
|
DefaultMaterialLocalizations.delegate,
|
||||||
|
DefaultWidgetsLocalizations.delegate
|
||||||
|
],
|
||||||
|
child: Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Navigator(
|
||||||
|
key: key,
|
||||||
|
pages: pages,
|
||||||
|
onPopPage: onPopPage,
|
||||||
|
transitionDelegate: transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
testWidgets('can initialize with pages list', (WidgetTester tester) async {
|
||||||
|
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
|
||||||
|
final List<TestPage> myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name:'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name:'second'),
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name:'third'),
|
||||||
|
];
|
||||||
|
|
||||||
|
bool onPopPage(Route<dynamic> route, dynamic result) {
|
||||||
|
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
|
||||||
|
return route.didPop(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
expect(find.text('third'), findsOneWidget);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('second'), findsOneWidget);
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('initial'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can push and pop pages using page api', (WidgetTester tester) async {
|
||||||
|
Animation<double> secondaryAnimationOfRouteOne;
|
||||||
|
Animation<double> primaryAnimationOfRouteOne;
|
||||||
|
Animation<double> secondaryAnimationOfRouteTwo;
|
||||||
|
Animation<double> primaryAnimationOfRouteTwo;
|
||||||
|
Animation<double> secondaryAnimationOfRouteThree;
|
||||||
|
Animation<double> primaryAnimationOfRouteThree;
|
||||||
|
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
|
||||||
|
List<Page<dynamic>> myPages = <Page<dynamic>>[
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('1'),
|
||||||
|
name:'initial',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteOne = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteOne = animation;
|
||||||
|
return const Text('initial');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
bool onPopPage(Route<dynamic> route, dynamic result) {
|
||||||
|
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
|
||||||
|
return route.didPop(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
expect(find.text('initial'), findsOneWidget);
|
||||||
|
|
||||||
|
myPages = <Page<dynamic>>[
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('1'),
|
||||||
|
name:'initial',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteOne = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteOne = animation;
|
||||||
|
return const Text('initial');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('2'),
|
||||||
|
name:'second',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteTwo = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteTwo = animation;
|
||||||
|
return const Text('second');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('3'),
|
||||||
|
name:'third',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteThree = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteThree = animation;
|
||||||
|
return const Text('third');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
// The third page is transitioning, and the secondary animation of first
|
||||||
|
// page should chain with the third page. The animation of second page
|
||||||
|
// won't start until the third page finishes transition.
|
||||||
|
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteThree.value);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
|
||||||
|
expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.forward);
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 30));
|
||||||
|
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteThree.value);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
|
||||||
|
expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteThree.value, 0.1);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
// After transition finishes, the routes' animations are correctly chained.
|
||||||
|
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
expect(find.text('third'), findsOneWidget);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
// Starts pops the pages using page api and verify the animations chain
|
||||||
|
// correctly.
|
||||||
|
|
||||||
|
myPages = <Page<dynamic>>[
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('1'),
|
||||||
|
name:'initial',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteOne = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteOne = animation;
|
||||||
|
return const Text('initial');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('2'),
|
||||||
|
name:'second',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteTwo = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteTwo = animation;
|
||||||
|
return const Text('second');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
await tester.pump(const Duration(milliseconds: 30));
|
||||||
|
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteThree.value, 0.9);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can modify routes history and secondary animation still works', (WidgetTester tester) async {
|
||||||
|
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
|
||||||
|
Animation<double> secondaryAnimationOfRouteOne;
|
||||||
|
Animation<double> primaryAnimationOfRouteOne;
|
||||||
|
Animation<double> secondaryAnimationOfRouteTwo;
|
||||||
|
Animation<double> primaryAnimationOfRouteTwo;
|
||||||
|
Animation<double> secondaryAnimationOfRouteThree;
|
||||||
|
Animation<double> primaryAnimationOfRouteThree;
|
||||||
|
List<Page<dynamic>> myPages = <CustomBuilderPage<void>>[
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('1'),
|
||||||
|
name:'initial',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteOne = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteOne = animation;
|
||||||
|
return const Text('initial');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('2'),
|
||||||
|
name:'second',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteTwo = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteTwo = animation;
|
||||||
|
return const Text('second');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
CustomBuilderPage<void>(
|
||||||
|
key: const ValueKey<String>('3'),
|
||||||
|
name:'third',
|
||||||
|
routeBuilder: (BuildContext context, RouteSettings settings) {
|
||||||
|
return PageRouteBuilder<void>(
|
||||||
|
settings: settings,
|
||||||
|
pageBuilder: (_, Animation<double> animation, Animation<double> secondaryAnimation) {
|
||||||
|
secondaryAnimationOfRouteThree = secondaryAnimation;
|
||||||
|
primaryAnimationOfRouteThree = animation;
|
||||||
|
return const Text('third');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
bool onPopPage(Route<dynamic> route, dynamic result) {
|
||||||
|
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
|
||||||
|
return route.didPop(result);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
expect(find.text('third'), findsOneWidget);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteThree.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteThree.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
|
||||||
|
myPages = myPages.reversed.toList();
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
// Reversed routes are still chained up correctly.
|
||||||
|
expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.completed);
|
||||||
|
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 30));
|
||||||
|
expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteOne.value, 0.9);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 30));
|
||||||
|
expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.value, 0.9);
|
||||||
|
expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(secondaryAnimationOfRouteThree.value, primaryAnimationOfRouteTwo.value);
|
||||||
|
expect(primaryAnimationOfRouteThree.status, AnimationStatus.completed);
|
||||||
|
expect(secondaryAnimationOfRouteTwo.value, primaryAnimationOfRouteOne.value);
|
||||||
|
expect(primaryAnimationOfRouteTwo.status, AnimationStatus.dismissed);
|
||||||
|
expect(secondaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
expect(primaryAnimationOfRouteOne.status, AnimationStatus.dismissed);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('can work with pageless route', (WidgetTester tester) async {
|
||||||
|
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
|
||||||
|
List<TestPage> myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name:'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name:'second'),
|
||||||
|
];
|
||||||
|
|
||||||
|
bool onPopPage(Route<dynamic> route, dynamic result) {
|
||||||
|
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
|
||||||
|
return route.didPop(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
expect(find.text('second'), findsOneWidget);
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
// Pushes two pageless routes to second page route
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('second-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('second-pageless2'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
// Now the history should look like
|
||||||
|
// [initial, second, second-pageless1, second-pageless2].
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsOneWidget);
|
||||||
|
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name:'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name:'second'),
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name:'third'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(find.text('third'), findsOneWidget);
|
||||||
|
|
||||||
|
// Pushes one pageless routes to third page route
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('third-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
// Now the history should look like
|
||||||
|
// [initial, second, second-pageless1, second-pageless2, third, third-pageless1].
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('third-pageless1'), findsOneWidget);
|
||||||
|
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name:'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name:'third'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name:'second'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
// Swaps the order without any adding or removing should not trigger any
|
||||||
|
// transition. The routes should update without a pumpAndSettle
|
||||||
|
// Now the history should look like
|
||||||
|
// [initial, third, third-pageless1, second, second-pageless1, second-pageless2].
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('third-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsOneWidget);
|
||||||
|
// Pops the route one by one to make sure the order is correct.
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('third-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsOneWidget);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(myPages.length, 3);
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('third-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second'), findsOneWidget);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(myPages.length, 3);
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('third-pageless1'), findsOneWidget);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(myPages.length, 2);
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('initial'), findsNothing);
|
||||||
|
expect(find.text('third'), findsOneWidget);
|
||||||
|
expect(find.text('third-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(myPages.length, 2);
|
||||||
|
navigator.currentState.pop();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('initial'), findsOneWidget);
|
||||||
|
expect(find.text('third'), findsNothing);
|
||||||
|
expect(find.text('third-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second'), findsNothing);
|
||||||
|
expect(find.text('second-pageless1'), findsNothing);
|
||||||
|
expect(find.text('second-pageless2'), findsNothing);
|
||||||
|
expect(myPages.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('complex case 1', (WidgetTester tester) async {
|
||||||
|
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
|
||||||
|
List<TestPage> myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
|
||||||
|
];
|
||||||
|
bool onPopPage(Route<dynamic> route, dynamic result) {
|
||||||
|
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
|
||||||
|
return route.didPop(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add initial page route with one pageless route.
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
bool initialPageless1Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('initial-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => initialPageless1Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Pushes second page route with two pageless routes.
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name: 'second'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
bool secondPageless1Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('second-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => secondPageless1Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
bool secondPageless2Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('second-pageless2'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => secondPageless2Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Pushes third page route with one pageless route.
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name: 'second'),
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name: 'third'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
bool thirdPageless1Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('third-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => thirdPageless1Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Nothing has been popped.
|
||||||
|
expect(initialPageless1Completed, false);
|
||||||
|
expect(secondPageless1Completed, false);
|
||||||
|
expect(secondPageless2Completed, false);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
|
||||||
|
// Switches order and removes the initial page route.
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name: 'third'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name: 'second'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
// The pageless route of initial page route should be completed.
|
||||||
|
expect(initialPageless1Completed, true);
|
||||||
|
expect(secondPageless1Completed, false);
|
||||||
|
expect(secondPageless2Completed, false);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name: 'third'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(secondPageless1Completed, true);
|
||||||
|
expect(secondPageless2Completed, true);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('4'), name: 'forth'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator));
|
||||||
|
expect(thirdPageless1Completed, true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('forth'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('complex case 1 - with always remove transition delegate', (WidgetTester tester) async {
|
||||||
|
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
|
||||||
|
final AlwaysRemoveTransitionDelegate transitionDelegate = AlwaysRemoveTransitionDelegate();
|
||||||
|
List<TestPage> myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
|
||||||
|
];
|
||||||
|
bool onPopPage(Route<dynamic> route, dynamic result) {
|
||||||
|
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
|
||||||
|
return route.didPop(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add initial page route with one pageless route.
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
|
||||||
|
bool initialPageless1Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('initial-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => initialPageless1Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Pushes second page route with two pageless routes.
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name: 'second'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
|
||||||
|
bool secondPageless1Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('second-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => secondPageless1Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
bool secondPageless2Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('second-pageless2'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => secondPageless2Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Pushes third page route with one pageless route.
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name: 'second'),
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name: 'third'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
|
||||||
|
bool thirdPageless1Completed = false;
|
||||||
|
navigator.currentState.push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => const Text('third-pageless1'),
|
||||||
|
settings: null,
|
||||||
|
)
|
||||||
|
).then((_) => thirdPageless1Completed = true);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Nothing has been popped.
|
||||||
|
expect(initialPageless1Completed, false);
|
||||||
|
expect(secondPageless1Completed, false);
|
||||||
|
expect(secondPageless2Completed, false);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
|
||||||
|
// Switches order and removes the initial page route.
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name: 'third'),
|
||||||
|
const TestPage(key: ValueKey<String>('2'), name: 'second'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
|
||||||
|
// The pageless route of initial page route should be removed without complete.
|
||||||
|
expect(initialPageless1Completed, false);
|
||||||
|
expect(secondPageless1Completed, false);
|
||||||
|
expect(secondPageless2Completed, false);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('3'), name: 'third'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(initialPageless1Completed, false);
|
||||||
|
expect(secondPageless1Completed, false);
|
||||||
|
expect(secondPageless2Completed, false);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
|
||||||
|
myPages = <TestPage>[
|
||||||
|
const TestPage(key: ValueKey<String>('4'), name: 'forth'),
|
||||||
|
];
|
||||||
|
await tester.pumpWidget(buildNavigator(myPages, onPopPage, navigator, transitionDelegate));
|
||||||
|
await tester.pump();
|
||||||
|
expect(initialPageless1Completed, false);
|
||||||
|
expect(secondPageless1Completed, false);
|
||||||
|
expect(secondPageless2Completed, false);
|
||||||
|
expect(thirdPageless1Completed, false);
|
||||||
|
expect(find.text('forth'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TickingWidget extends StatefulWidget {
|
class _TickingWidget extends StatefulWidget {
|
||||||
|
@ -1742,6 +2402,62 @@ class _TickingWidgetState extends State<_TickingWidget> with SingleTickerProvide
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AlwaysRemoveTransitionDelegate extends TransitionDelegate<void> {
|
||||||
|
@override
|
||||||
|
Iterable<RouteTransitionRecord> resolve({
|
||||||
|
List<RouteTransitionRecord> newPageRouteHistory,
|
||||||
|
Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
|
||||||
|
Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
|
||||||
|
}) {
|
||||||
|
final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
|
||||||
|
void handleExitingRoute(RouteTransitionRecord location) {
|
||||||
|
if (!locationToExitingPageRoute.containsKey(location))
|
||||||
|
return;
|
||||||
|
|
||||||
|
final RouteTransitionRecord exitingPageRoute = locationToExitingPageRoute[location];
|
||||||
|
final bool hasPagelessRoute = pageRouteToPagelessRoutes.containsKey(exitingPageRoute);
|
||||||
|
|
||||||
|
exitingPageRoute.markForRemove();
|
||||||
|
results.add(exitingPageRoute);
|
||||||
|
|
||||||
|
if (hasPagelessRoute) {
|
||||||
|
final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
|
||||||
|
for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
|
||||||
|
pagelessRoute.markForRemove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleExitingRoute(exitingPageRoute);
|
||||||
|
}
|
||||||
|
handleExitingRoute(null);
|
||||||
|
|
||||||
|
for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
|
||||||
|
if (pageRoute.isEntering) {
|
||||||
|
pageRoute.markForAdd();
|
||||||
|
}
|
||||||
|
results.add(pageRoute);
|
||||||
|
handleExitingRoute(pageRoute);
|
||||||
|
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestPage extends Page<void> {
|
||||||
|
const TestPage({
|
||||||
|
LocalKey key,
|
||||||
|
String name,
|
||||||
|
Object arguments,
|
||||||
|
}) : super(key: key, name: name, arguments: arguments);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Route<void> createRoute(BuildContext context) {
|
||||||
|
return MaterialPageRoute<void>(
|
||||||
|
builder: (BuildContext context) => Text(name),
|
||||||
|
settings: this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NoAnimationPageRoute extends PageRouteBuilder<void> {
|
class NoAnimationPageRoute extends PageRouteBuilder<void> {
|
||||||
NoAnimationPageRoute({WidgetBuilder pageBuilder})
|
NoAnimationPageRoute({WidgetBuilder pageBuilder})
|
||||||
: super(pageBuilder: (BuildContext context, __, ___) {
|
: super(pageBuilder: (BuildContext context, __, ___) {
|
||||||
|
|
Loading…
Reference in a new issue