Line data Source code
1 : part of '../main.dart';
2 :
3 : /// See [VRouter.mode]
4 14 : enum VRouterModes { hash, history }
5 :
6 : /// This widget handles most of the routing work
7 : /// It gives you access to the [routes] attribute where you can start
8 : /// building your routes using [VRouteElement]s
9 : ///
10 : /// Note that this widget also acts as a [MaterialApp] so you can pass
11 : /// it every argument that you would expect in [MaterialApp]
12 : class VRouter extends StatefulWidget
13 : with VRouteElement, VRouteElementSingleSubRoute {
14 : /// This list holds every possible routes of your app
15 : final List<VRouteElement> routes;
16 :
17 : /// If implemented, this becomes the default transition for every route transition
18 : /// except those who implement there own buildTransition
19 : /// Also see:
20 : /// * [VRouteElement.buildTransition] for custom local transitions
21 : ///
22 : /// Note that if this is not implemented, every route which does not implement
23 : /// its own buildTransition will be given a default transition: this of a
24 : /// [MaterialPage] or a [CupertinoPage] depending on the platform
25 : final Widget Function(Animation<double> animation,
26 : Animation<double> secondaryAnimation, Widget child)? buildTransition;
27 :
28 : /// The duration of [VRouter.buildTransition]
29 : final Duration? transitionDuration;
30 :
31 : /// The reverse duration of [VRouter.buildTransition]
32 : final Duration? reverseTransitionDuration;
33 :
34 : /// Two router mode are possible:
35 : /// - "hash": This is the default, the url will be serverAddress/#/localUrl
36 : /// - "history": This will display the url in the way we are used to, without
37 : /// the #. However note that you will need to configure your server to make this work.
38 : /// Follow the instructions here: [https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations]
39 : final VRouterModes mode;
40 :
41 12 : @override
42 : Future<void> beforeEnter(VRedirector vRedirector) =>
43 24 : _beforeEnter(vRedirector);
44 : final Future<void> Function(VRedirector vRedirector) _beforeEnter;
45 :
46 11 : @override
47 : Future<void> beforeLeave(
48 : VRedirector vRedirector,
49 : void Function(Map<String, String> historyState) saveHistoryState,
50 : ) =>
51 22 : _beforeLeave(vRedirector, saveHistoryState);
52 : final Future<void> Function(
53 : VRedirector vRedirector,
54 : void Function(Map<String, String> historyState) saveHistoryState,
55 : ) _beforeLeave;
56 :
57 12 : @override
58 : void afterEnter(BuildContext context, String? from, String to) =>
59 24 : _afterEnter(context, from, to);
60 : final void Function(BuildContext context, String? from, String to)
61 : _afterEnter;
62 :
63 7 : @override
64 14 : Future<void> onPop(VRedirector vRedirector) => _onPop(vRedirector);
65 : final Future<void> Function(VRedirector vRedirector) _onPop;
66 :
67 6 : @override
68 : Future<void> onSystemPop(VRedirector vRedirector) =>
69 12 : _onSystemPop(vRedirector);
70 : final Future<void> Function(VRedirector vRedirector) _onSystemPop;
71 :
72 : /// This allows you to change the initial url
73 : ///
74 : /// The default is '/'
75 : final String initialUrl;
76 :
77 14 : VRouter({
78 : Key? key,
79 : required this.routes,
80 : Future<void> Function(VRedirector vRedirector) beforeEnter =
81 : VGuard._voidBeforeEnter,
82 : Future<void> Function(
83 : VRedirector vRedirector,
84 : void Function(Map<String, String> historyState) saveHistoryState,
85 : )
86 : beforeLeave = VGuard._voidBeforeLeave,
87 : void Function(BuildContext context, String? from, String to) afterEnter =
88 : VGuard._voidAfterEnter,
89 : Future<void> Function(VRedirector vRedirector) onPop =
90 : VPopHandler._voidOnPop,
91 : Future<void> Function(VRedirector vRedirector) onSystemPop =
92 : VPopHandler._voidOnSystemPop,
93 : this.buildTransition,
94 : this.transitionDuration,
95 : this.reverseTransitionDuration,
96 : this.mode = VRouterModes.hash,
97 : this.initialUrl = '/',
98 : this.navigatorObservers = const [],
99 : this.builder,
100 : // Bellow are the MaterialApp parameters
101 : this.title = '',
102 : this.onGenerateTitle,
103 : this.color,
104 : this.theme,
105 : this.darkTheme,
106 : this.highContrastTheme,
107 : this.highContrastDarkTheme,
108 : this.themeMode = ThemeMode.system,
109 : this.locale,
110 : this.localizationsDelegates,
111 : this.localeListResolutionCallback,
112 : this.localeResolutionCallback,
113 : this.supportedLocales = const <Locale>[Locale('en', 'US')],
114 : this.debugShowMaterialGrid = false,
115 : this.showPerformanceOverlay = false,
116 : this.checkerboardRasterCacheImages = false,
117 : this.checkerboardOffscreenLayers = false,
118 : this.showSemanticsDebugger = false,
119 : this.debugShowCheckedModeBanner = true,
120 : this.shortcuts,
121 : this.actions,
122 : }) : _beforeEnter = beforeEnter,
123 : _beforeLeave = beforeLeave,
124 : _afterEnter = afterEnter,
125 : _onPop = onPop,
126 : _onSystemPop = onSystemPop,
127 14 : super(key: key);
128 :
129 12 : @override
130 12 : VRouterState createState() => VRouterState();
131 :
132 : /// {@macro flutter.widgets.widgetsApp.navigatorObservers}
133 : final List<NavigatorObserver> navigatorObservers;
134 :
135 : /// {@macro flutter.widgets.widgetsApp.builder}
136 : ///
137 : /// Material specific features such as [showDialog] and [showMenu], and widgets
138 : /// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly
139 : /// function.
140 : final TransitionBuilder? builder;
141 :
142 : /// {@macro flutter.widgets.widgetsApp.title}
143 : ///
144 : /// This value is passed unmodified to [WidgetsApp.title].
145 : final String title;
146 :
147 : /// {@macro flutter.widgets.widgetsApp.onGenerateTitle}
148 : ///
149 : /// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
150 : final GenerateAppTitle? onGenerateTitle;
151 :
152 : /// Default visual properties, like colors fonts and shapes, for this app's
153 : /// material widgets.
154 : ///
155 : /// A second [darkTheme] [ThemeData] value, which is used to provide a dark
156 : /// version of the user interface can also be specified. [themeMode] will
157 : /// control which theme will be used if a [darkTheme] is provided.
158 : ///
159 : /// The default value of this property is the value of [ThemeData.light()].
160 : ///
161 : /// See also:
162 : ///
163 : /// * [themeMode], which controls which theme to use.
164 : /// * [MediaQueryData.platformBrightness], which indicates the platform's
165 : /// desired brightness and is used to automatically toggle between [theme]
166 : /// and [darkTheme] in [MaterialApp].
167 : /// * [ThemeData.brightness], which indicates the [Brightness] of a theme's
168 : /// colors.
169 : final ThemeData? theme;
170 :
171 : /// The [ThemeData] to use when a 'dark mode' is requested by the system.
172 : ///
173 : /// Some host platforms allow the users to select a system-wide 'dark mode',
174 : /// or the application may want to offer the user the ability to choose a
175 : /// dark theme just for this application. This is theme that will be used for
176 : /// such cases. [themeMode] will control which theme will be used.
177 : ///
178 : /// This theme should have a [ThemeData.brightness] set to [Brightness.dark].
179 : ///
180 : /// Uses [theme] instead when null. Defaults to the value of
181 : /// [ThemeData.light()] when both [darkTheme] and [theme] are null.
182 : ///
183 : /// See also:
184 : ///
185 : /// * [themeMode], which controls which theme to use.
186 : /// * [MediaQueryData.platformBrightness], which indicates the platform's
187 : /// desired brightness and is used to automatically toggle between [theme]
188 : /// and [darkTheme] in [MaterialApp].
189 : /// * [ThemeData.brightness], which is typically set to the value of
190 : /// [MediaQueryData.platformBrightness].
191 : final ThemeData? darkTheme;
192 :
193 : /// The [ThemeData] to use when 'high contrast' is requested by the system.
194 : ///
195 : /// Some host platforms (for example, iOS) allow the users to increase
196 : /// contrast through an accessibility setting.
197 : ///
198 : /// Uses [theme] instead when null.
199 : ///
200 : /// See also:
201 : ///
202 : /// * [MediaQueryData.highContrast], which indicates the platform's
203 : /// desire to increase contrast.
204 : final ThemeData? highContrastTheme;
205 :
206 : /// The [ThemeData] to use when a 'dark mode' and 'high contrast' is requested
207 : /// by the system.
208 : ///
209 : /// Some host platforms (for example, iOS) allow the users to increase
210 : /// contrast through an accessibility setting.
211 : ///
212 : /// This theme should have a [ThemeData.brightness] set to [Brightness.dark].
213 : ///
214 : /// Uses [darkTheme] instead when null.
215 : ///
216 : /// See also:
217 : ///
218 : /// * [MediaQueryData.highContrast], which indicates the platform's
219 : /// desire to increase contrast.
220 : final ThemeData? highContrastDarkTheme;
221 :
222 : /// Determines which theme will be used by the application if both [theme]
223 : /// and [darkTheme] are provided.
224 : ///
225 : /// If set to [ThemeMode.system], the choice of which theme to use will
226 : /// be based on the user's system preferences. If the [MediaQuery.platformBrightnessOf]
227 : /// is [Brightness.light], [theme] will be used. If it is [Brightness.dark],
228 : /// [darkTheme] will be used (unless it is null, in which case [theme]
229 : /// will be used.
230 : ///
231 : /// If set to [ThemeMode.light] the [theme] will always be used,
232 : /// regardless of the user's system preference.
233 : ///
234 : /// If set to [ThemeMode.dark] the [darkTheme] will be used
235 : /// regardless of the user's system preference. If [darkTheme] is null
236 : /// then it will fallback to using [theme].
237 : ///
238 : /// The default value is [ThemeMode.system].
239 : ///
240 : /// See also:
241 : ///
242 : /// * [theme], which is used when a light mode is selected.
243 : /// * [darkTheme], which is used when a dark mode is selected.
244 : /// * [ThemeData.brightness], which indicates to various parts of the
245 : /// system what kind of theme is being used.
246 : final ThemeMode? themeMode;
247 :
248 : /// {@macro flutter.widgets.widgetsApp.color}
249 : final Color? color;
250 :
251 : /// {@macro flutter.widgets.widgetsApp.locale}
252 : final Locale? locale;
253 :
254 : /// {@macro flutter.widgets.widgetsApp.localizationsDelegates}
255 : ///
256 : /// Internationalized apps that require translations for one of the locales
257 : /// listed in [GlobalMaterialLocalizations] should specify this parameter
258 : /// and list the [supportedLocales] that the application can handle.
259 : ///
260 : /// ```dart
261 : /// import 'package:flutter_localizations/flutter_localizations.dart';
262 : /// MaterialApp(
263 : /// localizationsDelegates: [
264 : /// // ... app-specific localization delegate[s] here
265 : /// GlobalMaterialLocalizations.delegate,
266 : /// GlobalWidgetsLocalizations.delegate,
267 : /// ],
268 : /// supportedLocales: [
269 : /// const Locale('en', 'US'), // English
270 : /// const Locale('he', 'IL'), // Hebrew
271 : /// // ... other locales the app supports
272 : /// ],
273 : /// // ...
274 : /// )
275 : /// ```
276 : ///
277 : /// ## Adding localizations for a new locale
278 : ///
279 : /// The information that follows applies to the unusual case of an app
280 : /// adding translations for a language not already supported by
281 : /// [GlobalMaterialLocalizations].
282 : ///
283 : /// Delegates that produce [WidgetsLocalizations] and [MaterialLocalizations]
284 : /// are included automatically. Apps can provide their own versions of these
285 : /// localizations by creating implementations of
286 : /// [LocalizationsDelegate<WidgetsLocalizations>] or
287 : /// [LocalizationsDelegate<MaterialLocalizations>] whose load methods return
288 : /// custom versions of [WidgetsLocalizations] or [MaterialLocalizations].
289 : ///
290 : /// For example: to add support to [MaterialLocalizations] for a
291 : /// locale it doesn't already support, say `const Locale('foo', 'BR')`,
292 : /// one could just extend [DefaultMaterialLocalizations]:
293 : ///
294 : /// ```dart
295 : /// class FooLocalizations extends DefaultMaterialLocalizations {
296 : /// FooLocalizations(Locale locale) : super(locale);
297 : /// @override
298 : /// String get okButtonLabel {
299 : /// if (locale == const Locale('foo', 'BR'))
300 : /// return 'foo';
301 : /// return super.okButtonLabel;
302 : /// }
303 : /// }
304 : ///
305 : /// ```
306 : ///
307 : /// A `FooLocalizationsDelegate` is essentially just a method that constructs
308 : /// a `FooLocalizations` object. We return a [SynchronousFuture] here because
309 : /// no asynchronous work takes place upon "loading" the localizations object.
310 : ///
311 : /// ```dart
312 : /// class FooLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
313 : /// const FooLocalizationsDelegate();
314 : /// @override
315 : /// Future<FooLocalizations> load(Locale locale) {
316 : /// return SynchronousFuture(FooLocalizations(locale));
317 : /// }
318 : /// @override
319 : /// bool shouldReload(FooLocalizationsDelegate old) => false;
320 : /// }
321 : /// ```
322 : ///
323 : /// Constructing a [MaterialApp] with a `FooLocalizationsDelegate` overrides
324 : /// the automatically included delegate for [MaterialLocalizations] because
325 : /// only the first delegate of each [LocalizationsDelegate.type] is used and
326 : /// the automatically included delegates are added to the end of the app's
327 : /// [localizationsDelegates] list.
328 : ///
329 : /// ```dart
330 : /// MaterialApp(
331 : /// localizationsDelegates: [
332 : /// const FooLocalizationsDelegate(),
333 : /// ],
334 : /// // ...
335 : /// )
336 : /// ```
337 : /// See also:
338 : ///
339 : /// * [supportedLocales], which must be specified along with
340 : /// [localizationsDelegates].
341 : /// * [GlobalMaterialLocalizations], a [localizationsDelegates] value
342 : /// which provides material localizations for many languages.
343 : /// * The Flutter Internationalization Tutorial,
344 : /// <https://flutter.dev/tutorials/internationalization/>.
345 : final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;
346 :
347 : /// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback}
348 : ///
349 : /// This callback is passed along to the [WidgetsApp] built by this widget.
350 : final LocaleListResolutionCallback? localeListResolutionCallback;
351 :
352 : /// {@macro flutter.widgets.LocaleResolutionCallback}
353 : ///
354 : /// This callback is passed along to the [WidgetsApp] built by this widget.
355 : final LocaleResolutionCallback? localeResolutionCallback;
356 :
357 : /// {@macro flutter.widgets.widgetsApp.supportedLocales}
358 : ///
359 : /// It is passed along unmodified to the [WidgetsApp] built by this widget.
360 : ///
361 : /// See also:
362 : ///
363 : /// * [localizationsDelegates], which must be specified for localized
364 : /// applications.
365 : /// * [GlobalMaterialLocalizations], a [localizationsDelegates] value
366 : /// which provides material localizations for many languages.
367 : /// * The Flutter Internationalization Tutorial,
368 : /// <https://flutter.dev/tutorials/internationalization/>.
369 : final Iterable<Locale> supportedLocales;
370 :
371 : /// Turns on a performance overlay.
372 : ///
373 : /// See also:
374 : ///
375 : /// * <https://flutter.dev/debugging/#performanceoverlay>
376 : final bool showPerformanceOverlay;
377 :
378 : /// Turns on checkerboarding of raster cache images.
379 : final bool checkerboardRasterCacheImages;
380 :
381 : /// Turns on checkerboarding of layers rendered to offscreen bitmaps.
382 : final bool checkerboardOffscreenLayers;
383 :
384 : /// Turns on an overlay that shows the accessibility information
385 : /// reported by the framework.
386 : final bool showSemanticsDebugger;
387 :
388 : /// {@macro flutter.widgets.widgetsApp.debugShowCheckedModeBanner}
389 : final bool debugShowCheckedModeBanner;
390 :
391 : /// {@macro flutter.widgets.widgetsApp.shortcuts}
392 : /// {@tool snippet}
393 : /// This example shows how to add a single shortcut for
394 : /// [LogicalKeyboardKey.select] to the default shortcuts without needing to
395 : /// add your own [Shortcuts] widget.
396 : ///
397 : /// Alternatively, you could insert a [Shortcuts] widget with just the mapping
398 : /// you want to add between the [WidgetsApp] and its child and get the same
399 : /// effect.
400 : ///
401 : /// ```dart
402 : /// Widget build(BuildContext context) {
403 : /// return WidgetsApp(
404 : /// shortcuts: <LogicalKeySet, Intent>{
405 : /// ... WidgetsApp.defaultShortcuts,
406 : /// LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
407 : /// },
408 : /// color: const Color(0xFFFF0000),
409 : /// builder: (BuildContext context, Widget child) {
410 : /// return const Placeholder();
411 : /// },
412 : /// );
413 : /// }
414 : /// ```
415 : /// {@end-tool}
416 : /// {@macro flutter.widgets.widgetsApp.shortcuts.seeAlso}
417 : final Map<LogicalKeySet, Intent>? shortcuts;
418 :
419 : /// {@macro flutter.widgets.widgetsApp.actions}
420 : /// {@tool snippet}
421 : /// This example shows how to add a single action handling an
422 : /// [ActivateAction] to the default actions without needing to
423 : /// add your own [Actions] widget.
424 : ///
425 : /// Alternatively, you could insert a [Actions] widget with just the mapping
426 : /// you want to add between the [WidgetsApp] and its child and get the same
427 : /// effect.
428 : ///
429 : /// ```dart
430 : /// Widget build(BuildContext context) {
431 : /// return WidgetsApp(
432 : /// actions: <Type, Action<Intent>>{
433 : /// ... WidgetsApp.defaultActions,
434 : /// ActivateAction: CallbackAction(
435 : /// onInvoke: (Intent intent) {
436 : /// // Do something here...
437 : /// return null;
438 : /// },
439 : /// ),
440 : /// },
441 : /// color: const Color(0xFFFF0000),
442 : /// builder: (BuildContext context, Widget child) {
443 : /// return const Placeholder();
444 : /// },
445 : /// );
446 : /// }
447 : /// ```
448 : /// {@end-tool}
449 : /// {@macro flutter.widgets.widgetsApp.actions.seeAlso}
450 : final Map<Type, Action<Intent>>? actions;
451 :
452 : /// Turns on a [GridPaper] overlay that paints a baseline grid
453 : /// Material apps.
454 : ///
455 : /// Only available in checked mode.
456 : ///
457 : /// See also:
458 : ///
459 : /// * <https://material.io/design/layout/spacing-methods.html>
460 : final bool debugShowMaterialGrid;
461 :
462 9 : static VRouterData of(BuildContext context) {
463 : VRouterData? vRouterData;
464 :
465 : // First try to get a local MaterialVRouterData
466 : vRouterData =
467 9 : context.dependOnInheritedWidgetOfExactType<LocalVRouterData>();
468 : if (vRouterData != null) {
469 : return vRouterData;
470 : }
471 :
472 : // Else try to get the root MaterialVRouterData
473 0 : vRouterData = context.dependOnInheritedWidgetOfExactType<RootVRouterData>();
474 : if (vRouterData != null) {
475 : return vRouterData;
476 : }
477 :
478 : if (vRouterData == null) {
479 0 : throw FlutterError(
480 : 'MaterialVRouter.of(context) was called with a context which does not contain a MaterialVRouter.\n'
481 : 'The context used to retrieve MaterialVRouter must be that of a widget that '
482 : 'is a descendant of a MaterialVRouter widget.');
483 : }
484 : return vRouterData;
485 : }
486 :
487 2 : @override
488 2 : List<VRouteElement> buildRoutes() => routes;
489 :
490 0 : @override
491 : void afterUpdate(BuildContext context, String? from, String to) {}
492 :
493 : @override
494 0 : Future<void> beforeUpdate(VRedirector vRedirector) async {}
495 : }
496 :
497 : class VRouterState extends State<VRouter> {
498 24 : late final vRouterDelegate = VRouterDelegate(
499 24 : routes: widget.routes,
500 24 : builder: widget.builder,
501 24 : navigatorObservers: widget.navigatorObservers,
502 24 : beforeEnter: widget.beforeEnter,
503 24 : beforeLeave: widget.beforeLeave,
504 24 : afterEnter: widget.afterEnter,
505 24 : onPop: widget.onPop,
506 24 : onSystemPop: widget.onSystemPop,
507 24 : buildTransition: widget.buildTransition,
508 24 : transitionDuration: widget.transitionDuration,
509 24 : reverseTransitionDuration: widget.reverseTransitionDuration,
510 24 : mode: widget.mode,
511 24 : initialUrl: widget.initialUrl,
512 : );
513 :
514 12 : @override
515 : Widget build(BuildContext context) {
516 12 : return MaterialApp.router(
517 12 : backButtonDispatcher: VBackButtonDispatcher(),
518 12 : routeInformationParser: VRouteInformationParser(),
519 12 : routerDelegate: vRouterDelegate,
520 24 : title: widget.title,
521 24 : onGenerateTitle: widget.onGenerateTitle,
522 24 : color: widget.color,
523 24 : theme: widget.theme,
524 24 : darkTheme: widget.darkTheme,
525 24 : highContrastTheme: widget.highContrastTheme,
526 24 : highContrastDarkTheme: widget.highContrastDarkTheme,
527 24 : themeMode: widget.themeMode,
528 24 : locale: widget.locale,
529 24 : localizationsDelegates: widget.localizationsDelegates,
530 24 : localeListResolutionCallback: widget.localeListResolutionCallback,
531 24 : localeResolutionCallback: widget.localeResolutionCallback,
532 24 : supportedLocales: widget.supportedLocales,
533 24 : debugShowMaterialGrid: widget.debugShowMaterialGrid,
534 24 : showPerformanceOverlay: widget.showPerformanceOverlay,
535 24 : checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
536 24 : checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
537 24 : showSemanticsDebugger: widget.showSemanticsDebugger,
538 24 : debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
539 24 : shortcuts: widget.shortcuts,
540 24 : actions: widget.actions,
541 : );
542 : }
543 :
544 : /// Url currently synced with the state
545 : /// This url can differ from the once of the browser if
546 : /// the state has been yet been updated
547 0 : String? get url => vRouterDelegate.url;
548 :
549 : /// Previous url that was synced with the state
550 0 : String? get previousUrl => vRouterDelegate.previousUrl;
551 :
552 : /// This state is saved in the browser history. This means that if the user presses
553 : /// the back or forward button on the navigator, this historyState will be the same
554 : /// as the last one you saved.
555 : ///
556 : /// It can be changed by using [context.vRouter.replaceHistoryState(newState)]
557 0 : Map<String, String> get historyState => vRouterDelegate.historyState;
558 :
559 : /// Maps all route parameters (i.e. parameters of the path
560 : /// mentioned as ":someId")
561 0 : Map<String, String> get pathParameters => vRouterDelegate.pathParameters;
562 :
563 : /// Contains all query parameters (i.e. parameters after
564 : /// the "?" in the url) of the current url
565 3 : Map<String, String> get queryParameters => vRouterDelegate.queryParameters;
566 :
567 : /// Starts a pop cycle
568 : ///
569 : /// Pop cycle:
570 : /// 1. onPop is called in all [VNavigationGuard]s
571 : /// 2. onPop is called in all [VRouteElement]s of the current route
572 : /// 3. onPop is called in [VRouter]
573 : ///
574 : /// In any of the above steps, we can use [vRedirector] if you want to redirect or
575 : /// stop the navigation
576 3 : Future<void> pop({
577 : Map<String, String> pathParameters = const {},
578 : Map<String, String> queryParameters = const {},
579 : Map<String, String> newHistoryState = const {},
580 : }) async =>
581 6 : vRouterDelegate.pop(
582 : pathParameters: pathParameters,
583 : queryParameters: queryParameters,
584 : newHistoryState: newHistoryState,
585 : );
586 :
587 : /// Starts a systemPop cycle
588 : ///
589 : /// systemPop cycle:
590 : /// 1. onSystemPop (or onPop if not implemented) is called in all VNavigationGuards
591 : /// 2. onSystemPop (or onPop if not implemented) is called in the nested-most VRouteElement of the current route
592 : /// 3. onSystemPop (or onPop if not implemented) is called in MaterialVRouter
593 : ///
594 : /// In any of the above steps, we can use a [VRedirector] if you want to redirect or
595 : /// stop the navigation
596 2 : Future<void> systemPop({
597 : Map<String, String> pathParameters = const {},
598 : Map<String, String> queryParameters = const {},
599 : Map<String, String> newHistoryState = const {},
600 : }) async =>
601 4 : vRouterDelegate.systemPop(
602 : pathParameters: pathParameters,
603 : queryParameters: queryParameters,
604 : newHistoryState: newHistoryState,
605 : );
606 :
607 : /// Pushes the new route of the given url on top of the current one
608 : /// A path can be of one of two forms:
609 : /// * stating with '/', in which case we just navigate
610 : /// to the given path
611 : /// * not starting with '/', in which case we append the
612 : /// current path to the given one
613 : ///
614 : /// We can also specify queryParameters, either by directly
615 : /// putting them is the url or by providing a Map using [queryParameters]
616 : ///
617 : /// We can also put a state to the next route, this state will
618 : /// be a router state (this is the only kind of state that we can
619 : /// push) accessible with MaterialVRouter.of(context).historyState
620 4 : void push(
621 : String newUrl, {
622 : Map<String, String> queryParameters = const {},
623 : Map<String, String> historyState = const {},
624 : }) =>
625 8 : vRouterDelegate.push(
626 : newUrl,
627 : queryParameters: queryParameters,
628 : historyState: historyState,
629 : );
630 :
631 : /// Updates the url given a [VRouteElement] name
632 : ///
633 : /// We can also specify path parameters to inject into the new path
634 : ///
635 : /// We can also specify queryParameters, either by directly
636 : /// putting them is the url or by providing a Map using [queryParameters]
637 : ///
638 : /// We can also put a state to the next route, this state will
639 : /// be a router state (this is the only kind of state that we can
640 : /// push) accessible with MaterialVRouter.of(context).historyState
641 : ///
642 : /// After finding the url and taking charge of the path parameters,
643 : /// it updates the url
644 : ///
645 : /// To specify a name, see [VRouteElement.name]
646 2 : void pushNamed(
647 : String name, {
648 : Map<String, String> pathParameters = const {},
649 : Map<String, String> queryParameters = const {},
650 : Map<String, String> historyState = const {},
651 : }) =>
652 4 : vRouterDelegate.pushNamed(
653 : name,
654 : pathParameters: pathParameters,
655 : queryParameters: queryParameters,
656 : historyState: historyState,
657 : );
658 :
659 : /// Replace the current one by the new route corresponding to the given url
660 : /// The difference with [push] is that this overwrites the current browser history entry
661 : /// If you are on mobile, this is the same as push
662 : /// Path can be of one of two forms:
663 : /// * stating with '/', in which case we just navigate
664 : /// to the given path
665 : /// * not starting with '/', in which case we append the
666 : /// current path to the given one
667 : ///
668 : /// We can also specify queryParameters, either by directly
669 : /// putting them is the url or by providing a Map using [queryParameters]
670 : ///
671 : /// We can also put a state to the next route, this state will
672 : /// be a router state (this is the only kind of state that we can
673 : /// push) accessible with MaterialVRouter.of(context).historyState
674 0 : void pushReplacement(
675 : String newUrl, {
676 : Map<String, String> queryParameters = const {},
677 : Map<String, String> historyState = const {},
678 : }) =>
679 0 : vRouterDelegate.pushReplacement(
680 : newUrl,
681 : queryParameters: queryParameters,
682 : historyState: historyState,
683 : );
684 :
685 : /// Replace the url given a [VRouteElement] name
686 : /// The difference with [pushNamed] is that this overwrites the current browser history entry
687 : ///
688 : /// We can also specify path parameters to inject into the new path
689 : ///
690 : /// We can also specify queryParameters, either by directly
691 : /// putting them is the url or by providing a Map using [queryParameters]
692 : ///
693 : /// We can also put a state to the next route, this state will
694 : /// be a router state (this is the only kind of state that we can
695 : /// push) accessible with MaterialVRouter.of(context).historyState
696 : ///
697 : /// After finding the url and taking charge of the path parameters
698 : /// it updates the url
699 : ///
700 : /// To specify a name, see [VPath.name]
701 0 : void pushReplacementNamed(
702 : String name, {
703 : Map<String, String> pathParameters = const {},
704 : Map<String, String> queryParameters = const {},
705 : Map<String, String> historyState = const {},
706 : }) =>
707 0 : vRouterDelegate.pushReplacementNamed(
708 : name,
709 : pathParameters: pathParameters,
710 : queryParameters: queryParameters,
711 : historyState: historyState,
712 : );
713 :
714 : /// Goes to an url which is not in the app
715 : ///
716 : /// On the web, you can set [openNewTab] to true to open this url
717 : /// in a new tab
718 0 : void pushExternal(String newUrl, {bool openNewTab = false}) =>
719 0 : vRouterDelegate.pushExternal(
720 : newUrl,
721 : openNewTab: openNewTab,
722 : );
723 : }
|