Pesto home stack (#5168)
This commit is contained in:
parent
fb3e64cce4
commit
56a2d2262c
@ -142,20 +142,25 @@ class _PestoDemoState extends State<PestoDemo> {
|
||||
new DrawerItem(
|
||||
child: new Text('Home'),
|
||||
selected: !config.showFavorites,
|
||||
onPressed: () => Navigator.pushNamed(context, PestoDemo.routeName)
|
||||
onPressed: () {
|
||||
Navigator.popUntil(context, ModalRoute.withName('/pesto'));
|
||||
}
|
||||
),
|
||||
new DrawerItem(
|
||||
child: new Text('Favorites'),
|
||||
selected: config.showFavorites,
|
||||
onPressed: () { _showFavorites(context); }
|
||||
onPressed: () {
|
||||
if (config.showFavorites)
|
||||
Navigator.pop(context);
|
||||
else
|
||||
_showFavorites(context);
|
||||
}
|
||||
),
|
||||
new Divider(),
|
||||
new DrawerItem(
|
||||
child: new Text('Return to Gallery'),
|
||||
onPressed: () {
|
||||
Navigator.of(context)
|
||||
..pop() // Close the drawer.
|
||||
..pop(); // Go back to the gallery.
|
||||
Navigator.popUntil(context, ModalRoute.withName('/'));
|
||||
}
|
||||
),
|
||||
]
|
||||
@ -193,6 +198,7 @@ class _PestoDemoState extends State<PestoDemo> {
|
||||
|
||||
void _showFavorites(BuildContext context) {
|
||||
Navigator.push(context, new MaterialPageRoute<Null>(
|
||||
settings: const RouteSettings(name: "/pesto/favorites"),
|
||||
builder: (BuildContext context) {
|
||||
return new PestoDemo(showFavorites: true);
|
||||
}
|
||||
@ -201,6 +207,7 @@ class _PestoDemoState extends State<PestoDemo> {
|
||||
|
||||
void _showRecipe(BuildContext context, Recipe recipe) {
|
||||
Navigator.push(context, new MaterialPageRoute<Null>(
|
||||
settings: const RouteSettings(name: "/pesto/recipe"),
|
||||
builder: (BuildContext context) {
|
||||
return new Theme(
|
||||
data: _kTheme,
|
||||
|
55
examples/flutter_gallery/test/pesto_test.dart
Normal file
55
examples/flutter_gallery/test/pesto_test.dart
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_gallery/main.dart' as flutter_gallery_main;
|
||||
|
||||
Finder byTooltip(WidgetTester tester, String message) {
|
||||
return find.byWidgetPredicate((Widget widget) {
|
||||
return widget is Tooltip && widget.message == message;
|
||||
});
|
||||
}
|
||||
|
||||
Finder findNavigationMenuButton(WidgetTester tester) {
|
||||
return byTooltip(tester, 'Open navigation menu');
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding binding =
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
if (binding is LiveTestWidgetsFlutterBinding) binding.allowAllFrames = true;
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/pull/5168
|
||||
testWidgets('Pesto route management', (WidgetTester tester) async {
|
||||
flutter_gallery_main
|
||||
.main(); // builds the app and schedules a frame but doesn't trigger one
|
||||
await tester.pump(); // see https://github.com/flutter/flutter/issues/1865
|
||||
await tester.pump(); // triggers a frame
|
||||
|
||||
expect(find.text('Pesto'), findsOneWidget);
|
||||
await tester.tap(find.text('Pesto'));
|
||||
await tester.pump(); // Launch pesto
|
||||
await tester.pump(const Duration(seconds: 1)); // transition is complete
|
||||
|
||||
Future<Null> tapDrawerItem(String title) async {
|
||||
await tester.tap(findNavigationMenuButton(tester));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1)); // drawer opening animation
|
||||
await tester.tap(find.text(title));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1)); // drawer closing animation
|
||||
await tester.pump(); // maybe open a new page
|
||||
return tester.pump(const Duration(seconds: 1)); // new page transition
|
||||
}
|
||||
await tapDrawerItem('Home');
|
||||
await tapDrawerItem('Favorites');
|
||||
await tapDrawerItem('Home');
|
||||
await tapDrawerItem('Favorites');
|
||||
await tapDrawerItem('Home');
|
||||
await tapDrawerItem('Return to Gallery');
|
||||
|
||||
expect(find.text('Flutter gallery'), findsOneWidget);
|
||||
});
|
||||
}
|
@ -161,6 +161,9 @@ class NavigatorObserver {
|
||||
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { }
|
||||
}
|
||||
|
||||
/// Signature for the [Navigator.popUntil] predicate argument.
|
||||
typedef bool RoutePredicate(Route<dynamic> route);
|
||||
|
||||
/// A widget that manages a set of child widgets with a stack discipline.
|
||||
///
|
||||
/// Many apps have a navigator near the top of their widget hierarchy in order
|
||||
@ -243,10 +246,11 @@ class Navigator extends StatefulWidget {
|
||||
return Navigator.of(context).pop(result);
|
||||
}
|
||||
|
||||
/// Calls pop() repeatedly until the given route is the current route.
|
||||
/// If it is already the current route, nothing happens.
|
||||
static void popUntil(BuildContext context, Route<dynamic> targetRoute) {
|
||||
Navigator.of(context).popUntil(targetRoute);
|
||||
/// Calls [pop()] repeatedly until the predicate returns false.
|
||||
/// The predicate may be applied to the same route more than once if
|
||||
/// [Route.willHandlePopInternally] is true.
|
||||
static void popUntil(BuildContext context, RoutePredicate predicate) {
|
||||
Navigator.of(context).popUntil(predicate);
|
||||
}
|
||||
|
||||
/// Whether the navigator that most tightly encloses the given context can be popped.
|
||||
@ -463,9 +467,8 @@ class NavigatorState extends State<Navigator> {
|
||||
return true;
|
||||
}
|
||||
|
||||
void popUntil(Route<dynamic> targetRoute) {
|
||||
assert(_history.contains(targetRoute));
|
||||
while (!targetRoute.isCurrent)
|
||||
void popUntil(RoutePredicate predicate) {
|
||||
while (!predicate(_history.last))
|
||||
pop();
|
||||
}
|
||||
|
||||
|
@ -487,6 +487,17 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a predicate that's true if the route has the specified name and if
|
||||
/// popping the route will not yield the same route, i.e. if the route's
|
||||
/// [willHandlePopInternally] property is false.
|
||||
///
|
||||
/// This function is typically used with [Navigator.popUntil()].
|
||||
static RoutePredicate withName(String name) {
|
||||
return (Route<dynamic> route) {
|
||||
return !route.willHandlePopInternally
|
||||
&& route is ModalRoute && route.settings.name == name;
|
||||
};
|
||||
}
|
||||
|
||||
// The API for subclasses to override - used by _ModalScope
|
||||
|
||||
|
@ -11,7 +11,7 @@ final List<String> results = <String>[];
|
||||
|
||||
Set<TestRoute> routes = new HashSet<TestRoute>();
|
||||
|
||||
class TestRoute extends Route<String> {
|
||||
class TestRoute extends LocalHistoryRoute<String> {
|
||||
TestRoute(this.name);
|
||||
final String name;
|
||||
|
||||
@ -329,7 +329,7 @@ void main() {
|
||||
await runNavigatorTest(
|
||||
tester,
|
||||
host,
|
||||
() { host.popUntil(routeB); },
|
||||
() { host.popUntil((Route<dynamic> route) => route == routeB); },
|
||||
<String>[
|
||||
'C: didPop null',
|
||||
'C: dispose',
|
||||
@ -341,4 +341,42 @@ void main() {
|
||||
expect(routes.isEmpty, isTrue);
|
||||
results.clear();
|
||||
});
|
||||
|
||||
testWidgets('Route localHistory - popUntil', (WidgetTester tester) async {
|
||||
TestRoute routeA = new TestRoute('A');
|
||||
routeA.addLocalHistoryEntry(new LocalHistoryEntry(
|
||||
onRemove: () { routeA.log('onRemove 0'); }
|
||||
));
|
||||
routeA.addLocalHistoryEntry(new LocalHistoryEntry(
|
||||
onRemove: () { routeA.log('onRemove 1'); }
|
||||
));
|
||||
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
||||
await tester.pumpWidget(new Navigator(
|
||||
key: navigatorKey,
|
||||
onGenerateRoute: (_) => routeA
|
||||
));
|
||||
NavigatorState host = navigatorKey.currentState;
|
||||
await runNavigatorTest(
|
||||
tester,
|
||||
host,
|
||||
() { host.popUntil((Route<dynamic> route) => !route.willHandlePopInternally); },
|
||||
<String>[
|
||||
'A: install',
|
||||
'A: didPush',
|
||||
'A: didChangeNext null',
|
||||
'A: didPop null',
|
||||
'A: onRemove 1',
|
||||
'A: didPop null',
|
||||
'A: onRemove 0',
|
||||
]
|
||||
);
|
||||
|
||||
await runNavigatorTest(
|
||||
tester,
|
||||
host,
|
||||
() { host.popUntil((Route<dynamic> route) => !route.willHandlePopInternally); },
|
||||
<String>[
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user