LCOV - code coverage report
Current view: top level - src/vroute_elements - vroute_element.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 45 56 80.4 %
Date: 2021-04-26 23:10:51 Functions: 0 0 -

          Line data    Source code
       1             : part of '../main.dart';
       2             : 
       3             : /// [VRouteElement] is the base class for any object used in routes, stackedRoutes
       4             : /// or nestedRoutes
       5             : @immutable
       6             : abstract class VRouteElement {
       7             : 
       8             :   /// [buildRoute] must return [VRoute] if it constitute (which its subroutes or not) a valid
       9             :   /// route given the input parameters
      10             :   /// [VRoute] should describe this valid route
      11             :   ///
      12             :   ///
      13             :   /// [vPathRequestData] contains all the information about the original request coming
      14             :   /// from [VRouter]
      15             :   /// It should not be changed and should be given as-is to its subroutes
      16             :   ///
      17             :   /// [parentRemainingPath] is the part on which to base any local path
      18             :   /// WARNING: [parentRemainingPath] is null if the parent did not match the path
      19             :   /// in which case only absolute path should be tested.
      20             :   ///
      21             :   /// [parentPathParameters] are the path parameters of every [VRouteElement] above this
      22             :   /// one in the route
      23             :   ///
      24             :   /// [buildRoute] basically just checks for a match in stackedRoutes and if any
      25             :   /// adds this [VRouteElement] to the [VRoute]
      26             :   ///
      27             :   /// For more info on buildRoute, see [VRouteElement.buildRoute]
      28             :   VRoute? buildRoute(
      29             :     VPathRequestData vPathRequestData, {
      30             :     required VPathMatch parentVPathMatch,
      31             :   });
      32             : 
      33             :   /// This function takes a name and tries to find the path corresponding to
      34             :   /// the route matching this name
      35             :   ///
      36             :   /// The deeper nested the route the better
      37             :   /// The given path parameters have to include at least every path parameters of the final path
      38             :   GetPathFromNameResult getPathFromName(
      39             :     String nameToMatch, {
      40             :     required Map<String, String> pathParameters,
      41             :     required GetNewParentPathResult parentPathResult,
      42             :     required Map<String, String> remainingPathParameters,
      43             :   });
      44             : 
      45             :   /// [GetPathFromPopResult.didPop] is true if this [VRouteElement] popped
      46             :   /// [GetPathFromPopResult.extendedPath] is null if this path can't be the right one according to
      47             :   ///                                                                     the path parameters
      48             :   /// [GetPathFromPopResult] is null when this [VRouteElement] does not pop AND none of
      49             :   ///                                                                     its stackedRoutes popped
      50             :   GetPathFromPopResult getPathFromPop(
      51             :     VRouteElement elementToPop, {
      52             :     required Map<String, String> pathParameters,
      53             :     required GetNewParentPathResult parentPathResult,
      54             :   });
      55             : 
      56             :   /// This is called before the url is updated if this [VRouteElement] was NOT in the
      57             :   /// previous route but is in the new route
      58             :   ///
      59             :   /// Use [vRedirector] if you want to redirect or stop the navigation.
      60             :   /// DO NOT use VRouter methods to redirect.
      61             :   /// [vRedirector] also has information about the route you leave and the route you go to
      62             :   ///
      63             :   /// Note that you should consider the navigation cycle to
      64             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
      65             :   ///
      66             :   /// Also see:
      67             :   ///   * [VRouter.beforeEnter] for router level beforeEnter
      68             :   ///   * [VRedirector] to known how to redirect and have access to route information
      69             :   Future<void> beforeEnter(VRedirector vRedirector);
      70             : 
      71             :   /// This is called before the url is updated if this [VRouteElement] was in the previous
      72             :   /// route and is in the new route
      73             :   ///
      74             :   /// Use [vRedirector] if you want to redirect or stop the navigation.
      75             :   /// DO NOT use VRouter methods to redirect.
      76             :   /// [vRedirector] also has information about the route you leave and the route you go to
      77             :   ///
      78             :   /// Note that you should consider the navigation cycle to
      79             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
      80             :   ///
      81             :   /// Also see:
      82             :   ///   * [VWidgetGuard.beforeUpdate] for widget level beforeUpdate
      83             :   ///   * [VRedirector] to known how to redirect and have access to route information
      84             :   Future<void> beforeUpdate(VRedirector vRedirector);
      85             : 
      86             :   /// Called when a url changes, before the url is updated
      87             :   /// Use [vRedirector] if you want to redirect or stop the navigation.
      88             :   /// DO NOT use VRouter methods to redirect.
      89             :   /// [vRedirector] also has information about the route you leave and the route you go to
      90             :   ///
      91             :   /// [saveHistoryState] can be used to save a history state before leaving
      92             :   /// This history state will be restored if the user uses the back button
      93             :   /// You will find the saved history state in the [VRouteElementData] using
      94             :   /// [VRouter.of(context).historyState]
      95             :   ///
      96             :   /// Note that you should consider the navigation cycle to
      97             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
      98             :   ///
      99             :   /// Also see:
     100             :   ///   * [VRouteElement.beforeLeave] for route level beforeLeave
     101             :   ///   * [VWidgetGuard.beforeLeave] for widget level beforeLeave
     102             :   ///   * [VRedirector] to known how to redirect and have access to route information
     103             :   Future<void> beforeLeave(
     104             :     VRedirector vRedirector,
     105             :     void Function(Map<String, String> state) saveHistoryState,
     106             :   );
     107             : 
     108             :   /// This is called after the url and the historyState are updated and this [VRouteElement]
     109             :   /// was NOT in the previous route and is in the new route
     110             :   /// You can't prevent the navigation anymore
     111             :   /// You can get the new route parameters, and queryParameters
     112             :   ///
     113             :   /// Note that you should consider the navigation cycle to
     114             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
     115             :   ///
     116             :   /// Also see:
     117             :   ///   * [VRouter.afterEnter] for router level afterEnter
     118             :   ///   * [VWidgetGuard.afterEnter] for widget level afterEnter
     119             :   void afterEnter(BuildContext context, String? from, String to);
     120             : 
     121             :   /// This is called after the url and the historyState are updated and this [VRouteElement]
     122             :   /// was in the previous route and is in the new route
     123             :   /// You can't prevent the navigation anymore
     124             :   /// You can get the new route parameters, and queryParameters
     125             :   ///
     126             :   /// Note that you should consider the navigation cycle to
     127             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Navigation%20Control/The%20Navigation%20Cycle]
     128             :   ///
     129             :   /// Also see:
     130             :   ///   * [VWidgetGuard.afterUpdate] for widget level afterUpdate
     131             :   void afterUpdate(BuildContext context, String? from, String to);
     132             : 
     133             :   /// Called when a pop event occurs
     134             :   /// A pop event can be called programmatically (with [VRouter.of(context).pop()])
     135             :   /// or by other widgets such as the appBar back button
     136             :   ///
     137             :   /// Use [vRedirector] if you want to redirect or stop the navigation.
     138             :   /// DO NOT use VRouter methods to redirect.
     139             :   /// [vRedirector] also has information about the route you leave and the route you go to
     140             :   ///
     141             :   /// The route you go to is calculated based on [VRouterState._defaultPop]
     142             :   ///
     143             :   /// Note that you should consider the pop cycle to
     144             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Pop%20Events/onPop]
     145             :   ///
     146             :   /// Also see:
     147             :   ///   * [VRouter.onPop] for router level onPop
     148             :   ///   * [VWidgetGuard.onPop] for widget level onPop
     149             :   ///   * [VRedirector] to known how to redirect and have access to route information
     150             :   Future<void> onPop(VRedirector vRedirector);
     151             : 
     152             :   /// Called when a system pop event occurs.
     153             :   /// This happens on android when the system back button is pressed.
     154             :   ///
     155             :   /// Use [vRedirector] if you want to redirect or stop the navigation.
     156             :   /// DO NOT use VRouter methods to redirect.
     157             :   /// [vRedirector] also has information about the route you leave and the route you go to
     158             :   ///
     159             :   /// The route you go to is calculated based on [VRouterState._defaultPop]
     160             :   ///
     161             :   /// Note that you should consider the systemPop cycle to
     162             :   /// handle this precisely, see [https://vrouter.dev/guide/Advanced/Pop%20Events/onSystemPop]
     163             :   ///
     164             :   /// Also see:
     165             :   ///   * [VRouter.onSystemPop] for route level onSystemPop
     166             :   ///   * [VWidgetGuard.onSystemPop] for widget level onSystemPop
     167             :   ///   * [VRedirector] to known how to redirect and have access to route information
     168             :   Future<void> onSystemPop(VRedirector vRedirector);
     169             : }
     170             : 
     171             : /// Return type of [VRouteElement.getPathFromPop]
     172             : abstract class GetPathFromPopResult {}
     173             : 
     174             : class ValidPopResult extends GetPathFromPopResult {
     175             :   /// [extendedPath] should be deducted from the parent path, [VRouteElement.path] and the path parameters,
     176             :   ///  Note the it should be null if the path can not be deduced from the said parameters
     177             :   final String? path;
     178             : 
     179             :   /// [didPop] should be true if this [VRouteElement] is to be popped
     180             :   final bool didPop;
     181             : 
     182             :   /// List of every popping [VRouteElement]
     183             :   final List<VRouteElement> poppedVRouteElements;
     184             : 
     185           9 :   ValidPopResult({
     186             :     required this.path,
     187             :     required this.didPop,
     188             :     required this.poppedVRouteElements,
     189             :   });
     190             : }
     191             : 
     192             : abstract class ErrorGetPathFromPopResult extends GetPathFromPopResult
     193             :     implements Exception {}
     194             : 
     195             : class ErrorNotFoundGetPathFromPopResult extends ErrorGetPathFromPopResult {
     196           0 :   @override
     197             :   String toString() =>
     198             :       'The VRouteElement to pop was not found. Please open an issue, this should never happen.';
     199             : }
     200             : 
     201             : class PathParamsPopErrors extends ErrorGetPathFromPopResult {
     202             :   final List<MissingPathParamsError> values;
     203             : 
     204           4 :   PathParamsPopErrors({
     205             :     required this.values,
     206             :   });
     207             : 
     208           1 :   @override
     209             :   String toString() =>
     210             :       'Could not pop because some path parameters where missing. \n'
     211           1 :           'Here are the possible path parameters that were expected and the missing ones:\n' +
     212           1 :       [
     213           1 :         for (var value in values)
     214           2 :           '  - Path parameters: ${value.pathParams}, missing ones: ${value.missingPathParams}'
     215           2 :       ].join('\n');
     216             : }
     217             : 
     218             : /// Return type of [VRouteElement.getPathFromName]
     219             : abstract class GetPathFromNameResult {}
     220             : 
     221             : class ValidNameResult extends GetPathFromNameResult {
     222             :   /// [extendedPath] should be deducted from the parent path, [VRouteElement.path] and the path parameters,
     223             :   ///  Note the it should be null if the path can not be deduced from the said parameters
     224             :   final String path;
     225             : 
     226           6 :   ValidNameResult({required this.path});
     227             : }
     228             : 
     229             : abstract class ErrorGetPathFromNameResult extends GetPathFromNameResult
     230             :     implements Error {
     231             :   String get error;
     232             : 
     233           1 :   @override
     234           1 :   String toString() => error;
     235             : 
     236           0 :   @override
     237           0 :   StackTrace? get stackTrace => StackTrace.current;
     238             : }
     239             : 
     240             : class NotFoundErrorNameResult extends ErrorGetPathFromNameResult {
     241             :   final String name;
     242             : 
     243           7 :   NotFoundErrorNameResult({required this.name});
     244             : 
     245           3 :   String get error => 'Could not find the VRouteElement named $name.';
     246             : }
     247             : 
     248             : class NullPathErrorNameResult extends ErrorGetPathFromNameResult{
     249             :   final String name;
     250             : 
     251           1 :   NullPathErrorNameResult({required this.name});
     252             : 
     253           2 :   String get error =>
     254           1 :       'The VRouteElement named $name as a null path but no parent VRouteElement with a path.\n'
     255             :       'No valid path can therefore be formed.';
     256             : }
     257             : 
     258             : abstract class PathParamsError implements Error {
     259             :   List<String> get pathParams;
     260             : 
     261             :   String get error;
     262             : 
     263           0 :   @override
     264           0 :   String toString() => error;
     265             : 
     266           0 :   @override
     267           0 :   StackTrace? get stackTrace => StackTrace.current;
     268             : }
     269             : 
     270             : class MissingPathParamsError extends PathParamsError {
     271             :   final List<String> missingPathParams;
     272             :   final List<String> pathParams;
     273             : 
     274           5 :   MissingPathParamsError(
     275             :       {required this.pathParams, required this.missingPathParams});
     276             : 
     277           1 :   String get error =>
     278           3 :       'Path parameters given: $pathParams, missing: $missingPathParams';
     279             : }
     280             : 
     281             : class OverlyPathParamsError extends PathParamsError {
     282             :   final List<String> expectedPathParams;
     283             :   final List<String> pathParams;
     284             : 
     285           2 :   OverlyPathParamsError(
     286             :       {required this.pathParams, required this.expectedPathParams});
     287             : 
     288           1 :   String get error =>
     289           3 :       'Path parameters given: $pathParams, expected: $expectedPathParams';
     290             : }
     291             : 
     292             : class PathParamsErrorsNameResult extends ErrorGetPathFromNameResult {
     293             :   final List<PathParamsError> values;
     294             :   final String name;
     295             : 
     296           7 :   PathParamsErrorsNameResult({required this.name, required this.values});
     297             : 
     298           1 :   @override
     299           1 :   String get error =>
     300           1 :       'Could not find value route for name $name because of path parameters. \n'
     301           1 :           'Here are the possible path parameters that were expected compared to what you gave:\n' +
     302           5 :       [for (var value in values) '  - ${value.error}'].join('\n');
     303             : }
     304             : 
     305             : /// Hold every information of the current route we are building
     306             : /// This is used is [VRouteElement.buildRoute] and should be passed down to the next
     307             : /// [VRouteElement.buildRoute] without modification.
     308             : ///
     309             : /// The is used for two purposes:
     310             : ///   1. Giving the needed information for [VRouteElement.buildRoute] to decide how/if it should
     311             : ///       build its route
     312             : ///   2. Holds information that are used to populate the [LocalVRouterData] attached to every
     313             : ///   _  [VRouteElement]
     314             : class VPathRequestData {
     315             :   /// The previous url (which is actually the current one since when [VPathRequestData] is passed
     316             :   /// the url did not yet change from [VRouter] point of view)
     317             :   final String? previousUrl;
     318             : 
     319             :   /// The new uri. This is what should be used to determine the validity of the [VRouteElement]
     320             :   final Uri uri;
     321             : 
     322             :   /// The new history state, used to populate the [LocalVRouterData]
     323             :   final Map<String, String> historyState;
     324             : 
     325             :   /// A [BuildContext] with which we can access [RootVRouterData]
     326             :   final BuildContext rootVRouterContext;
     327             : 
     328          12 :   VPathRequestData({
     329             :     required this.previousUrl,
     330             :     required this.uri,
     331             :     required this.historyState,
     332             :     required this.rootVRouterContext,
     333             :   });
     334             : 
     335             :   /// The path contained in the uri
     336          36 :   String get path => uri.path;
     337             : 
     338             :   /// The query parameters contained in the uri
     339          36 :   Map<String, String> get queryParameters => uri.queryParameters;
     340             : 
     341             :   /// The url corresponding to the uri
     342          36 :   String get url => uri.toString();
     343             : }
     344             : 
     345             : /// [VRouteElementNode] is used to represent the current route configuration as a tree
     346             : class VRouteElementNode {
     347             :   /// The [VRouteElementNode] containing the [VRouteElement] which is the current nested route
     348             :   /// to be valid, if any
     349             :   ///
     350             :   /// The is used be all types of [VNestedPage]
     351             :   final VRouteElementNode? nestedVRouteElementNode;
     352             : 
     353             :   /// The [VRouteElementNode] containing the [VRouteElement] which is the current stacked routes
     354             :   /// to be valid, if any
     355             :   final VRouteElementNode? stackedVRouteElementNode;
     356             : 
     357             :   /// The [VRouteElement] attached to this node
     358             :   final VRouteElement vRouteElement;
     359             : 
     360             :   /// The path of the [VRouteElement] attached to this node
     361             :   /// If the path has path parameters, they should be replaced
     362             :   final String? localPath;
     363             : 
     364          12 :   VRouteElementNode(
     365             :     this.vRouteElement, {
     366             :     required this.localPath,
     367             :     this.nestedVRouteElementNode,
     368             :     this.stackedVRouteElementNode,
     369             :   });
     370             : 
     371             :   /// Finding the element to pop for a [VRouteElementNode] means finding which one is at the
     372             :   /// end of the chain of stackedVRouteElementNode (if none then this should be popped)
     373           8 :   VRouteElement getVRouteElementToPop() {
     374           8 :     if (stackedVRouteElementNode != null) {
     375          12 :       return stackedVRouteElementNode!.getVRouteElementToPop();
     376             :     }
     377           8 :     return vRouteElement;
     378             :   }
     379             : 
     380             :   /// This function will search this node and the nested and sub nodes to try to find the node
     381             :   /// that hosts [vRouteElement]
     382           1 :   VRouteElementNode? getChildVRouteElementNode({
     383             :     required VRouteElement vRouteElement,
     384             :   }) {
     385             :     // If this VRouteElementNode contains the given VRouteElement, return this
     386           2 :     if (vRouteElement == this.vRouteElement) {
     387             :       return this;
     388             :     }
     389             : 
     390             :     // Search if the VRouteElementNode containing the VRouteElement is in the nestedVRouteElementNode
     391           1 :     if (nestedVRouteElementNode != null) {
     392           0 :       VRouteElementNode? vRouteElementNode = nestedVRouteElementNode!
     393           0 :           .getChildVRouteElementNode(vRouteElement: vRouteElement);
     394             :       if (vRouteElementNode != null) {
     395             :         return vRouteElementNode;
     396             :       }
     397             :     }
     398             : 
     399             :     // Search if the VRouteElementNode containing the VRouteElement is in the stackedVRouteElementNode
     400           1 :     if (stackedVRouteElementNode != null) {
     401           1 :       VRouteElementNode? vRouteElementNode = stackedVRouteElementNode!
     402           1 :           .getChildVRouteElementNode(vRouteElement: vRouteElement);
     403             :       if (vRouteElementNode != null) {
     404             :         return vRouteElementNode;
     405             :       }
     406             :     }
     407             : 
     408             :     // If the VRouteElement was not find anywhere, return null
     409             :     return null;
     410             :   }
     411             : }
     412             : 
     413             : /// Part of [VRouteElement.buildRoute] that must be passed down but can be modified
     414             : abstract class VPathMatch {
     415             :   /// The local path is the one of the current VRouteElement
     416             :   /// If the path has path parameters, those should be replaced
     417             :   String? get localPath;
     418             : }
     419             : 
     420             : class ValidVPathMatch extends VPathMatch {
     421             :   /// The remaining of the path after having remove the part of the path that this
     422             :   /// [VPath] has matched
     423             :   final String remainingPath;
     424             : 
     425             :   /// The path parameters of the valid [VRoute] which are
     426             :   ///   - Empty if no valid [VRoute] has been found
     427             :   ///   - This [VPath.pathParameters] if [VRouteElement.extendedPath] is absolute
     428             :   ///   - This [VPath.pathParameters] and the parent pathParameters if  [VRouteElement.extendedPath] is relative
     429             :   final Map<String, String> pathParameters;
     430             : 
     431             :   /// The local path is the one of the current VRouteElement
     432             :   /// If the path has path parameters, those should be replaced
     433             :   final String? localPath;
     434             : 
     435          12 :   ValidVPathMatch({
     436             :     required this.remainingPath,
     437             :     required this.pathParameters,
     438             :     required this.localPath,
     439             :   });
     440             : }
     441             : 
     442             : class InvalidVPathMatch extends VPathMatch implements Error {
     443             :   /// If there is no pathMatch but a VRouteElement needs a ValueKey
     444             :   /// use a constant path (which the user is likely to pop on)
     445             :   final String? localPath;
     446             : 
     447          12 :   InvalidVPathMatch({required this.localPath});
     448             : 
     449           0 :   @override
     450           0 :   StackTrace? get stackTrace => StackTrace.current;
     451             : }

Generated by: LCOV version 1.14