### Dart: Programmatically Trigger Back Button with BackButtonInterceptor.popRoute() Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt Demonstrates how to use BackButtonInterceptor.popRoute() to programmatically trigger the back button behavior in a Flutter application. This includes examples of using it within an IconButton, a custom ElevatedButton, and within a testing scenario. The method intercepts and executes registered listeners before the default back navigation occurs. ```dart class CustomBackButton extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Custom Back Button'), // Replace default back button leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () async { // Trigger all interceptors programmatically await BackButtonInterceptor.popRoute(); }, ), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( // Custom button that acts like back button onPressed: BackButtonInterceptor.popRoute, child: const Text('Pop Route'), ), const SizedBox(height: 20), ElevatedButton( onPressed: () async { // Can await and handle result await BackButtonInterceptor.popRoute(); print("Back button processing completed"); }, child: const Text('Pop with Await'), ), ], ), ), ); } } // Testing example void main() { test('popRoute triggers interceptors', () async { bool interceptorFired = false; BackButtonInterceptor.add((stop, info) { interceptorFired = true; return true; }); // Simulate back button press in tests await BackButtonInterceptor.popRoute(); expect(interceptorFired, true); BackButtonInterceptor.removeAll(); }); } ``` -------------------------------- ### Intercept Back Button on Specific Routes with BackButtonInterceptor in Dart Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt This example demonstrates how to get the current route using `BackButtonInterceptor.getCurrentNavigatorRoute()` or `RouteInfo.currentRoute()` and use this information to intercept the back button only on specific routes (e.g., '/settings', '/profile'). It allows conditional interception based on the active route. ```dart class RouteAwareInterceptor extends StatefulWidget { @override State createState() => _RouteAwareInterceptorState(); } class _RouteAwareInterceptorState extends State { @override void initState() { super.initState(); BackButtonInterceptor.add(_handleBackButton, context: context); } @override void dispose() { BackButtonInterceptor.remove(_handleBackButton); super.dispose(); } bool _handleBackButton(bool stopDefaultButtonEvent, RouteInfo info) { // Get current route using RouteInfo Route? currentRoute = info.currentRoute(context); // Or use static method Route? route = BackButtonInterceptor.getCurrentNavigatorRoute(context); String? routeName = route?.settings.name; print("Current route: $routeName"); // Only intercept on specific routes if (routeName == '/settings' || routeName == '/profile') { print("Intercepting back button on $routeName"); _showExitConfirmation(); return true; } // Allow default behavior on other routes return false; } void _showExitConfirmation() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Unsaved Changes'), content: const Text('You have unsaved changes. Exit anyway?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Stay'), ), TextButton( onPressed: () { Navigator.pop(context); // Close dialog Navigator.pop(context); // Go back }, child: const Text('Exit'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Route Aware Interceptor')), body: const Center(child: Text('Back button behavior varies by route')), ); } } ``` -------------------------------- ### Dart: Conditional Back Button Interceptor with ifNotYetIntercepted Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt Demonstrates how to use `ifNotYetIntercepted: true` to create a fallback back button interceptor that executes only if no higher-priority interceptor has already stopped the default back button event. This example uses two interceptors: one to check for unsaved changes (high priority) and another general interceptor (low priority) that acts as a fallback. ```dart class MultiInterceptorExample extends StatefulWidget { @override State createState() => _MultiInterceptorExampleState(); } class _MultiInterceptorExampleState extends State { bool hasUnsavedChanges = true; @override void initState() { super.initState(); // High priority interceptor - checks for unsaved changes BackButtonInterceptor.add( _unsavedChangesInterceptor, name: "UnsavedChanges", zIndex: 10, ); // Low priority interceptor - only runs if previous ones didn't intercept BackButtonInterceptor.add( _generalInterceptor, name: "General", zIndex: 1, ifNotYetIntercepted: true, // Only runs if stopDefaultButtonEvent is false ); } @override void dispose() { BackButtonInterceptor.removeByName("UnsavedChanges"); BackButtonInterceptor.removeByName("General"); super.dispose(); } bool _unsavedChangesInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { if (hasUnsavedChanges) { _showUnsavedDialog(); return true; // Prevent default back action } return false; // Allow next interceptor to run } bool _generalInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { // This only runs if _unsavedChangesInterceptor returned false // because ifNotYetIntercepted: true was set print("No unsaved changes, showing general exit message"); _showGeneralExitDialog(); return true; } void _showUnsavedDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Unsaved Changes'), content: const Text('Save before exiting?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), TextButton( onPressed: () { setState(() => hasUnsavedChanges = false); Navigator.pop(context); // Close dialog Navigator.pop(context); // Go back }, child: const Text('Discard'), ), ], ), ); } void _showGeneralExitDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Exit'), content: const Text('Are you sure you want to leave?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Stay'), ), TextButton( onPressed: () { Navigator.pop(context); Navigator.pop(context); }, child: const Text('Exit'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Multi-Interceptor Example')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Has unsaved changes: $hasUnsavedChanges'), ElevatedButton( onPressed: () => setState(() => hasUnsavedChanges = !hasUnsavedChanges), child: const Text('Toggle Unsaved Changes'), ), ], ), ), ); } } ``` -------------------------------- ### Simulate Back Button Press for Testing - Dart Source: https://github.com/marcglasberg/back_button_interceptor/blob/master/README.md Shows how to programmatically simulate a back button press using `BackButtonInterceptor.popRoute()` for testing purposes. It also mentions accessing recorded results via `BackButtonInterceptor.results` and cleaning up interceptors with `removeAll()`. ```dart // To simulate pressing the back button: BackButtonInterceptor.popRoute(); // To clean up old interceptors between tests: // BackButtonInterceptor.removeAll(); ``` -------------------------------- ### Named Interceptor and Z-Index Management - Dart Source: https://github.com/marcglasberg/back_button_interceptor/blob/master/README.md Illustrates how to add an interceptor with a specific name and z-index for prioritized execution and removal. This allows for more granular control over interceptor management. ```dart @override void initState() { super.initState(); BackButtonInterceptor.add(myInterceptor, zIndex:2, name:"SomeName"); } @override void dispose() { BackButtonInterceptor.removeByName("SomeName"); super.dispose(); } bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { print("BACK BUTTON!"); // Do some stuff. return true; } ``` -------------------------------- ### Debugging Interceptors - Dart Source: https://github.com/marcglasberg/back_button_interceptor/blob/master/README.md Provides a code snippet for debugging interceptors by printing their names and z-indexes to the console using the `BackButtonInterceptor.describe()` static method. ```dart print(BackButtonInterceptor.describe()); ``` -------------------------------- ### Describe Registered Interceptors with BackButtonInterceptor.describe() Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt Retrieves a string describing all currently registered interceptors. This includes their names, z-indexes, and ifNotYetIntercepted status, aiding in debugging complex interceptor configurations. ```dart class InterceptorDebugger extends StatefulWidget { @override State createState() => _InterceptorDebuggerState(); } class _InterceptorDebuggerState extends State { String interceptorDescription = ''; @override void initState() { super.initState(); // Add multiple interceptors with different configurations BackButtonInterceptor.add( _firstInterceptor, name: "FirstInterceptor", zIndex: 100, ); BackButtonInterceptor.add( _secondInterceptor, name: "SecondInterceptor", zIndex: 50, ifNotYetIntercepted: true, ); BackButtonInterceptor.add( _thirdInterceptor, name: "ThirdInterceptor", // No z-index specified ); // Get description for debugging _updateDescription(); } @override void dispose() { BackButtonInterceptor.removeByName("FirstInterceptor"); BackButtonInterceptor.removeByName("SecondInterceptor"); BackButtonInterceptor.removeByName("ThirdInterceptor"); super.dispose(); } void _updateDescription() { setState(() { interceptorDescription = BackButtonInterceptor.describe(); }); print("Current interceptors:\n$interceptorDescription"); } bool _firstInterceptor(bool stop, RouteInfo info) => false; bool _secondInterceptor(bool stop, RouteInfo info) => false; bool _thirdInterceptor(bool stop, RouteInfo info) => false; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Interceptor Debugger')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Registered Interceptors:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), Text(interceptorDescription), const SizedBox(height: 20), ElevatedButton( onPressed: _updateDescription, child: const Text('Refresh Description'), ), ], ), ), ); } } // Example output: // BackButtonInterceptor: FirstInterceptor, z-index: 100 (ifNotYetIntercepted: false). // BackButtonInterceptor: SecondInterceptor, z-index: 50 (ifNotYetIntercepted: true). // BackButtonInterceptor: ThirdInterceptor, z-index: null (ifNotYetIntercepted: false). ``` -------------------------------- ### Conditional Interceptor Execution (Specific Routes) - Dart Source: https://github.com/marcglasberg/back_button_interceptor/blob/master/README.md Shows how to configure an interceptor to only run (or not run) on specific routes by checking against a list of route names using `info.currentRoute(context)`. ```dart bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { if (["myRoute1", "myRoute2", "myRoute3"] .contains(info.currentRoute(context))) return false; // ... rest of interceptor logic } ``` -------------------------------- ### Add and Remove Back Button Interceptor - Dart Source: https://github.com/marcglasberg/back_button_interceptor/blob/master/README.md Demonstrates the basic usage of adding a custom interceptor function to handle back button presses and removing it when the widget is disposed. The interceptor function itself is also shown. ```dart @override void initState() { super.initState(); BackButtonInterceptor.add(myInterceptor); } @override void dispose() { BackButtonInterceptor.remove(myInterceptor); super.dispose(); } bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { print("BACK BUTTON!"); // Do some stuff. return true; } ``` -------------------------------- ### Remove All BackButtonInterceptors in Dart Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt Explains how to remove all registered back button interceptors at once using the `removeAll()` method. This is particularly useful for testing scenarios or when a complete reset of interceptors is needed. It requires the 'back_button_interceptor' and 'flutter_test' packages. ```dart import 'package:flutter_test/flutter_test.dart'; import 'package:back_button_interceptor/back_button_interceptor.dart'; void main() { setUp(() { // Clear all interceptors before each test BackButtonInterceptor.removeAll(); }); testWidgets('back button interceptor test', (WidgetTester tester) async { bool interceptorCalled = false; BackButtonInterceptor.add((stopDefaultButtonEvent, info) { interceptorCalled = true; return true; }); // Simulate back button press await BackButtonInterceptor.popRoute(); expect(interceptorCalled, true); // Clean up after test BackButtonInterceptor.removeAll(); }); test('multiple interceptors are called in order', () async { List callOrder = []; BackButtonInterceptor.add( (stop, info) { callOrder.add('first'); return false; }, zIndex: 1, ); BackButtonInterceptor.add( (stop, info) { callOrder.add('second'); return false; }, zIndex: 2, ); await BackButtonInterceptor.popRoute(); expect(callOrder, ['second', 'first']); // Higher z-index called first BackButtonInterceptor.removeAll(); }); } ``` -------------------------------- ### Conditional Interceptor Execution (Route Changed) - Dart Source: https://github.com/marcglasberg/back_button_interceptor/blob/master/README.md Demonstrates how to make an interceptor function conditionally execute only if the route has changed since the interceptor was added, using `info.ifRouteChanged(context)`. This is useful for disabling interceptors during temporary state changes like dialogs. ```dart bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { if (info.ifRouteChanged(context)) return false; // ... rest of interceptor logic } ``` -------------------------------- ### Remove BackButtonInterceptor by Name in Dart Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt Demonstrates how to remove a registered back button interceptor using its unique name. This is useful for managing interceptors from different parts of your application or when function references are not readily available. It requires the 'back_button_interceptor' package. ```dart class NamedInterceptorExample extends StatefulWidget { @override State createState() => _NamedInterceptorExampleState(); } class _NamedInterceptorExampleState extends State { @override void initState() { super.initState(); // Add interceptor with a name BackButtonInterceptor.add( _myInterceptor, name: "UniqueInterceptorName", zIndex: 10, ); } @override void dispose() { // Remove by name instead of function reference BackButtonInterceptor.removeByName("UniqueInterceptorName"); super.dispose(); } bool _myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { print("Named interceptor called"); return false; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Named Interceptor')), body: Center( child: ElevatedButton( onPressed: () { // Can remove from anywhere in the code BackButtonInterceptor.removeByName("UniqueInterceptorName"); }, child: const Text('Remove Interceptor'), ), ), ); } } ``` -------------------------------- ### Add and Remove Back Button Interceptor in Flutter Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt Demonstrates how to add a custom interceptor function using BackButtonInterceptor.add() and remove it using BackButtonInterceptor.remove() in a Flutter StatefulWidget. The interceptor function can conditionally prevent the default back button behavior based on route information and other factors. It's crucial to remove interceptors in the dispose method to prevent memory leaks. ```dart import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:flutter/material.dart'; class Demo extends StatefulWidget { @override DemoState createState() => DemoState(); } class DemoState extends State { @override void initState() { super.initState(); // Add interceptor with name and z-index BackButtonInterceptor.add( myInterceptor, name: "DemoInterceptor", zIndex: 1, context: context, ); } @override void dispose() { BackButtonInterceptor.remove(myInterceptor); super.dispose(); } bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { // Check if another interceptor already handled the event if (stopDefaultButtonEvent) return false; // Only run if route hasn't changed (e.g., no dialog is open) if (info.ifRouteChanged(context)) return false; // Perform custom logic print("BACK BUTTON PRESSED!"); // Return true to prevent default back action (route pop) return true; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Back Button Example')), body: const Center(child: Text('Press the back button')), ); } } class MyWidget extends StatefulWidget { @override MyWidgetState createState() => MyWidgetState(); } class MyWidgetState extends State { @override void initState() { super.initState(); BackButtonInterceptor.add(_handleBackButton); } @override void dispose() { // Always remove interceptors in dispose BackButtonInterceptor.remove(_handleBackButton); super.dispose(); } bool _handleBackButton(bool stopDefaultButtonEvent, RouteInfo info) { // Show confirmation dialog showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Exit?'), content: const Text('Do you want to leave this page?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), TextButton( onPressed: () { Navigator.pop(context); Navigator.pop(context); }, child: const Text('Exit'), ), ], ), ); return true; // Prevent default back action } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('My Widget')), body: const Center(child: Text('Content here')), ); } } ``` -------------------------------- ### Check Route Change with BackButtonInterceptor in Dart Source: https://context7.com/marcglasberg/back_button_interceptor/llms.txt This snippet shows how to use `RouteInfo.ifRouteChanged()` to check if the current route has changed since the interceptor was registered. It prevents interceptors from firing when other routes (like dialogs or bottom sheets) are open on top of the original route. The interceptor conditionally disables itself if the route has changed. ```dart class ContainerWithInterceptor extends StatefulWidget { final String name; const ContainerWithInterceptor(this.name); @override State createState() => _ContainerWithInterceptorState(); } class _ContainerWithInterceptorState extends State { bool hasIntercepted = false; @override void initState() { super.initState(); // IMPORTANT: Pass context to enable route tracking BackButtonInterceptor.add( myInterceptor, name: widget.name, context: context, // Required for ifRouteChanged() to work ); } @override void dispose() { BackButtonInterceptor.remove(myInterceptor); super.dispose(); } bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) { // Don't intercept if already handled by previous interceptor if (stopDefaultButtonEvent) return false; // Skip interceptor if a dialog or other route is open if (info.ifRouteChanged(context)) { print("Route changed, interceptor disabled"); return false; } if (!hasIntercepted) { setState(() => hasIntercepted = true); print("Intercepted on original route"); return true; } return false; } @override Widget build(BuildContext context) { return Container( color: hasIntercepted ? Colors.blue : Colors.red, height: 100, width: 100, child: Center( child: ElevatedButton( onPressed: () { // Open dialog - interceptor will be disabled while dialog is open showDialog( context: context, builder: (context) => AlertDialog( title: const Text("Dialog"), content: const Text("Interceptor is disabled while this is open"), ), ); }, child: const Text('Open Dialog'), ), ), ); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.