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 [widget]
65 : final List<VRouteElement> stackedRoutes;
66 :
67 :
68 : /// The path (relative or absolute) or this [VRouteElement]
69 : ///
70 : /// If the path of a subroute is exactly matched, this will be used in
71 : /// the route but might be covered by another [VRouteElement.widget]
72 : /// The value of the path ca have three form:
73 : /// * starting with '/': The path will be treated as a route path,
74 : /// this is useful to take full advantage of nested routes while
75 : /// conserving the freedom of path naming
76 : /// * not starting with '/': The path corresponding to this route
77 : /// will be the path of the parent route + this path. If this is used
78 : /// directly in the [VRouter] routes, a '/' will be added anyway
79 : /// * be null: In this case this path will match the parent path
80 : ///
81 : /// Note we use the package [path_to_regexp](https://pub.dev/packages/path_to_regexp)
82 : /// so you can use naming such as /user/:id to get the id (see [VRouteElementData.pathParameters]
83 : /// You can also use more advance technique using regexp directly in your path, for example
84 : /// '.*' will match any route, '/user/:id(\d+)' will match any route starting with user
85 : /// and followed by a digit. Here is a recap:
86 : /// | pattern | matched path | [VRouter.pathParameters]
87 : /// | /user/:username | /user/evan | { username: 'evan' }
88 : /// | /user/:id(\d+) | /user/123 | { id: '123' }
89 : /// | .* | every path | -
90 : final String? path;
91 :
92 : /// A name for the route which will allow you to easily navigate to it
93 : /// using [VRouter.of(context).pushNamed]
94 : ///
95 : /// Note that [name] should be unique w.r.t every [VRouteElement]
96 : final String? name;
97 :
98 : /// Alternative paths that will be matched to this route
99 : ///
100 : /// Note that path is match first, then every aliases in order
101 : final List<String> aliases;
102 :
103 : /// A boolean to indicate whether this can be a valid [VRouteElement] of the [VRoute] if no
104 : /// [VRouteElement] in its [stackedRoute] is matched
105 : ///
106 : /// This is mainly useful for [VRouteElement]s which are NOT [VRouteElementWithPage]
107 : final bool mustMatchStackedRoute;
108 :
109 : /// A function which creates the [VRouteElement.widget] associated to this [VRouteElement]
110 : ///
111 : /// [child] will be the [VRouteElement.widget] of the matched [VRouteElement] in
112 : /// [nestedRoutes]
113 : final Widget Function(Widget child) widgetBuilder;
114 :
115 : /// A LocalKey that will be given to the page which contains the given [widget]
116 : ///
117 : /// This key mostly controls the page animation. If a page remains the same but the key is changes,
118 : /// the page gets animated
119 : /// The key is by default the value of the current [path] (or [aliases]) with
120 : /// the path parameters replaced
121 : ///
122 : /// Do provide a constant [key] if you don't want this page to animate even if [path] or
123 : /// [aliases] path parameters change
124 : final LocalKey? key;
125 :
126 : /// The duration of [VWidgetBase.buildTransition]
127 : final Duration? transitionDuration;
128 :
129 : /// The reverse duration of [VWidgetBase.buildTransition]
130 : final Duration? reverseTransitionDuration;
131 :
132 : /// Create a custom transition effect when coming to and
133 : /// going to this route
134 : /// This has the priority over [VRouter.buildTransition]
135 : ///
136 : /// Also see:
137 : /// * [VRouter.buildTransition] for default transitions for all routes
138 : final Widget Function(Animation<double> animation,
139 : Animation<double> secondaryAnimation, Widget child)? buildTransition;
140 :
141 2 : VNester({
142 : required this.path,
143 : required this.widgetBuilder,
144 : required this.nestedRoutes,
145 : this.transitionDuration,
146 : this.reverseTransitionDuration,
147 : this.buildTransition,
148 : this.key,
149 : this.name,
150 : this.stackedRoutes = const [],
151 : this.aliases = const [],
152 : this.mustMatchStackedRoute = false,
153 : });
154 :
155 2 : @override
156 2 : List<VRouteElement> buildRoutes() => [
157 2 : VPath(
158 2 : path: path,
159 2 : name: name,
160 2 : aliases: aliases,
161 2 : mustMatchStackedRoute: mustMatchStackedRoute,
162 2 : stackedRoutes: [
163 2 : VNesterBase(
164 2 : key: key,
165 2 : nestedRoutes: nestedRoutes,
166 2 : stackedRoutes: stackedRoutes,
167 2 : widgetBuilder: widgetBuilder,
168 2 : buildTransition: buildTransition,
169 2 : transitionDuration: transitionDuration,
170 2 : reverseTransitionDuration: reverseTransitionDuration,
171 : ),
172 : ],
173 : ),
174 : ];
175 : }
|