Line data Source code
1 : part of '../main.dart';
2 :
3 : @immutable
4 : abstract class VRouteElement {
5 : /// A list of stackedRoutes composed of any type of [VRouteElement]
6 : List<VRouteElement> get stackedRoutes;
7 :
8 : VRoute? buildRoute(
9 : VPathRequestData vPathRequestData, {
10 : required String? parentRemainingPath,
11 : required Map<String, String> parentPathParameters,
12 : });
13 :
14 : /// This function takes a name and tries to find the path corresponding to
15 : /// the route matching this name
16 : ///
17 : /// The deeper nested the route the better
18 : /// The given path parameters have to include at least every path parameters of the final path
19 5 : String? getPathFromName(
20 : String nameToMatch, {
21 : required Map<String, String> pathParameters,
22 : required String? parentPath,
23 : required Map<String, String> remainingPathParameters,
24 : }) {
25 : // Check if any subroute matches the name
26 10 : for (var vRouteElement in stackedRoutes) {
27 5 : String? childPathFromName = vRouteElement.getPathFromName(
28 : nameToMatch,
29 : pathParameters: pathParameters,
30 : parentPath: parentPath,
31 : remainingPathParameters: remainingPathParameters,
32 : );
33 : if (childPathFromName != null) {
34 : return childPathFromName;
35 : }
36 : }
37 :
38 : // Else we return null
39 : return null;
40 : }
41 :
42 : /// [GetPathFromPopResult.didPop] is true if this [VRouteElement] popped
43 : /// [GetPathFromPopResult.path] is null if this path can't be the right one according to
44 : /// the path parameters
45 : /// [GetPathFromPopResult] is null when this [VRouteElement] does not pop AND none of
46 : /// its stackedRoutes popped
47 11 : GetPathFromPopResult? getPathFromPop(
48 : VRouteElement elementToPop, {
49 : required Map<String, String> pathParameters,
50 : required String? parentPath,
51 : }) {
52 : // Try to pop from the stackedRoutes
53 22 : for (var vRouteElement in stackedRoutes) {
54 11 : final childPopResult = vRouteElement.getPathFromPop(
55 : elementToPop,
56 : pathParameters: pathParameters,
57 : parentPath: parentPath,
58 : );
59 : if (childPopResult != null) {
60 : return childPopResult;
61 : }
62 : }
63 :
64 : // If none of the stackedRoutes popped and this did not pop, return a null result
65 : return null;
66 : }
67 :
68 : /// This is called before the url is updated if this [VRouteElement] was NOT in the
69 : /// previous route but is in the new route
70 : ///
71 : /// Use [vRedirector] if you want to redirect or stop the navigation.
72 : /// DO NOT use VRouter methods to redirect.
73 : /// [vRedirector] also has information about the route you leave and the route you go to
74 : ///
75 : /// Note that you should consider the navigation cycle to
76 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
77 : ///
78 : /// Also see:
79 : /// * [VRouter.beforeEnter] for router level beforeEnter
80 : /// * [VRedirector] to known how to redirect and have access to route information
81 11 : Future<void> Function(VRedirector vRedirector) get beforeEnter =>
82 : _voidBeforeEnter;
83 :
84 : /// This is called before the url is updated if this [VRouteElement] was in the previous
85 : /// route and is in the new route
86 : ///
87 : /// Use [vRedirector] if you want to redirect or stop the navigation.
88 : /// DO NOT use VRouter methods to redirect.
89 : /// [vRedirector] also has information about the route you leave and the route you go to
90 : ///
91 : /// Note that you should consider the navigation cycle to
92 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
93 : ///
94 : /// Also see:
95 : /// * [VNavigationGuard.beforeUpdate] for widget level beforeUpdate
96 : /// * [VRedirector] to known how to redirect and have access to route information
97 19 : Future<void> Function(VRedirector vRedirector) get beforeUpdate =>
98 : _voidBeforeUpdate;
99 :
100 : /// Called when a url changes, before the url is updated
101 : /// Use [vRedirector] if you want to redirect or stop the navigation.
102 : /// DO NOT use VRouter methods to redirect.
103 : /// [vRedirector] also has information about the route you leave and the route you go to
104 : ///
105 : /// [saveHistoryState] can be used to save a history state before leaving
106 : /// This history state will be restored if the user uses the back button
107 : /// You will find the saved history state in the [VRouteElementData] using
108 : /// [VRouterData.of(context).historyState]
109 : ///
110 : /// Note that you should consider the navigation cycle to
111 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
112 : ///
113 : /// Also see:
114 : /// * [VRouteElement.beforeLeave] for route level beforeLeave
115 : /// * [VNavigationGuard.beforeLeave] for widget level beforeLeave
116 : /// * [VRedirector] to known how to redirect and have access to route information
117 8 : Future<void> Function(
118 : VRedirector vRedirector,
119 : void Function(Map<String, String> state) saveHistoryState,
120 : ) get beforeLeave => _voidBeforeLeave;
121 :
122 : /// This is called after the url and the historyState are updated and this [VRouteElement]
123 : /// was NOT in the previous route and is in the new route
124 : /// You can't prevent the navigation anymore
125 : /// You can get the new route parameters, and queryParameters
126 : ///
127 : /// Note that you should consider the navigation cycle to
128 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
129 : ///
130 : /// Also see:
131 : /// * [VRouter.afterEnter] for router level afterEnter
132 : /// * [VNavigationGuard.afterEnter] for widget level afterEnter
133 11 : void Function(BuildContext context, String? from, String to) get afterEnter =>
134 : _voidAfterEnter;
135 :
136 : /// This is called after the url and the historyState are updated and this [VRouteElement]
137 : /// was in the previous route and is in the new route
138 : /// You can't prevent the navigation anymore
139 : /// You can get the new route parameters, and queryParameters
140 : ///
141 : /// Note that you should consider the navigation cycle to
142 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
143 : ///
144 : /// Also see:
145 : /// * [VNavigationGuard.afterUpdate] for widget level afterUpdate
146 19 : void Function(BuildContext context, String? from, String to)
147 : get afterUpdate => _voidAfterUpdate;
148 :
149 : /// Called when a pop event occurs
150 : /// A pop event can be called programmatically (with [VRouterData.of(context).pop()])
151 : /// or by other widgets such as the appBar back button
152 : ///
153 : /// Use [vRedirector] if you want to redirect or stop the navigation.
154 : /// DO NOT use VRouter methods to redirect.
155 : /// [vRedirector] also has information about the route you leave and the route you go to
156 : ///
157 : /// The route you go to is calculated based on [VRouterState._defaultPop]
158 : ///
159 : /// Note that you should consider the pop cycle to
160 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Pop%20Events/onPop]
161 : ///
162 : /// Also see:
163 : /// * [VRouter.onPop] for router level onPop
164 : /// * [VNavigationGuard.onPop] for widget level onPop
165 : /// * [VRedirector] to known how to redirect and have access to route information
166 7 : Future<void> Function(VRedirector vRedirector) get onPop => _voidOnPop;
167 :
168 : /// Called when a system pop event occurs.
169 : /// This happens on android when the system back button is pressed.
170 : ///
171 : /// Use [vRedirector] if you want to redirect or stop the navigation.
172 : /// DO NOT use VRouter methods to redirect.
173 : /// [vRedirector] also has information about the route you leave and the route you go to
174 : ///
175 : /// The route you go to is calculated based on [VRouterState._defaultPop]
176 : ///
177 : /// Note that you should consider the systemPop cycle to
178 : /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Pop%20Events/onSystemPop]
179 : ///
180 : /// Also see:
181 : /// * [VRouter.onSystemPop] for route level onSystemPop
182 : /// * [VNavigationGuard.onSystemPop] for widget level onSystemPop
183 : /// * [VRedirector] to known how to redirect and have access to route information
184 4 : Future<void> Function(VRedirector vRedirector) get onSystemPop =>
185 : _voidOnSystemPop;
186 :
187 : /// Default function for [VRouteElement.beforeEnter]
188 : /// Basically does nothing
189 10 : static Future<void> _voidBeforeEnter(VRedirector vRedirector) async {}
190 :
191 : /// Default function for [VRouteElement.beforeUpdate]
192 : /// Basically does nothing
193 10 : static Future<void> _voidBeforeUpdate(VRedirector vRedirector) async {}
194 :
195 : /// Default function for [VRouteElement.beforeLeave]
196 : /// Basically does nothing
197 9 : static Future<void> _voidBeforeLeave(
198 : VRedirector? vRedirector,
199 : void Function(Map<String, String> state) saveHistoryState,
200 : ) async {}
201 :
202 : /// Default function for [VRouteElement.afterEnter]
203 : /// Basically does nothing
204 10 : static void _voidAfterEnter(BuildContext context, String? from, String to) {}
205 :
206 : /// Default function for [VRouteElement.afterUpdate]
207 : /// Basically does nothing
208 10 : static void _voidAfterUpdate(BuildContext context, String? from, String to) {}
209 :
210 : /// Default function for [VRouteElement.onPop]
211 : /// Basically does nothing
212 7 : static Future<void> _voidOnPop(VRedirector vRedirector) async {}
213 :
214 : /// Default function for [VRouteElement.pnSystemPop]
215 : /// Basically does nothing
216 4 : static Future<void> _voidOnSystemPop(VRedirector vRedirector) async {}
217 : }
218 :
219 : /// Return type of [VRouteElement.getPathFromPop]
220 : ///
221 : /// [didPop] should be true if this [VRouteElement] is to be popped
222 : /// [path] should be deducted from the parent path, [VRouteElement.path] and the path parameters,
223 : /// Note the it should be null if the path can not be deduced from the said parameters
224 : class GetPathFromPopResult {
225 : final String? path;
226 : final bool didPop;
227 :
228 8 : GetPathFromPopResult({
229 : required this.path,
230 : required this.didPop,
231 : });
232 : }
233 :
234 : /// Hold every information of the current route we are building
235 : /// This is used is [VRouteElement.buildRoute] and should be passed down to the next
236 : /// [VRouteElement.buildRoute] without modification.
237 : ///
238 : /// The is used for two purposes:
239 : /// 1. Giving the needed information for [VRouteElement.buildRoute] to decide how/if it should
240 : /// build its route
241 : /// 2. Holds information that are used to populate the [LocalVRouterData] attached to every
242 : /// _ [VRouteElement]
243 : class VPathRequestData {
244 : final String? previousUrl;
245 : final Uri uri;
246 : final Map<String, String> historyState;
247 : final BuildContext rootVRouterContext;
248 :
249 10 : VPathRequestData({
250 : required this.previousUrl,
251 : required this.uri,
252 : required this.historyState,
253 : required this.rootVRouterContext,
254 : });
255 :
256 30 : String get path => uri.path;
257 :
258 30 : Map<String, String> get queryParameters => uri.queryParameters;
259 :
260 30 : String get url => uri.toString();
261 : }
262 :
263 : /// [VRouteElementNode] is used to represent the current route configuration as a tree
264 : class VRouteElementNode {
265 : /// The [VRouteElementNode] containing the [VRouteElement] which is the current nested route
266 : /// to be valid, if any
267 : ///
268 : /// The is used be all types of [VNestedPage]
269 : final VRouteElementNode? nestedVRouteElementNode;
270 :
271 : /// The [VRouteElementNode] containing the [VRouteElement] which is the current stacked routes
272 : /// to be valid, if any
273 : final VRouteElementNode? stackedVRouteElementNode;
274 :
275 : /// The [VRouteElement] attached to this node
276 : final VRouteElement vRouteElement;
277 :
278 10 : VRouteElementNode(
279 : this.vRouteElement, {
280 : this.nestedVRouteElementNode,
281 : this.stackedVRouteElementNode,
282 : });
283 :
284 : /// Finding the element to pop for a [VRouteElementNode] means finding which one is at the
285 : /// end of the chain of stackedVRouteElementNode (if none then this should be popped)
286 7 : VRouteElement getVRouteElementToPop() {
287 7 : if (stackedVRouteElementNode != null) {
288 8 : return stackedVRouteElementNode!.getVRouteElementToPop();
289 : }
290 7 : return vRouteElement;
291 : }
292 :
293 : /// This function will search this node and the nested and sub nodes to try to find the node
294 : /// that hosts [vRouteElement]
295 1 : VRouteElementNode? getChildVRouteElementNode({
296 : required VRouteElement vRouteElement,
297 : }) {
298 : // If this VRouteElementNode contains the given VRouteElement, return this
299 2 : if (vRouteElement == this.vRouteElement) {
300 : return this;
301 : }
302 :
303 : // Search if the VRouteElementNode containing the VRouteElement is in the nestedVRouteElementNode
304 1 : if (nestedVRouteElementNode != null) {
305 0 : VRouteElementNode? vRouteElementNode = nestedVRouteElementNode!
306 0 : .getChildVRouteElementNode(vRouteElement: vRouteElement);
307 : if (vRouteElementNode != null) {
308 : return vRouteElementNode;
309 : }
310 : }
311 :
312 : // Search if the VRouteElementNode containing the VRouteElement is in the stackedVRouteElementNode
313 1 : if (stackedVRouteElementNode != null) {
314 1 : VRouteElementNode? vRouteElementNode = stackedVRouteElementNode!
315 1 : .getChildVRouteElementNode(vRouteElement: vRouteElement);
316 : if (vRouteElementNode != null) {
317 : return vRouteElementNode;
318 : }
319 : }
320 :
321 : // If the VRouteElement was not find anywhere, return null
322 : return null;
323 : }
324 : }
|