LCOV - code coverage report
Current view: top level - src/vroute_elements - vnester_page.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 118 147 80.3 %
Date: 2021-03-18 15:42:40 Functions: 0 0 -

          Line data    Source code
       1             : part of '../main.dart';
       2             : 
       3             : @immutable
       4             : class VNesterPage extends VPage {
       5             :   final List<VRouteElement> nestedRoutes;
       6             :   final Widget Function(Widget child) widgetBuilder;
       7             : 
       8           3 :   VNesterPage({
       9             :     required String? path,
      10             :     required Page Function(Widget child) pageBuilder,
      11             :     required this.widgetBuilder,
      12             :     required this.nestedRoutes,
      13             :     String? name,
      14             :     List<VRouteElement> stackedRoutes = const [],
      15             :     List<String> aliases = const [],
      16             :     bool mustMatchSubRoute = false,
      17           3 :   })  : assert(nestedRoutes.isNotEmpty,
      18             :             'The stackedRoutes of a VNester should not be null, otherwise it can\'t nest'),
      19           3 :         navigatorKey = GlobalKey<NavigatorState>(),
      20           3 :         heroController = HeroController(),
      21           3 :         super(
      22             :           pageBuilder: pageBuilder,
      23           6 :           widget: widgetBuilder(Container()),
      24             :           path: path,
      25             :           name: name,
      26             :           stackedRoutes: stackedRoutes,
      27             :           aliases: aliases,
      28             :           mustMatchSubRoute: mustMatchSubRoute,
      29             :         );
      30             : 
      31             :   /// A key for the navigator
      32             :   /// It is created automatically
      33             :   final GlobalKey<NavigatorState> navigatorKey;
      34             : 
      35             :   /// A hero controller for the navigator
      36             :   /// It is created automatically
      37             :   final HeroController heroController;
      38             : 
      39           2 :   @override
      40             :   VRoute? buildRoute(
      41             :     VPathRequestData vPathRequestData, {
      42             :     required String? parentRemainingPath,
      43             :     required Map<String, String> parentPathParameters,
      44             :   }) {
      45             :     VRoute? nestedRouteVRoute;
      46             :     late final GetPathMatchResult getPathMatchResult;
      47             : 
      48             :     // Try to find valid VRoute from nestedRoutes
      49             : 
      50             :     // Check for the path
      51           2 :     final pathGetPathMatchResult = getPathMatch(
      52           2 :       entirePath: vPathRequestData.path,
      53             :       remainingPathFromParent: parentRemainingPath,
      54           2 :       selfPath: path,
      55           2 :       selfPathRegExp: pathRegExp,
      56           2 :       selfPathParametersKeys: pathParametersKeys,
      57             :       parentPathParameters: parentPathParameters,
      58             :     );
      59           2 :     final VRoute? vRoute = getVRouteFromRoutes(
      60             :       vPathRequestData,
      61           2 :       routes: nestedRoutes,
      62             :       getPathMatchResult: pathGetPathMatchResult,
      63             :     );
      64             :     if (vRoute != null) {
      65             :       // If we have a matching path with the path, keep it
      66             :       nestedRouteVRoute = vRoute;
      67           0 :       getPathMatchResult = pathGetPathMatchResult;
      68             :     } else {
      69             :       // Else check with the aliases
      70           7 :       for (var i = 0; i < aliases.length; i++) {
      71           1 :         final aliasGetPathMatchResult = getPathMatch(
      72           1 :           entirePath: vPathRequestData.path,
      73             :           remainingPathFromParent: parentRemainingPath,
      74           2 :           selfPath: aliases[i],
      75           2 :           selfPathRegExp: aliasesRegExp[i],
      76           2 :           selfPathParametersKeys: aliasesPathParametersKeys[i],
      77             :           parentPathParameters: parentPathParameters,
      78             :         );
      79           1 :         final VRoute? vRoute = getVRouteFromRoutes(
      80             :           vPathRequestData,
      81           1 :           routes: nestedRoutes,
      82             :           getPathMatchResult: aliasGetPathMatchResult,
      83             :         );
      84             :         if (vRoute != null) {
      85             :           nestedRouteVRoute = vRoute;
      86           0 :           getPathMatchResult = aliasGetPathMatchResult;
      87             :           break;
      88             :         }
      89             :       }
      90             :     }
      91             : 
      92             :     // If no child route match, this is not a match
      93             :     if (nestedRouteVRoute == null) {
      94             :       return null;
      95             :     }
      96             : 
      97             :     // Else also try to match nestedRoute with the path (or the alias) with which the nestedRoute was valid
      98           2 :     final VRoute? stackedRouteVRoute = getVRouteFromRoutes(
      99             :       vPathRequestData,
     100           2 :       routes: stackedRoutes,
     101           0 :       getPathMatchResult: getPathMatchResult,
     102             :     );
     103             : 
     104             :     if (stackedRouteVRoute == null) {
     105           2 :       final newVRouteElements = VRouteElementNode(this,
     106           2 :           nestedVRouteElementNode: nestedRouteVRoute.vRouteElementNode);
     107             : 
     108             :       // If stackedRouteVRoute is null, create a VRoute with nestedRouteVRoute
     109           2 :       return VRoute(
     110             :         vRouteElementNode: newVRouteElements,
     111           2 :         pages: [
     112           2 :           buildPage(
     113           4 :             widget: widgetBuilder(
     114           2 :               Builder(
     115           2 :                 builder: (BuildContext context) {
     116           2 :                   return VRouterHelper(
     117           4 :                     pages: nestedRouteVRoute!.pages.isNotEmpty
     118           2 :                         ? nestedRouteVRoute.pages
     119           0 :                         : [
     120           0 :                             MaterialPage(child: Center(child: CircularProgressIndicator())),
     121             :                           ],
     122           2 :                     navigatorKey: navigatorKey,
     123           4 :                     observers: [heroController],
     124             :                     backButtonDispatcher:
     125           6 :                         ChildBackButtonDispatcher(Router.of(context).backButtonDispatcher!),
     126           1 :                     onPopPage: (_, __) {
     127           2 :                       RootVRouterData.of(context).pop(
     128           2 :                         nestedRouteVRoute!.vRouteElementNode.getVRouteElementToPop(),
     129           2 :                         pathParameters: VRouter.of(context).pathParameters,
     130             :                       );
     131             : 
     132             :                       // We always prevent popping because we handle it in VRouter
     133             :                       return false;
     134             :                     },
     135           0 :                     onSystemPopPage: () async {
     136           0 :                       await RootVRouterData.of(context).systemPop(
     137           0 :                         nestedRouteVRoute!.vRouteElementNode.getVRouteElementToPop(),
     138           0 :                         pathParameters: VRouter.of(context).pathParameters,
     139             :                       );
     140             : 
     141             :                       // We always prevent popping because we handle it in VRouter
     142             :                       return true;
     143             :                     },
     144             :                   );
     145             :                 },
     146             :               ),
     147             :             ),
     148             :             vPathRequestData: vPathRequestData,
     149           2 :             pathParameters: nestedRouteVRoute.pathParameters,
     150             :             vRouteElementNode: newVRouteElements,
     151             :           ),
     152             :         ],
     153           2 :         pathParameters: nestedRouteVRoute.pathParameters,
     154           6 :         vRouteElements: <VRouteElement>[this] + nestedRouteVRoute.vRouteElements,
     155             :       );
     156             :     } else {
     157             :       // If stackedRouteVRoute is NOT null, create a VRoute by mixing nestedRouteVRoute and stackedRouteVRoute
     158             : 
     159           1 :       final allPathParameters = {
     160           1 :         ...nestedRouteVRoute.pathParameters,
     161           1 :         ...stackedRouteVRoute.pathParameters,
     162             :       };
     163           1 :       final newVRouteElementNode = VRouteElementNode(
     164             :         this,
     165           1 :         nestedVRouteElementNode: nestedRouteVRoute.vRouteElementNode,
     166           1 :         stackedVRouteElementNode: stackedRouteVRoute.vRouteElementNode,
     167             :       );
     168             : 
     169           1 :       return VRoute(
     170             :         vRouteElementNode: newVRouteElementNode,
     171           1 :         pages: [
     172           1 :           buildPage(
     173           1 :             widget: Builder(
     174           1 :               builder: (BuildContext context) {
     175           1 :                 return VRouterHelper(
     176           1 :                   pages: nestedRouteVRoute!.pages,
     177           1 :                   navigatorKey: navigatorKey,
     178           2 :                   observers: [heroController],
     179             :                   backButtonDispatcher:
     180           3 :                       ChildBackButtonDispatcher(Router.of(context).backButtonDispatcher!),
     181           0 :                   onPopPage: (_, __) {
     182           0 :                     RootVRouterData.of(context).pop(
     183           0 :                       newVRouteElementNode.getVRouteElementToPop(),
     184           0 :                       pathParameters: VRouter.of(context).pathParameters,
     185             :                     );
     186             :                     return false;
     187             :                   },
     188           0 :                   onSystemPopPage: () async {
     189           0 :                     await RootVRouterData.of(context).systemPop(
     190           0 :                       newVRouteElementNode.getVRouteElementToPop(),
     191           0 :                       pathParameters: VRouter.of(context).pathParameters,
     192             :                     );
     193             :                     return true;
     194             :                   },
     195             :                 );
     196             :               },
     197             :             ),
     198             :             vPathRequestData: vPathRequestData,
     199             :             pathParameters: allPathParameters,
     200             :             vRouteElementNode: newVRouteElementNode,
     201             :           ),
     202           1 :           ...stackedRouteVRoute.pages,
     203             :         ],
     204             :         pathParameters: allPathParameters,
     205           2 :         vRouteElements: <VRouteElement>[this] +
     206           2 :             nestedRouteVRoute.vRouteElements +
     207           1 :             stackedRouteVRoute.vRouteElements,
     208             :       );
     209             :     }
     210             :   }
     211             : 
     212           1 :   String? getPathFromName(
     213             :     String nameToMatch, {
     214             :     required Map<String, String> pathParameters,
     215             :     required String? parentPath,
     216             :     required Map<String, String> remainingPathParameters,
     217             :   }) {
     218             :     // A variable to store the new parentPath from the path
     219             :     late final String? newParentPathFromPath;
     220             :     late final Map<String, String> newRemainingPathParametersFromPath;
     221             : 
     222             :     // A variable to store the new parent path from the aliases
     223           1 :     final List<String?> newParentPathFromAliases = [];
     224           1 :     final List<Map<String, String>> newRemainingPathParametersFromAliases = [];
     225             : 
     226             :     // Get the new parent path by taking this path into account
     227           1 :     newParentPathFromPath = getNewParentPath(parentPath,
     228           2 :         path: path, pathParametersKeys: pathParametersKeys, pathParameters: pathParameters);
     229             : 
     230           1 :     newRemainingPathParametersFromPath = Map<String, String>.from(remainingPathParameters)
     231           1 :       ..removeWhere((key, value) => pathParametersKeys.contains(key));
     232             : 
     233             :     // Check if any nested route matches the name using path
     234           2 :     for (var vRouteElement in nestedRoutes) {
     235           1 :       String? childPathFromName = vRouteElement.getPathFromName(
     236             :         nameToMatch,
     237             :         pathParameters: pathParameters,
     238           0 :         parentPath: newParentPathFromPath,
     239           0 :         remainingPathParameters: newRemainingPathParametersFromPath,
     240             :       );
     241             :       if (childPathFromName != null) {
     242             :         return childPathFromName;
     243             :       }
     244             :     }
     245             : 
     246             :     // Check if any subroute matches the name using path
     247           1 :     for (var vRouteElement in stackedRoutes) {
     248           0 :       String? childPathFromName = vRouteElement.getPathFromName(
     249             :         nameToMatch,
     250             :         pathParameters: pathParameters,
     251           0 :         parentPath: newParentPathFromPath,
     252           0 :         remainingPathParameters: newRemainingPathParametersFromPath,
     253             :       );
     254             :       if (childPathFromName != null) {
     255             :         return childPathFromName;
     256             :       }
     257             :     }
     258             : 
     259           4 :     for (var i = 0; i < aliases.length; i++) {
     260             :       // Get the new parent path by taking this alias into account
     261           2 :       newParentPathFromAliases.add(getNewParentPath(
     262             :         parentPath,
     263           2 :         path: aliases[i],
     264           2 :         pathParametersKeys: aliasesPathParametersKeys[i],
     265             :         pathParameters: pathParameters,
     266             :       ));
     267           1 :       newRemainingPathParametersFromAliases.add(
     268           1 :         Map<String, String>.from(remainingPathParameters)
     269           1 :           ..removeWhere((key, value) => pathParametersKeys.contains(key)),
     270             :       );
     271             : 
     272             :       // Check if any nested route matches the name using aliases
     273           2 :       for (var vRouteElement in nestedRoutes) {
     274           1 :         String? childPathFromName = vRouteElement.getPathFromName(
     275             :           nameToMatch,
     276             :           pathParameters: pathParameters,
     277           1 :           parentPath: newParentPathFromAliases[i],
     278           1 :           remainingPathParameters: newRemainingPathParametersFromAliases[i],
     279             :         );
     280             :         if (childPathFromName != null) {
     281             :           return childPathFromName;
     282             :         }
     283             :       }
     284             : 
     285             :       // Check if any subroute matches the name using aliases
     286           1 :       for (var vRouteElement in stackedRoutes) {
     287           0 :         String? childPathFromName = vRouteElement.getPathFromName(
     288             :           nameToMatch,
     289             :           pathParameters: pathParameters,
     290           0 :           parentPath: newParentPathFromAliases[i],
     291           0 :           remainingPathParameters: newRemainingPathParametersFromAliases[i],
     292             :         );
     293             :         if (childPathFromName != null) {
     294             :           return childPathFromName;
     295             :         }
     296             :       }
     297             :     }
     298             : 
     299             :     // If no subroute matches the name, try to match this name
     300           2 :     if (name == nameToMatch) {
     301             :       // Note that newParentPath will be null if this path can't be included so the return value
     302             :       // is the right one
     303           1 :       if (newParentPathFromPath != null && newRemainingPathParametersFromPath.isEmpty) {
     304           0 :         return newParentPathFromPath;
     305             :       }
     306           3 :       for (var i = 0; i < aliases.length; i++) {
     307           1 :         if (newParentPathFromAliases[i] != null &&
     308           2 :             newRemainingPathParametersFromAliases[i].isEmpty) {
     309           1 :           return newParentPathFromAliases[i];
     310             :         }
     311             :       }
     312             :     }
     313             : 
     314             :     // Else we return null
     315             :     return null;
     316             :   }
     317             : 
     318           3 :   GetPathFromPopResult? getPathFromPop(
     319             :     VRouteElement elementToPop, {
     320             :     required Map<String, String> pathParameters,
     321             :     required String? parentPath,
     322             :   }) {
     323             :     // If vRouteElement is this, then this is the element to pop so we return null
     324           3 :     if (elementToPop == this) {
     325           0 :       return GetPathFromPopResult(path: parentPath, didPop: true);
     326             :     }
     327             : 
     328             :     // Try to match the path given the path parameters
     329           3 :     final newParentPathFromPath = getNewParentPath(
     330             :       parentPath,
     331           3 :       path: path,
     332           3 :       pathParametersKeys: pathParametersKeys,
     333             :       pathParameters: pathParameters,
     334             :     );
     335             : 
     336           6 :     print('newParentPathFromPath: $newParentPathFromPath');
     337             : 
     338             :     // If the path matched and produced a non null newParentPath, try to pop from the stackedRoutes or the nestedRoutes
     339             :     if (newParentPathFromPath != null) {
     340             :       // Try to pop from the stackedRoutes
     341           4 :       for (var vRouteElement in stackedRoutes) {
     342           1 :         final childPopResult = vRouteElement.getPathFromPop(
     343             :           elementToPop,
     344             :           pathParameters: pathParameters,
     345             :           parentPath: newParentPathFromPath,
     346             :         );
     347             :         if (childPopResult != null) {
     348           2 :           return GetPathFromPopResult(path: childPopResult.path, didPop: false);
     349             :         }
     350             :       }
     351             : 
     352             :       // Try to pop from the nestedRoutes
     353           6 :       for (var vRouteElement in nestedRoutes) {
     354           3 :         final childPopResult = vRouteElement.getPathFromPop(
     355             :           elementToPop,
     356             :           pathParameters: pathParameters,
     357             :           parentPath: newParentPathFromPath,
     358             :         );
     359             :         if (childPopResult != null) {
     360           3 :           if (childPopResult.didPop) {
     361             :             // if the nestedRoute popped, we should pop too
     362           3 :             return GetPathFromPopResult(path: parentPath, didPop: true);
     363             :           } else {
     364           9 :             print('childPopResult.path: ${childPopResult.path}');
     365           6 :             return GetPathFromPopResult(path: childPopResult.path, didPop: false);
     366             :           }
     367             :         }
     368             :       }
     369             :     }
     370             : 
     371             :     // Try to match the aliases given the path parameters
     372           3 :     for (var i = 0; i < aliases.length; i++) {
     373           1 :       final newParentPathFromAlias = getNewParentPath(
     374             :         parentPath,
     375           2 :         path: aliases[i],
     376           2 :         pathParametersKeys: aliasesPathParametersKeys[i],
     377             :         pathParameters: pathParameters,
     378             :       );
     379             : 
     380             :       // If an alias matched and produced a non null newParentPath, try to pop from the stackedRoutes or the nestedRoutes
     381             :       if (newParentPathFromAlias != null) {
     382             :         // Try to pop from the stackedRoutes
     383           1 :         for (var vRouteElement in stackedRoutes) {
     384           0 :           final childPopResult = vRouteElement.getPathFromPop(
     385             :             elementToPop,
     386             :             pathParameters: pathParameters,
     387             :             parentPath: newParentPathFromAlias,
     388             :           );
     389             :           if (childPopResult != null) {
     390           0 :             return GetPathFromPopResult(path: childPopResult.path, didPop: false);
     391             :           }
     392             :         }
     393             : 
     394             :         // Try to pop from the nested routes
     395           2 :         for (var vRouteElement in nestedRoutes) {
     396           1 :           final childPopResult = vRouteElement.getPathFromPop(
     397             :             elementToPop,
     398             :             pathParameters: pathParameters,
     399             :             parentPath: newParentPathFromAlias,
     400             :           );
     401             :           if (childPopResult != null) {
     402           1 :             if (childPopResult.didPop) {
     403             :               // if the nestedRoute popped, we should pop too
     404           1 :               return GetPathFromPopResult(path: parentPath, didPop: true);
     405             :             } else {
     406           2 :               return GetPathFromPopResult(path: childPopResult.path, didPop: false);
     407             :             }
     408             :           }
     409             :         }
     410             :       }
     411             :     }
     412             : 
     413             :     // If none of the stackedRoutes nor the nestedRoutes popped and this did not pop, return a null result
     414             :     return null;
     415             :   }
     416             : }

Generated by: LCOV version 1.14