Commit 6d433341 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Don't try to pop the initial route (#8307)

This functionality got lots somehow in the migration to maybePop.

Fixes #8258
parent 862fc051
......@@ -312,7 +312,7 @@ class _AppBarState extends State<AppBar> {
super.dependenciesChanged();
ScaffoldState scaffold = Scaffold.of(context);
_hasDrawer = scaffold?.hasDrawer ?? false;
_canPop = ModalRoute.of(context)?.canPop() ?? false;
_canPop = ModalRoute.of(context)?.canPop ?? false;
}
void _handleDrawerButton() {
......
......@@ -70,10 +70,14 @@ abstract class Route<T> {
/// Returns false if this route wants to veto a [Navigator.pop]. This method is
/// called by [Naviagtor.willPop].
///
/// By default, routes veto a pop if they're the first route in the history
/// (i.e., if [isFirst]). This behavior prevents the user from popping the
/// first route off the history and being stranded at a blank screen.
///
/// See also:
///
/// * [Form], which provides an `onWillPop` callback that uses this mechanism.
Future<bool> willPop() async => true;
Future<bool> willPop() async => !isFirst;
/// A request was made to pop this route. If the route can handle it
/// internally (e.g. because it has its own stack of internal state) then
......
......@@ -315,6 +315,11 @@ abstract class LocalHistoryRoute<T> extends Route<T> {
changedInternalState();
}
@override
Future<bool> willPop() async {
return willHandlePopInternally || await super.willPop();
}
@override
bool didPop(T result) {
if (_localHistory != null && _localHistory.isNotEmpty) {
......@@ -401,7 +406,7 @@ class _ModalScope extends StatefulWidget {
class _ModalScopeState extends State<_ModalScope> {
// See addScopedWillPopCallback, removeScopedWillPopCallback in ModalRoute.
List<WillPopCallback> willPopCallbacks = <WillPopCallback>[];
final List<WillPopCallback> _willPopCallbacks = <WillPopCallback>[];
@override
void initState() {
......@@ -424,12 +429,12 @@ class _ModalScopeState extends State<_ModalScope> {
void addWillPopCallback(WillPopCallback callback) {
assert(mounted);
willPopCallbacks.add(callback);
_willPopCallbacks.add(callback);
}
void removeWillPopCallback(WillPopCallback callback) {
assert(mounted);
willPopCallbacks.remove(callback);
_willPopCallbacks.remove(callback);
}
void _animationStatusChanged(AnimationStatus status) {
......@@ -461,7 +466,7 @@ class _ModalScopeState extends State<_ModalScope> {
child: new _ModalScopeStatus(
route: config.route,
isCurrent: config.route.isCurrent,
canPop: config.route.canPop(),
canPop: config.route.canPop,
child: config.page,
),
),
......@@ -655,7 +660,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
ProxyAnimation _forwardAnimationProxy;
/// Return the value of the first callback added with
/// [addScopedWillPopCallback] that returns false. Otherwise return true.
/// [addScopedWillPopCallback] that returns false. Otherwise return
/// [super.willPop()].
///
/// Typically this method is not overridden because applications usually
/// don't create modal routes directly, they use higher level primitives
......@@ -673,11 +679,11 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
Future<bool> willPop() async {
final _ModalScopeState scope = _scopeKey.currentState;
assert(scope != null);
for (WillPopCallback callback in new List<WillPopCallback>.from(scope.willPopCallbacks)) {
for (WillPopCallback callback in new List<WillPopCallback>.from(scope._willPopCallbacks)) {
if (!await callback())
return false;
}
return true;
return await super.willPop();
}
/// Enables this route to veto attempts by the user to dismiss it.
......@@ -754,7 +760,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
/// * [removeScopedWillPopCallback], which removes a callback.
@protected
bool get hasScopedWillPopCallback {
return _scopeKey.currentState == null || _scopeKey.currentState.willPopCallbacks.length > 0;
return _scopeKey.currentState == null || _scopeKey.currentState._willPopCallbacks.length > 0;
}
@override
......@@ -773,7 +779,7 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
///
/// When this changes, the route will rebuild, and any widgets that used
/// [ModalRoute.of] will be notified.
bool canPop() => !isFirst || willHandlePopInternally;
bool get canPop => !isFirst || willHandlePopInternally;
// Internals
......
......@@ -117,4 +117,16 @@ void main() {
expect(buildCounter, 2);
});
testWidgets('Cannot pop the initial route', (WidgetTester tester) async {
await tester.pumpWidget(new MaterialApp(home: new Text('Home')));
expect(find.text('Home'), findsOneWidget);
NavigatorState navigator = tester.state(find.byType(Navigator));
bool result = await navigator.maybePop();
expect(result, isFalse);
expect(find.text('Home'), findsOneWidget);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment