Unverified Commit 204a8848 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

PopScope example improvements (#142163)

Attempting to help users understand how to build a confirmation dialog when exiting a route.
parent e985c29f
...@@ -62,8 +62,13 @@ class _SaveableFormState extends State<_SaveableForm> { ...@@ -62,8 +62,13 @@ class _SaveableFormState extends State<_SaveableForm> {
}); });
} }
Future<void> _showDialog() async { /// Shows a dialog and resolves to true when the user has indicated that they
final bool? shouldDiscard = await showDialog<bool>( /// want to pop.
///
/// A return value of null indicates a desire not to pop, such as when the
/// user has dismissed the modal without tapping a button.
Future<bool?> _showDialog() {
return showDialog<bool>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
...@@ -86,19 +91,13 @@ class _SaveableFormState extends State<_SaveableForm> { ...@@ -86,19 +91,13 @@ class _SaveableFormState extends State<_SaveableForm> {
); );
}, },
); );
if (shouldDiscard ?? false) {
// Since this is the root route, quit the app where possible by invoking
// the SystemNavigator. If this wasn't the root route, then
// Navigator.maybePop could be used instead.
// See https://github.com/flutter/flutter/issues/11490
SystemNavigator.pop();
}
} }
void _save(String? value) { void _save(String? value) {
final String nextSavedValue = value ?? '';
setState(() { setState(() {
_savedValue = value ?? ''; _savedValue = nextSavedValue;
_isDirty = nextSavedValue != _controller.text;
}); });
} }
...@@ -112,11 +111,18 @@ class _SaveableFormState extends State<_SaveableForm> { ...@@ -112,11 +111,18 @@ class _SaveableFormState extends State<_SaveableForm> {
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Form( Form(
canPop: !_isDirty, canPop: !_isDirty,
onPopInvoked: (bool didPop) { onPopInvoked: (bool didPop) async {
if (didPop) { if (didPop) {
return; return;
} }
_showDialog(); final bool shouldPop = await _showDialog() ?? false;
if (shouldPop) {
// Since this is the root route, quit the app where possible by
// invoking the SystemNavigator. If this wasn't the root route,
// then Navigator.maybePop could be used instead.
// See https://github.com/flutter/flutter/issues/11490
SystemNavigator.pop();
}
}, },
autovalidateMode: AutovalidateMode.always, autovalidateMode: AutovalidateMode.always,
child: Column( child: Column(
...@@ -146,9 +152,9 @@ class _SaveableFormState extends State<_SaveableForm> { ...@@ -146,9 +152,9 @@ class _SaveableFormState extends State<_SaveableForm> {
), ),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () async {
if (_isDirty) { final bool shouldPop = !_isDirty || (await _showDialog() ?? false);
_showDialog(); if (!shouldPop) {
return; return;
} }
// Since this is the root route, quit the app where possible by // Since this is the root route, quit the app where possible by
......
...@@ -62,8 +62,13 @@ class _PageTwo extends StatefulWidget { ...@@ -62,8 +62,13 @@ class _PageTwo extends StatefulWidget {
} }
class _PageTwoState extends State<_PageTwo> { class _PageTwoState extends State<_PageTwo> {
void _showBackDialog() { /// Shows a dialog and resolves to true when the user has indicated that they
showDialog<void>( /// want to pop.
///
/// A return value of null indicates a desire not to pop, such as when the
/// user has dismissed the modal without tapping a button.
Future<bool?> _showBackDialog() {
return showDialog<bool>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
...@@ -78,7 +83,7 @@ class _PageTwoState extends State<_PageTwo> { ...@@ -78,7 +83,7 @@ class _PageTwoState extends State<_PageTwo> {
), ),
child: const Text('Nevermind'), child: const Text('Nevermind'),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context, false);
}, },
), ),
TextButton( TextButton(
...@@ -87,8 +92,7 @@ class _PageTwoState extends State<_PageTwo> { ...@@ -87,8 +92,7 @@ class _PageTwoState extends State<_PageTwo> {
), ),
child: const Text('Leave'), child: const Text('Leave'),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context, true);
Navigator.pop(context);
}, },
), ),
], ],
...@@ -107,15 +111,21 @@ class _PageTwoState extends State<_PageTwo> { ...@@ -107,15 +111,21 @@ class _PageTwoState extends State<_PageTwo> {
const Text('Page Two'), const Text('Page Two'),
PopScope( PopScope(
canPop: false, canPop: false,
onPopInvoked: (bool didPop) { onPopInvoked: (bool didPop) async {
if (didPop) { if (didPop) {
return; return;
} }
_showBackDialog(); final bool shouldPop = await _showBackDialog() ?? false;
if (context.mounted && shouldPop) {
Navigator.pop(context);
}
}, },
child: TextButton( child: TextButton(
onPressed: () { onPressed: () async {
_showBackDialog(); final bool shouldPop = await _showBackDialog() ?? false;
if (context.mounted && shouldPop) {
Navigator.pop(context);
}
}, },
child: const Text('Go back'), child: const Text('Go back'),
), ),
......
...@@ -26,8 +26,8 @@ import 'routes.dart'; ...@@ -26,8 +26,8 @@ import 'routes.dart';
/// [PopScope], in which case it will be `false`. /// [PopScope], in which case it will be `false`.
/// ///
/// {@tool dartpad} /// {@tool dartpad}
/// This sample demonstrates how to use this widget to handle nested navigation /// This sample demonstrates showing a confirmation dialog before navigating
/// in a bottom navigation bar. /// away from a page.
/// ///
/// ** See code in examples/api/lib/widgets/pop_scope/pop_scope.0.dart ** /// ** See code in examples/api/lib/widgets/pop_scope/pop_scope.0.dart **
/// {@end-tool} /// {@end-tool}
......
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