Line data Source code
1 : part of '../main.dart';
2 :
3 : /// An [InheritedWidget] accessible via [VRouter.of(context)]
4 : ///
5 : /// [LocalVRouterData] is placed on top of each [VRouteElement._rootVRouter], the main goal of having
6 : /// local classes compared to a single one is that:
7 : /// 1. [_vRouteElementNode] is specific to the local [VRouteElement] to allow a different
8 : /// _ pop event based on where the [VRouteElement] is in the [VRoute]
9 : /// 2. When a [VRouteElement] is no longer in the route, it has a page animation out. During
10 : /// _ this, the old VRouterData should be used, which this [LocalVRouterData] holds
11 : class LocalVRouterData extends VRouterData {
12 : /// The [VRouteElementNode] of the associated [VRouteElement]
13 : final VRouteElementNode _vRouteElementNode;
14 :
15 : /// A [BuildContext] which can be used to access the [RootVRouterData]
16 : final BuildContext _rootVRouterDataContext;
17 :
18 12 : LocalVRouterData({
19 : Key? key,
20 : required Widget child,
21 : required this.url,
22 : required this.previousUrl,
23 : required this.historyState,
24 : required this.pathParameters,
25 : required this.queryParameters,
26 : required VRouteElementNode vRouteElementNode,
27 : required BuildContext context,
28 : }) : _vRouteElementNode = vRouteElementNode,
29 : _rootVRouterDataContext = context,
30 12 : super(
31 : key: key,
32 : child: child,
33 : );
34 :
35 11 : @override
36 : bool updateShouldNotify(LocalVRouterData old) {
37 33 : return (old.url != url ||
38 3 : old.previousUrl != previousUrl ||
39 0 : old.historyState != historyState ||
40 0 : old.pathParameters != pathParameters ||
41 0 : old.queryParameters != queryParameters);
42 : }
43 :
44 : /// Url currently synced with the state
45 : /// This url can differ from the once of the browser if
46 : /// the state has been yet been updated
47 : final String? url;
48 :
49 : /// Previous url that was synced with the state
50 : final String? previousUrl;
51 :
52 : /// This state is saved in the browser history. This means that if the user presses
53 : /// the back or forward button on the navigator, this historyState will be the same
54 : /// as the last one you saved.
55 : ///
56 : /// It can be changed by using [VRouteElementWidgetData.of(context).replaceHistoryState(newState)]
57 : ///
58 : /// Also see:
59 : /// * [VRouteElementData.historyState] if you want to use a local level
60 : /// version of the historyState
61 : /// * [VRouterData.historyState] if you want to use a router level
62 : /// version of the historyState
63 : final Map<String, String> historyState;
64 :
65 : /// Maps all route parameters (i.e. parameters of the path
66 : /// mentioned as ":someId")
67 : /// Note that if you have multiple parameters with the same
68 : /// name, only the last one will be visible here
69 : /// However every parameters is passed locally to VRouteElementWidgetData
70 : /// so you should find them there.
71 : /// See [VRouteElementData.pathParameters]
72 : final Map<String, String> pathParameters;
73 :
74 : /// Contains all query parameters (i.e. parameters after
75 : /// the "?" in the url) of the current url
76 : final Map<String, String> queryParameters;
77 :
78 : /// Pushes the new route of the given url on top of the current one
79 : /// A path can be of one of two forms:
80 : /// * stating with '/', in which case we just navigate
81 : /// to the given path
82 : /// * not starting with '/', in which case we append the
83 : /// current path to the given one
84 : ///
85 : /// We can also specify queryParameters, either by directly
86 : /// putting them is the url or by providing a Map using [queryParameters]
87 : ///
88 : /// We can also put a state to the next route, this state will
89 : /// be a router state (this is the only kind of state that we can
90 : /// push) accessible with VRouter.of(context).historyState
91 9 : void push(
92 : String newUrl, {
93 : Map<String, String> queryParameters = const {},
94 : Map<String, String> historyState = const {},
95 : }) =>
96 27 : RootVRouterData.of(_rootVRouterDataContext).push(newUrl,
97 : queryParameters: queryParameters, historyState: historyState);
98 :
99 : /// Updates the url given a [VRouteElement] name
100 : ///
101 : /// We can also specify path parameters to inject into the new path
102 : ///
103 : /// We can also specify queryParameters, either by directly
104 : /// putting them is the url or by providing a Map using [queryParameters]
105 : ///
106 : /// We can also put a state to the next route, this state will
107 : /// be a router state (this is the only kind of state that we can
108 : /// push) accessible with VRouter.of(context).historyState
109 : ///
110 : /// After finding the url and taking charge of the path parameters,
111 : /// it updates the url
112 : ///
113 : /// To specify a name, see [VRouteElement.name]
114 3 : void pushNamed(
115 : String name, {
116 : Map<String, String> pathParameters = const {},
117 : Map<String, String> queryParameters = const {},
118 : Map<String, String> historyState = const {},
119 : }) =>
120 9 : RootVRouterData.of(_rootVRouterDataContext).pushNamed(name,
121 : pathParameters: pathParameters,
122 : queryParameters: queryParameters,
123 : historyState: historyState);
124 :
125 : /// Replace the current one by the new route corresponding to the given url
126 : /// The difference with [push] is that this overwrites the current browser history entry
127 : /// If you are on mobile, this is the same as push
128 : /// Path can be of one of two forms:
129 : /// * stating with '/', in which case we just navigate
130 : /// to the given path
131 : /// * not starting with '/', in which case we append the
132 : /// current path to the given one
133 : ///
134 : /// We can also specify queryParameters, either by directly
135 : /// putting them is the url or by providing a Map using [queryParameters]
136 : ///
137 : /// We can also put a state to the next route, this state will
138 : /// be a router state (this is the only kind of state that we can
139 : /// push) accessible with VRouter.of(context).historyState
140 0 : void pushReplacement(
141 : String newUrl, {
142 : Map<String, String> queryParameters = const {},
143 : Map<String, String> historyState = const {},
144 : }) =>
145 0 : RootVRouterData.of(_rootVRouterDataContext).pushReplacement(newUrl,
146 : queryParameters: queryParameters, historyState: historyState);
147 :
148 : /// Replace the url given a [VRouteElement] name
149 : /// The difference with [pushNamed] is that this overwrites the current browser history entry
150 : ///
151 : /// We can also specify path parameters to inject into the new path
152 : ///
153 : /// We can also specify queryParameters, either by directly
154 : /// putting them is the url or by providing a Map using [queryParameters]
155 : ///
156 : /// We can also put a state to the next route, this state will
157 : /// be a router state (this is the only kind of state that we can
158 : /// push) accessible with VRouter.of(context).historyState
159 : ///
160 : /// After finding the url and taking charge of the path parameters
161 : /// it updates the url
162 : ///
163 : /// To specify a name, see [VPath.name]
164 0 : void pushReplacementNamed(
165 : String name, {
166 : Map<String, String> pathParameters = const {},
167 : Map<String, String> queryParameters = const {},
168 : Map<String, String> historyState = const {},
169 : }) =>
170 0 : RootVRouterData.of(_rootVRouterDataContext).pushReplacementNamed(name,
171 : pathParameters: pathParameters,
172 : queryParameters: queryParameters,
173 : historyState: historyState);
174 :
175 : /// Goes to an url which is not in the app
176 : ///
177 : /// On the web, you can set [openNewTab] to true to open this url
178 : /// in a new tab
179 0 : void pushExternal(String newUrl, {bool openNewTab = false}) =>
180 0 : RootVRouterData.of(_rootVRouterDataContext)
181 0 : .pushExternal(newUrl, openNewTab: openNewTab);
182 :
183 : /// Starts a pop cycle
184 : ///
185 : /// Pop cycle:
186 : /// 1. onPop is called in all [VWidgetGuard]s
187 : /// 2. onPop is called in the nested-most [VRouteElement] of the current route
188 : /// 3. onPop is called in [VRouter]
189 : /// 4. Default behaviour of pop is called: [VRouterState._defaultPop]
190 : ///
191 : /// In any of the above steps, we can use [vRedirector] if you want to redirect or
192 : /// stop the navigation
193 4 : void pop({
194 : Map<String, String> pathParameters = const {},
195 : Map<String, String> queryParameters = const {},
196 : Map<String, String> newHistoryState = const {},
197 : }) =>
198 12 : RootVRouterData.of(_rootVRouterDataContext).popFromElement(
199 8 : _vRouteElementNode.getVRouteElementToPop(),
200 : pathParameters: pathParameters,
201 : queryParameters: queryParameters,
202 : newHistoryState: newHistoryState,
203 : );
204 :
205 : /// Starts a systemPop cycle
206 : ///
207 : /// systemPop cycle:
208 : /// 1. onSystemPop is called in all VWidgetGuards
209 : /// 2. onSystemPop is called in the nested-most VRouteElement of the current route
210 : /// 3. onSystemPop is called in VRouter
211 : /// 4. [pop] is called
212 : ///
213 : /// In any of the above steps, we can use [vRedirector] if you want to redirect or
214 : /// stop the navigation
215 3 : Future<void> systemPop({
216 : Map<String, String> pathParameters = const {},
217 : Map<String, String> queryParameters = const {},
218 : Map<String, String> newHistoryState = const {},
219 : }) =>
220 9 : RootVRouterData.of(_rootVRouterDataContext).systemPopFromElement(
221 6 : _vRouteElementNode.getVRouteElementToPop(),
222 : pathParameters: pathParameters,
223 : queryParameters: queryParameters,
224 : newHistoryState: newHistoryState,
225 : );
226 :
227 : /// This replaces the current history state of [VRouter] with given one
228 0 : void replaceHistoryState(Map<String, String> historyState) =>
229 0 : RootVRouterData.of(_rootVRouterDataContext)
230 0 : .replaceHistoryState(historyState);
231 :
232 0 : static LocalVRouterData of(BuildContext context) {
233 : final localVRouterData =
234 0 : context.dependOnInheritedWidgetOfExactType<LocalVRouterData>();
235 : if (localVRouterData == null) {
236 0 : throw FlutterError(
237 : 'LocalVRouter.of(context) was called with a context which does not contain a LocalVRouterData.\n'
238 : 'The context used to retrieve LocalVRouterData must be that of a widget that '
239 : 'is a descendant of a LocalVRouterData widget.');
240 : }
241 : return localVRouterData;
242 : }
243 : }
|