LCOV - code coverage report
Current view: top level - src/vroute_elements - vroute_element_with_page.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 72 72 100.0 %
Date: 2021-04-29 14:25:52 Functions: 0 0 -

          Line data    Source code
       1             : part of '../main.dart';
       2             : 
       3             : /// If the [VRouteElement] does have a page to display, it should extend this class
       4             : ///
       5             : /// What is does is:
       6             : ///   - Requiring attribute [widget]
       7             : ///   - implementing [buildRoute] methods
       8             : @immutable
       9             : mixin VRouteElementWithPage on VRouteElement {
      10             :   List<VRouteElement> get stackedRoutes;
      11             : 
      12             :   /// The widget which will be displayed for the given [path]
      13             :   Page Function(LocalKey key, Widget child, String? name) get pageBuilder;
      14             : 
      15             :   /// The widget which will be put inside the page
      16             :   Widget get widget;
      17             : 
      18             :   /// The key associated to the page
      19             :   LocalKey? get key;
      20             : 
      21             :   /// A name for the route which will allow you to easily navigate to it
      22             :   /// using [VRouter.of(context).pushNamed]
      23             :   ///
      24             :   /// Note that [name] should be unique w.r.t every [VRouteElement]
      25             :   String? get name;
      26             : 
      27             :   /// This is basically the same as [VPath.buildRoute] except that
      28             :   /// we add the page of this [VRouteElement] as a page to [VRoute.pages]
      29          12 :   @override
      30             :   VRoute? buildRoute(
      31             :     VPathRequestData vPathRequestData, {
      32             :     required VPathMatch parentVPathMatch,
      33             :   }) {
      34             :     // Set localPath to null since a VRouteElementWithPage marks a limit between localPaths
      35          12 :     VPathMatch newVPathMatch = (parentVPathMatch is ValidVPathMatch)
      36          12 :         ? ValidVPathMatch(
      37          12 :             remainingPath: parentVPathMatch.remainingPath,
      38          12 :             pathParameters: parentVPathMatch.pathParameters,
      39             :             localPath: null,
      40             :           )
      41          12 :         : InvalidVPathMatch(localPath: null);
      42             : 
      43             :     VRoute? childVRoute;
      44          24 :     for (var vRouteElement in stackedRoutes) {
      45          12 :       childVRoute = vRouteElement.buildRoute(
      46             :         vPathRequestData,
      47             :         parentVPathMatch: newVPathMatch,
      48             :       );
      49             :       if (childVRoute != null) {
      50             :         break;
      51             :       }
      52             :     }
      53             : 
      54          12 :     final bool validParentVRoute = !(parentVPathMatch is InvalidVPathMatch) &&
      55          24 :         (parentVPathMatch as ValidVPathMatch).remainingPath.isEmpty;
      56             :     if (childVRoute == null && !validParentVRoute) {
      57             :       return null;
      58             :     }
      59             : 
      60          12 :     final VRouteElementNode vRouteElementNode = VRouteElementNode(
      61             :       this,
      62             :       localPath: null,
      63          12 :       stackedVRouteElementNode: childVRoute?.vRouteElementNode,
      64             :     );
      65             : 
      66          12 :     Map<String, String> pathParameters = childVRoute?.pathParameters ??
      67          12 :         (parentVPathMatch as ValidVPathMatch).pathParameters;
      68             : 
      69          12 :     return VRoute(
      70             :       vRouteElementNode: vRouteElementNode,
      71          12 :       pages: [
      72          24 :         pageBuilder(
      73          36 :           key ?? ValueKey(parentVPathMatch.localPath),
      74          12 :           LocalVRouterData(
      75          12 :             child: NotificationListener<VWidgetGuardMessage>(
      76             :               // This listen to [VWidgetGuardNotification] which is a notification
      77             :               // that a [VWidgetGuard] sends when it is created
      78             :               // When this happens, we store the VWidgetGuard and its context
      79             :               // This will be used to call its afterUpdate and beforeLeave in particular.
      80           1 :               onNotification: (VWidgetGuardMessage vWidgetGuardMessage) {
      81           1 :                 VWidgetGuardMessageRoot(
      82           1 :                   vWidgetGuard: vWidgetGuardMessage.vWidgetGuard,
      83           1 :                   localContext: vWidgetGuardMessage.localContext,
      84             :                   associatedVRouteElement: this,
      85           2 :                 ).dispatch(vPathRequestData.rootVRouterContext);
      86             : 
      87             :                 return true;
      88             :               },
      89          12 :               child: widget,
      90             :             ),
      91             :             vRouteElementNode: vRouteElementNode,
      92          12 :             url: vPathRequestData.url,
      93          12 :             previousUrl: vPathRequestData.previousUrl,
      94          12 :             historyState: vPathRequestData.historyState,
      95             :             pathParameters: pathParameters,
      96          12 :             queryParameters: vPathRequestData.queryParameters,
      97          12 :             context: vPathRequestData.rootVRouterContext,
      98             :           ),
      99          24 :           name ?? parentVPathMatch.localPath,
     100             :         ),
     101          36 :         ...childVRoute?.pages ?? []
     102             :       ],
     103             :       pathParameters: pathParameters,
     104             :       vRouteElements:
     105          48 :           <VRouteElement>[this] + (childVRoute?.vRouteElements ?? []),
     106             :     );
     107             :   }
     108             : 
     109             :   /// Tries to find a path from a name
     110             :   ///
     111             :   /// This first asks its stackedRoutes if they have a match
     112             :   /// Else is tries to see if this [VRouteElement] matches the name
     113             :   /// Else return null
     114             :   ///
     115             :   /// Note that not only the name must match but the path parameters must be able to form a
     116             :   /// valid path afterward too
     117           7 :   GetPathFromNameResult getPathFromName(
     118             :     String nameToMatch, {
     119             :     required Map<String, String> pathParameters,
     120             :     required GetNewParentPathResult parentPathResult,
     121             :     required Map<String, String> remainingPathParameters,
     122             :   }) {
     123           7 :     final List<GetPathFromNameResult> childNameResults = [];
     124             : 
     125             :     // Check if any subroute matches the name
     126          13 :     for (var vRouteElement in stackedRoutes) {
     127           6 :       childNameResults.add(
     128           6 :         vRouteElement.getPathFromName(
     129             :           nameToMatch,
     130             :           pathParameters: pathParameters,
     131             :           parentPathResult: parentPathResult,
     132             :           remainingPathParameters: remainingPathParameters,
     133             :         ),
     134             :       );
     135          12 :       if (childNameResults.last is ValidNameResult) {
     136           6 :         return childNameResults.last;
     137             :       }
     138             :     }
     139             : 
     140             :     // If no subroute matches the name, try to match this name
     141          14 :     if (name == nameToMatch) {
     142             :       // If path or any alias is valid considering the given path parameters, return this
     143           6 :       if (parentPathResult is ValidParentPathResult) {
     144           6 :         if (parentPathResult.path == null) {
     145             :           // If this path is null, we add a NullPathErrorNameResult
     146           2 :           childNameResults.add(NullPathErrorNameResult(name: nameToMatch));
     147             :         } else {
     148           6 :           if (remainingPathParameters.isNotEmpty) {
     149             :             // If there are path parameters remaining, wee add a PathParamsErrorsNameResult
     150           2 :             childNameResults.add(
     151           2 :               PathParamsErrorsNameResult(
     152             :                 name: nameToMatch,
     153           2 :                 values: [
     154           2 :                   OverlyPathParamsError(
     155           4 :                     pathParams: pathParameters.keys.toList(),
     156             :                     expectedPathParams:
     157           6 :                         parentPathResult.pathParameters.keys.toList(),
     158             :                   ),
     159             :                 ],
     160             :               ),
     161             :             );
     162             :           } else {
     163             :             // Else the result is valid
     164          10 :             return ValidNameResult(path: parentPathResult.path!);
     165             :           }
     166             :         }
     167             :       } else {
     168           2 :         assert(parentPathResult is PathParamsErrorNewParentPath);
     169           2 :         childNameResults.add(
     170           2 :           PathParamsErrorsNameResult(
     171             :             name: nameToMatch,
     172           2 :             values: [
     173           2 :               MissingPathParamsError(
     174           4 :                 pathParams: pathParameters.keys.toList(),
     175             :                 missingPathParams:
     176             :                     (parentPathResult as PathParamsErrorNewParentPath)
     177           2 :                         .pathParameters,
     178             :               ),
     179             :             ],
     180             :           ),
     181             :         );
     182             :       }
     183             :     }
     184             : 
     185             :     // If we don't have any valid result
     186             : 
     187             :     // If some stackedRoute returned PathParamsPopError, aggregate them
     188           5 :     final pathParamsNameErrors = PathParamsErrorsNameResult(
     189             :       name: nameToMatch,
     190           5 :       values: childNameResults.fold<List<PathParamsError>>(
     191           5 :         <PathParamsError>[],
     192           2 :         (previousValue, element) {
     193           2 :           return previousValue +
     194           5 :               ((element is PathParamsErrorsNameResult) ? element.values : []);
     195             :         },
     196             :       ),
     197             :     );
     198             : 
     199             :     // If there was any PathParamsPopError, we have some pathParamsPopErrors.values
     200             :     // and therefore should return this
     201          10 :     if (pathParamsNameErrors.values.isNotEmpty) {
     202             :       return pathParamsNameErrors;
     203             :     }
     204             : 
     205             :     // Else try to find a NullPathError
     206           5 :     if (childNameResults.indexWhere(
     207           7 :             (childNameResult) => childNameResult is NullPathErrorNameResult) !=
     208           5 :         -1) {
     209           1 :       return NullPathErrorNameResult(name: nameToMatch);
     210             :     }
     211             : 
     212             :     // Else return a NotFoundError
     213           5 :     return NotFoundErrorNameResult(name: nameToMatch);
     214             :   }
     215             : }

Generated by: LCOV version 1.14