I wanted to create a simple solution to prevent users of my application from forgetting to save their work and navigating away from entry and edit screens. When using ChatGPT, I was constantly told to use 'WillPopScope', but it's being deprecated, so it's not wise to implement something that will not be supported in the future.
The linked documentation above directs you to use PopScope.
Unfortunately, like some others have found, this was not a simple code replacement, and it didn't appear to be a straightforward fit. My objective was to display a pop-up on my entry or edit screens whenever a user tried to navigate away, regardless of whether they used a button in the UI or a swipe gesture. I spent hours trying various solutions from my research online, each one ending in an error in the stack... as if the navigate call had lost its place and didn't know where to return.
After much searching, I came across a thread (linked above) complaining about PopScope and requesting that WillPopScope be kept. Scanning the thread closely, I found a Flutter article discussing breaking changes due to the removal of WillPopScope. Within that thread, I found what appeared to be a solution/approach for my woes: Migrating a Back Confirmation Dialog.
Following this guide, I adjusted my code and within about 10 minutes, I had a working solution on mobile and web (I have aspirations to host my app as a web app at some point) that would alert the user to discarding changes when they navigate away from an entry/edit form using the UI or gestures.
Here is an example of the code I used, function, and implementation:
class MyScreen extends StatelessWidget {
Future<bool?> _showBackDialog(BuildContext context) async {
return showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Discard Edit?"),
content: Text("Are you sure you want to cancel edit?"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(true); // Confirm discard
},
child: Text(
"Yes",
style: Theme.of(context).textTheme.bodyLarge?.merge(
TextStyle(color: Colors.red),
),
),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(false); // Cancel discard
},
child: Text(
"No",
style: Theme.of(context).textTheme.bodyLarge,
),
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Screen'),
),
body: PopScope(
canPop: false,
onPopInvoked: (bool didPop) async {
if (didPop) {
return;
}
final NavigatorState navigator = Navigator.of(context);
final bool? shouldPop = await _showBackDialog(context);
if (shouldPop ?? false) {
navigator.pop();
}
},
child: Center(
child: Text('Press the back button to show confirmation dialog.'),
),
),
);
}
}
void main() {
runApp(MaterialApp(
home: MyScreen(),
));
}
I don't know if this will help anyone else, but I hope so. I posted my solution to the thread with users complaining about their own struggles, and maybe it will aid someone.