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