1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'form.dart';
6library;
7
8import 'framework.dart';
9import 'navigator.dart';
10import 'routes.dart';
11
12/// Registers a callback to veto attempts by the user to dismiss the enclosing
13/// [ModalRoute].
14///
15/// See also:
16///
17/// * [ModalRoute.addScopedWillPopCallback] and [ModalRoute.removeScopedWillPopCallback],
18/// which this widget uses to register and unregister [onWillPop].
19/// * [Form], which provides an `onWillPop` callback that enables the form
20/// to veto a `pop` initiated by the app's back button.
21@Deprecated(
22 'Use PopScope instead. The Android predictive back feature will not work with WillPopScope. '
23 'This feature was deprecated after v3.12.0-1.0.pre.',
24)
25class WillPopScope extends StatefulWidget {
26 /// Creates a widget that registers a callback to veto attempts by the user to
27 /// dismiss the enclosing [ModalRoute].
28 @Deprecated(
29 'Use PopScope instead. The Android predictive back feature will not work with WillPopScope. '
30 'This feature was deprecated after v3.12.0-1.0.pre.',
31 )
32 const WillPopScope({super.key, required this.child, required this.onWillPop});
33
34 /// The widget below this widget in the tree.
35 ///
36 /// {@macro flutter.widgets.ProxyWidget.child}
37 final Widget child;
38
39 /// Called to veto attempts by the user to dismiss the enclosing [ModalRoute].
40 ///
41 /// If the callback returns a Future that resolves to false, the enclosing
42 /// route will not be popped.
43 final WillPopCallback? onWillPop;
44
45 @override
46 State<WillPopScope> createState() => _WillPopScopeState();
47}
48
49class _WillPopScopeState extends State<WillPopScope> {
50 ModalRoute<dynamic>? _route;
51
52 @override
53 void didChangeDependencies() {
54 super.didChangeDependencies();
55 if (widget.onWillPop != null) {
56 _route?.removeScopedWillPopCallback(widget.onWillPop!);
57 }
58 _route = ModalRoute.of(context);
59 if (widget.onWillPop != null) {
60 _route?.addScopedWillPopCallback(widget.onWillPop!);
61 }
62 }
63
64 @override
65 void didUpdateWidget(WillPopScope oldWidget) {
66 super.didUpdateWidget(oldWidget);
67 if (widget.onWillPop != oldWidget.onWillPop && _route != null) {
68 if (oldWidget.onWillPop != null) {
69 _route!.removeScopedWillPopCallback(oldWidget.onWillPop!);
70 }
71 if (widget.onWillPop != null) {
72 _route!.addScopedWillPopCallback(widget.onWillPop!);
73 }
74 }
75 }
76
77 @override
78 void dispose() {
79 if (widget.onWillPop != null) {
80 _route?.removeScopedWillPopCallback(widget.onWillPop!);
81 }
82 super.dispose();
83 }
84
85 @override
86 Widget build(BuildContext context) => widget.child;
87}
88