Line data Source code
1 : import 'package:beamer/beamer.dart';
2 : import 'package:flutter/widgets.dart';
3 :
4 : import 'package:beamer/src/path_url_strategy_nonweb.dart'
5 : if (dart.library.html) 'path_url_strategy_web.dart' as url_strategy;
6 :
7 : /// Represents a navigation area and is a wrapper for [Router].
8 : ///
9 : /// This is most commonly used for "nested navigation", e.g. in a tabbed view.
10 : /// Each [Beamer] has its own navigation rules, but can communicate with its parent [Router].
11 : class Beamer extends StatefulWidget {
12 : /// Creates a [Beamer] with specified properties.
13 : ///
14 : /// [routerDelegate] is required because it handles the navigation within the
15 : /// "sub-navigation module" represented by this.
16 3 : const Beamer({
17 : Key? key,
18 : required this.routerDelegate,
19 : this.createBackButtonDispatcher = true,
20 : this.backButtonDispatcher,
21 3 : }) : super(key: key);
22 :
23 : /// Responsible for beaming, updating and rebuilding the page stack.
24 : final BeamerDelegate routerDelegate;
25 :
26 : /// Whether to create a [BeamerChildBackButtonDispatcher] automatically
27 : /// if the [backButtonDispatcher] is not set but parent has it.
28 : final bool createBackButtonDispatcher;
29 :
30 : /// Define how Android's back button should behave.
31 : ///
32 : /// Use [BeamerChildBackButtonDispatcher]
33 : /// instead of [BeamerBackButtonDispatcher].
34 : final BackButtonDispatcher? backButtonDispatcher;
35 :
36 : /// Access Beamer's [routerDelegate].
37 2 : static BeamerDelegate of(BuildContext context, {bool root = false}) {
38 : BeamerDelegate _delegate;
39 : try {
40 4 : _delegate = Router.of(context).routerDelegate as BeamerDelegate;
41 : } catch (e) {
42 1 : assert(BeamerProvider.of(context) != null,
43 : 'There was no Router nor BeamerProvider in current context. If using MaterialApp.builder, wrap the MaterialApp.router in BeamerProvider to which you pass the same routerDelegate as to MaterialApp.router.');
44 2 : return BeamerProvider.of(context)!.routerDelegate;
45 : }
46 : if (root) {
47 1 : return _delegate.root;
48 : }
49 : return _delegate;
50 : }
51 :
52 : /// Change the strategy to use for handling browser URL to [PathUrlStrategy].
53 : ///
54 : /// [PathUrlStrategy] uses the browser URL's pathname to represent Beamer's route name.
55 2 : static void setPathUrlStrategy() => url_strategy.setPathUrlStrategy();
56 :
57 3 : @override
58 3 : State<StatefulWidget> createState() => BeamerState();
59 : }
60 :
61 : /// A [State] for [Beamer].
62 : class BeamerState extends State<Beamer> {
63 : /// A getter for [BeamerDelegate] of the [Beamer] whose state is this.
64 9 : BeamerDelegate get routerDelegate => widget.routerDelegate;
65 :
66 : /// A convenience getter for current [BeamLocation] of [routerDelegate].
67 3 : BeamLocation get currentBeamLocation => routerDelegate.currentBeamLocation;
68 :
69 3 : @override
70 : void didChangeDependencies() {
71 3 : super.didChangeDependencies();
72 6 : routerDelegate.parent ??=
73 9 : Router.of(context).routerDelegate as BeamerDelegate;
74 : }
75 :
76 3 : @override
77 : Widget build(BuildContext context) {
78 3 : final parent = Router.of(context);
79 6 : routerDelegate.parent ??= parent.routerDelegate as BeamerDelegate;
80 6 : final backButtonDispatcher = widget.backButtonDispatcher ??
81 6 : ((parent.backButtonDispatcher is BeamerBackButtonDispatcher &&
82 2 : widget.createBackButtonDispatcher)
83 1 : ? BeamerChildBackButtonDispatcher(
84 : parent:
85 1 : parent.backButtonDispatcher! as BeamerBackButtonDispatcher,
86 1 : delegate: routerDelegate,
87 : )
88 : : null);
89 3 : return Router(
90 3 : routerDelegate: routerDelegate,
91 1 : backButtonDispatcher: backButtonDispatcher?..takePriority(),
92 : );
93 : }
94 : }
95 :
96 : /// Some beamer-specific extension methods on [BuildContext].
97 : extension BeamerExtensions on BuildContext {
98 : /// {@macro beamTo}
99 1 : void beamTo(
100 : BeamLocation location, {
101 : Object? data,
102 : BeamLocation? popTo,
103 : TransitionDelegate? transitionDelegate,
104 : bool beamBackOnPop = false,
105 : bool popBeamLocationOnPop = false,
106 : bool stacked = true,
107 : }) {
108 2 : Beamer.of(this).beamTo(
109 : location,
110 : data: data,
111 : popTo: popTo,
112 : transitionDelegate: transitionDelegate,
113 : beamBackOnPop: beamBackOnPop,
114 : popBeamLocationOnPop: popBeamLocationOnPop,
115 : stacked: stacked,
116 : );
117 : }
118 :
119 : /// {@macro beamToReplacement}
120 0 : void beamToReplacement(
121 : BeamLocation location, {
122 : Object? data,
123 : BeamLocation? popTo,
124 : TransitionDelegate? transitionDelegate,
125 : bool beamBackOnPop = false,
126 : bool popBeamLocationOnPop = false,
127 : bool stacked = true,
128 : }) {
129 0 : Beamer.of(this).beamToReplacement(
130 : location,
131 : data: data,
132 : popTo: popTo,
133 : transitionDelegate: transitionDelegate,
134 : beamBackOnPop: beamBackOnPop,
135 : popBeamLocationOnPop: popBeamLocationOnPop,
136 : stacked: stacked,
137 : );
138 : }
139 :
140 : /// {@macro beamToNamed}
141 1 : void beamToNamed(
142 : String uri, {
143 : Object? routeState,
144 : Object? data,
145 : String? popToNamed,
146 : TransitionDelegate? transitionDelegate,
147 : bool beamBackOnPop = false,
148 : bool popBeamLocationOnPop = false,
149 : bool stacked = true,
150 : }) {
151 2 : Beamer.of(this).beamToNamed(
152 : uri,
153 : routeState: routeState,
154 : data: data,
155 : popToNamed: popToNamed,
156 : transitionDelegate: transitionDelegate,
157 : beamBackOnPop: beamBackOnPop,
158 : popBeamLocationOnPop: popBeamLocationOnPop,
159 : stacked: stacked,
160 : );
161 : }
162 :
163 : /// {@macro beamToReplacementNamed}
164 0 : void beamToReplacementNamed(
165 : String uri, {
166 : Object? routeState,
167 : Object? data,
168 : String? popToNamed,
169 : TransitionDelegate? transitionDelegate,
170 : bool beamBackOnPop = false,
171 : bool popBeamLocationOnPop = false,
172 : bool stacked = true,
173 : }) {
174 0 : Beamer.of(this).beamToReplacementNamed(
175 : uri,
176 : routeState: routeState,
177 : data: data,
178 : popToNamed: popToNamed,
179 : transitionDelegate: transitionDelegate,
180 : beamBackOnPop: beamBackOnPop,
181 : popBeamLocationOnPop: popBeamLocationOnPop,
182 : stacked: stacked,
183 : );
184 : }
185 :
186 : /// {@macro popToNamed}
187 1 : void popToNamed(
188 : String uri, {
189 : Object? routeState,
190 : Object? data,
191 : String? popToNamed,
192 : bool beamBackOnPop = false,
193 : bool popBeamLocationOnPop = false,
194 : bool stacked = true,
195 : }) {
196 2 : Beamer.of(this).popToNamed(
197 : uri,
198 : routeState: routeState,
199 : data: data,
200 : popToNamed: popToNamed,
201 : beamBackOnPop: beamBackOnPop,
202 : popBeamLocationOnPop: popBeamLocationOnPop,
203 : stacked: stacked,
204 : );
205 : }
206 :
207 : /// {@macro beamBack}
208 3 : void beamBack({Object? data}) => Beamer.of(this).beamBack(data: data);
209 :
210 : /// {@macro popBeamLocation}
211 3 : void popBeamLocation() => Beamer.of(this).popBeamLocation();
212 :
213 : /// {@macro currentBeamLocation}
214 3 : BeamLocation get currentBeamLocation => Beamer.of(this).currentBeamLocation;
215 :
216 : /// {@macro currentPages}
217 3 : List<BeamPage> get currentBeamPages => Beamer.of(this).currentPages;
218 :
219 : /// {@macro beamingHistory}
220 3 : List<BeamLocation> get beamingHistory => Beamer.of(this).beamingHistory;
221 :
222 : /// {@macro canBeamBack}
223 3 : bool get canBeamBack => Beamer.of(this).canBeamBack;
224 :
225 : /// {@macro canPopBeamLocation}
226 3 : bool get canPopBeamLocation => Beamer.of(this).canPopBeamLocation;
227 : }
228 :
229 : /// Some convenient extension methods on [RouteInformation].
230 : extension BeamerRouteInformationExtension on RouteInformation {
231 : /// Returns a new [RouteInformation] created from this.
232 7 : RouteInformation copyWith({
233 : String? location,
234 : Object? state,
235 : }) {
236 7 : return RouteInformation(
237 7 : location: location ?? this.location,
238 7 : state: state ?? this.state,
239 : );
240 : }
241 : }
|