Line data Source code
1 : part of '../main.dart';
2 :
3 : /// A [VRouteElement] which enable nesting
4 : ///
5 : /// [widgetBuilder] gives you a [Widget] which is what you should use as the child to nest
6 : /// This [Widget] will be the one present in the [VRouteElement] in [nestedRoutes] corresponding
7 : /// to the current route
8 : ///
9 : /// {@tool snippet}
10 : ///
11 : /// If you want to nest ProfileWidget in MyScaffold at the path '/home/profile',
12 : /// here is what you can do:
13 : ///
14 : /// ```dart
15 : /// VNester(
16 : /// path: '/home',
17 : /// widgetBuilder: (child) => MyScaffold(child: child),
18 : /// nestedRoutes: [
19 : /// VWidget(
20 : /// path: 'profile',
21 : /// widget: ProfileWidget(),
22 : /// ),
23 : /// ],
24 : /// )
25 : /// ```
26 : /// {@end-tool}
27 : ///
28 : ///
29 : /// {@tool snippet}
30 : ///
31 : /// Note that you can also use stackedRoutes if you want to nest AND stack by using nestedRoutes
32 : /// AND stackedRoutes:
33 : ///
34 : /// ```dart
35 : /// VNester(
36 : /// path: '/home',
37 : /// widgetBuilder: (child) => MyScaffold(child: child),
38 : /// nestedRoutes: [
39 : /// VWidget(
40 : /// path: 'profile',
41 : /// alias: [':_(settings)'] // This is used because we want to display ProfileWidget while SettingsWidgets is on top of MyScaffold
42 : /// widget: ProfileWidget(),
43 : /// ),
44 : /// ],
45 : /// stackedRoutes: [
46 : /// VWidget(
47 : /// path: 'settings',
48 : /// widget: SettingsWidget(),
49 : /// ),
50 : /// ],
51 : /// )
52 : /// ```
53 : ///
54 : /// Also see:
55 : /// * [VNesterBase] for a [VRouteElement] similar to [VNester] but which does NOT take path information
56 : /// * [VNesterPage] for a [VRouteElement] similar to [VNester] but with which you can create you own page
57 : /// {@end-tool}
58 : class VNester extends VRouteElementBuilder {
59 : /// A list of [VRouteElement] which widget will be accessible in [widgetBuilder]
60 : final List<VRouteElement> nestedRoutes;
61 :
62 : /// A list of routes which:
63 : /// - path NOT starting with '/' will be relative to [path]
64 : /// - widget or page will be stacked on top of [_rootVRouter]
65 : final List<VRouteElement> stackedRoutes;
66 :
67 : /// The path (relative or absolute) or this [VRouteElement]
68 : ///
69 : /// If the path of a subroute is exactly matched, this will be used in
70 : /// the route but might be covered by another [VRouteElement._rootVRouter]
71 : /// The value of the path ca have three form:
72 : /// * starting with '/': The path will be treated as a route path,
73 : /// this is useful to take full advantage of nested routes while
74 : /// conserving the freedom of path naming
75 : /// * not starting with '/': The path corresponding to this route
76 : /// will be the path of the parent route + this path. If this is used
77 : /// directly in the [VRouter] routes, a '/' will be added anyway
78 : /// * be null: In this case this path will match the parent path
79 : ///
80 : /// Note we use the package [path_to_regexp](https://pub.dev/packages/path_to_regexp)
81 : /// so you can use naming such as /user/:id to get the id (see [VRouteElementData.pathParameters]
82 : /// You can also use more advance technique using regexp directly in your path, for example
83 : /// '.*' will match any route, '/user/:id(\d+)' will match any route starting with user
84 : /// and followed by a digit. Here is a recap:
85 : /// | pattern | matched path | [VRouter.pathParameters]
86 : /// | /user/:username | /user/evan | { username: 'evan' }
87 : /// | /user/:id(\d+) | /user/123 | { id: '123' }
88 : /// | .* | every path | -
89 : final String? path;
90 :
91 : /// A name for the route which will allow you to easily navigate to it
92 : /// using [VRouter.of(context).pushNamed]
93 : ///
94 : /// Note that [name] should be unique w.r.t every [VRouteElement]
95 : final String? name;
96 :
97 : /// Alternative paths that will be matched to this route
98 : ///
99 : /// Note that path is match first, then every aliases in order
100 : final List<String> aliases;
101 :
102 : /// A boolean to indicate whether this can be a valid [VRouteElement] of the [VRoute] if no
103 : /// [VRouteElement] in its [stackedRoute] is matched
104 : ///
105 : /// This is mainly useful for [VRouteElement]s which are NOT [VRouteElementWithPage]
106 : final bool mustMatchStackedRoute;
107 :
108 : /// A function which creates the [VRouteElement._rootVRouter] associated to this [VRouteElement]
109 : ///
110 : /// [child] will be the [VRouteElement._rootVRouter] of the matched [VRouteElement] in
111 : /// [nestedRoutes]
112 : final Widget Function(Widget child) widgetBuilder;
113 :
114 : /// A LocalKey that will be given to the page which contains the given [_rootVRouter]
115 : ///
116 : /// This key mostly controls the page animation. If a page remains the same but the key is changes,
117 : /// the page gets animated
118 : /// The key is by default the value of the current [path] (or [aliases]) with
119 : /// the path parameters replaced
120 : ///
121 : /// Do provide a constant [key] if you don't want this page to animate even if [path] or
122 : /// [aliases] path parameters change
123 : final LocalKey? key;
124 :
125 : /// The duration of [VWidgetBase.buildTransition]
126 : final Duration? transitionDuration;
127 :
128 : /// The reverse duration of [VWidgetBase.buildTransition]
129 : final Duration? reverseTransitionDuration;
130 :
131 : /// Create a custom transition effect when coming to and
132 : /// going to this route
133 : /// This has the priority over [VRouter.buildTransition]
134 : ///
135 : /// Also see:
136 : /// * [VRouter.buildTransition] for default transitions for all routes
137 : final Widget Function(Animation<double> animation,
138 : Animation<double> secondaryAnimation, Widget child)? buildTransition;
139 :
140 2 : VNester({
141 : required this.path,
142 : required this.widgetBuilder,
143 : required this.nestedRoutes,
144 : this.transitionDuration,
145 : this.reverseTransitionDuration,
146 : this.buildTransition,
147 : this.key,
148 : this.name,
149 : this.stackedRoutes = const [],
150 : this.aliases = const [],
151 : this.mustMatchStackedRoute = false,
152 : });
153 :
154 2 : @override
155 2 : List<VRouteElement> buildRoutes() => [
156 2 : VPath(
157 2 : path: path,
158 2 : aliases: aliases,
159 2 : mustMatchStackedRoute: mustMatchStackedRoute,
160 2 : stackedRoutes: [
161 2 : VNesterBase(
162 2 : key: key,
163 2 : name: name,
164 2 : nestedRoutes: nestedRoutes,
165 2 : stackedRoutes: stackedRoutes,
166 2 : widgetBuilder: widgetBuilder,
167 2 : buildTransition: buildTransition,
168 2 : transitionDuration: transitionDuration,
169 2 : reverseTransitionDuration: reverseTransitionDuration,
170 : ),
171 : ],
172 : ),
173 : ];
174 : }
|