buildRoute method
- VPathRequestData vPathRequestData, {
- required VPathMatch parentVPathMatch,
- required bool parentCanPop,
buildRoute must return VRoute if it constitute (which its subroutes or not) a valid route given the input parameters VRoute should describe this valid route
vPathRequestData
contains all the information about the original request coming
from VRouter
It should not be changed and should be given as-is to its subroutes
parentRemainingPath
is the part on which to base any local path
WARNING: parentRemainingPath
is null if the parent did not match the path
in which case only absolute path should be tested.
parentPathParameters
are the path parameters of every VRouteElement above this
one in the route
buildRoute basically just checks for a match in stackedRoutes and if any adds this VRouteElement to the VRoute
For more info on buildRoute, see VRouteElement.buildRoute
Implementation
@override
VRoute? buildRoute(
VPathRequestData vPathRequestData, {
required VPathMatch parentVPathMatch,
required bool parentCanPop,
}) {
// Set localPath to null since a VNesterPageBase marks a limit between localPaths
VPathMatch newVPathMatch = (parentVPathMatch is ValidVPathMatch)
? ValidVPathMatch(
remainingPath: parentVPathMatch.remainingPath,
pathParameters: parentVPathMatch.pathParameters,
localPath: null,
names: parentVPathMatch.names + [if (name != null) name!],
)
: InvalidVPathMatch(
localPath: null,
names: parentVPathMatch.names + [if (name != null) name!],
);
// Try to find valid VRoute from nestedRoutes
VRoute? nestedRouteVRoute;
for (var vRouteElement in nestedRoutes) {
nestedRouteVRoute = vRouteElement.buildRoute(
vPathRequestData,
parentVPathMatch: newVPathMatch,
parentCanPop: parentCanPop,
);
if (nestedRouteVRoute != null) {
break;
}
}
// If no child route match, this is not a match
if (nestedRouteVRoute == null) {
return null;
}
// Else also try to match stackedRoutes
VRoute? stackedRouteVRoute;
for (var vRouteElement in stackedRoutes) {
stackedRouteVRoute = vRouteElement.buildRoute(
vPathRequestData,
parentVPathMatch: newVPathMatch,
parentCanPop: true,
);
if (stackedRouteVRoute != null) {
break;
}
}
final vRouteElementNode = VRouteElementNode(
this,
localPath: null,
nestedVRouteElementNode: nestedRouteVRoute.vRouteElementNode,
stackedVRouteElementNode: stackedRouteVRoute?.vRouteElementNode,
);
final pathParameters = {
...nestedRouteVRoute.pathParameters,
...stackedRouteVRoute?.pathParameters ?? {},
};
final names = <String>[
...nestedRouteVRoute.names,
...stackedRouteVRoute?.names ?? [],
].toSet().toList();
return VRoute(
vRouteElementNode: vRouteElementNode,
pages: [
pageBuilder(
key ?? ValueKey(parentVPathMatch.localPath),
Builder(
builder: (context) => LocalVRouterData(
child: NotificationListener<VWidgetGuardMessage>(
// This listen to [VWidgetGuardNotification] which is a notification
// that a [VWidgetGuard] sends when it is created
// When this happens, we store the VWidgetGuard and its context
// This will be used to call its afterUpdate and beforeLeave in particular.
onNotification: (VWidgetGuardMessage vWidgetGuardMessage) {
// VWidgetGuardMessageRoot(
// vWidgetGuardState: vWidgetGuardMessage.vWidgetGuardState,
// localContext: vWidgetGuardMessage.localContext,
// associatedVRouteElement: this,
// ).dispatch(vPathRequestData.rootVRouterContext);
return false;
},
child: widgetBuilder(
Builder(
builder: (BuildContext context) {
return VRouterHelper(
pages: <Page>[if (parentCanPop) EmptyPage()] +
(nestedRouteVRoute!.pages.isNotEmpty
? nestedRouteVRoute.pages
: [EmptyPage()]),
navigatorKey: navigatorKey,
observers: <NavigatorObserver>[
VNestedObserverReporter(
navigatorObserversToReportTo:
vPathRequestData.navigatorObserversToReportTo,
),
heroController
],
backButtonDispatcher: ChildBackButtonDispatcher(
Router.of(context).backButtonDispatcher!,
)..takePriority(),
onPopPage: (route, data) {
// Try to pop a Nav1 page, if successful return false
if (!(route.settings is Page)) {
route.didPop(data);
return true;
}
// Else use [VRouterDelegate.pop]
late final vPopData;
if (data is VPopData) {
vPopData = data;
} else {
vPopData = VPopData(
elementToPop: nestedRouteVRoute!.vRouteElementNode
.getVRouteElementToPop(),
pathParameters: pathParameters,
queryParameters: {},
hash: '', // Pop to no hash be default
newHistoryState: {},
);
}
RootVRouterData.of(context).popFromElement(
vPopData.elementToPop,
pathParameters: vPopData.pathParameters,
queryParameters: vPopData.newHistoryState,
newHistoryState: vPopData.newHistoryState,
);
return false;
},
onSystemPopPage: () async {
// Try to pop a Nav1 page, if successful return true
if (navigatorKey.currentState!.isLastRouteNav1) {
navigatorKey.currentState!.pop();
return true; // We handled it
}
// Return false because we handle it in VRouter
return false;
},
);
},
),
),
),
vRouteElementNode: vRouteElementNode,
url: vPathRequestData.url,
previousUrl: vPathRequestData.previousUrl,
historyState: vPathRequestData.historyState,
pathParameters: pathParameters,
queryParameters: vPathRequestData.queryParameters,
context: context,
),
),
name ?? parentVPathMatch.localPath,
VRouterDataImpl(
previousUrl: vPathRequestData.previousUrl,
url: vPathRequestData.url,
pathParameters: pathParameters,
queryParameters: vPathRequestData.queryParameters,
historyState: vPathRequestData.historyState,
names: names,
),
),
...stackedRouteVRoute?.pages ?? [],
],
pathParameters: pathParameters,
vRouteElements: <VRouteElement>[this] +
nestedRouteVRoute.vRouteElements +
(stackedRouteVRoute?.vRouteElements ?? []),
names: names,
);
}