Browse Source

cleanup (#237)

* cleanup class member order and example/pubspec assets order
Luke Pighetti 4 years ago
parent
commit
d326c32482
5 changed files with 222 additions and 131 deletions
  1. 1 1
      README.md
  2. 2 2
      example/pubspec.yaml
  3. 30 10
      lib/src/common.dart
  4. 118 76
      lib/src/fluro_router.dart
  5. 71 42
      lib/src/tree.dart

+ 1 - 1
README.md

@@ -16,7 +16,7 @@ The brightest, hippest, coolest router for Flutter.
 - Querystring parameter parsing
 - Common transitions built-in
 - Simple custom transition creation
-- Follows `beta` Flutter channel
+- Follows `stable` Flutter channel
 - Null-safety
 
 ## Example Project

+ 2 - 2
example/pubspec.yaml

@@ -23,15 +23,15 @@ flutter:
   uses-material-design: true
 
   assets:
-    - assets/images/logo_fluro.png
     - assets/images/acc_boom.png
-    - assets/images/ic_result_hz.png
     - assets/images/ic_function_hz.png
+    - assets/images/ic_result_hz.png
     - assets/images/ic_transform_custom_hz.png
     - assets/images/ic_transform_fade_in_hz.png
     - assets/images/ic_transform_fade_out_hz.png
     - assets/images/ic_transform_global_hz.png
     - assets/images/ic_transform_native_hz.png
+    - assets/images/logo_fluro.png
 
   fonts:
     - family: Lazer84

+ 30 - 10
lib/src/common.dart

@@ -18,30 +18,44 @@ enum HandlerType {
 
 /// The handler to register with [FluroRouter.define]
 class Handler {
-  Handler({this.type = HandlerType.route, required this.handlerFunc});
+  Handler({
+    this.type = HandlerType.route,
+    required this.handlerFunc,
+  });
+
   final HandlerType type;
   final HandlerFunc handlerFunc;
 }
 
 /// A function that creates new routes.
 typedef Route<T> RouteCreator<T>(
-    RouteSettings route, Map<String, List<String>> parameters);
+  RouteSettings route,
+  Map<String, List<String>> parameters,
+);
 
 /// Builds out a screen based on string path [parameters] and context.
 ///
 /// Note: you can access [RouteSettings] with the [context.settings] extension
 typedef Widget? HandlerFunc(
-    BuildContext? context, Map<String, List<String>> parameters);
+  BuildContext? context,
+  Map<String, List<String>> parameters,
+);
 
 /// A route that is added to the router tree.
 class AppRoute {
+  AppRoute(
+    this.route,
+    this.handler, {
+    this.transitionType,
+    this.transitionDuration,
+    this.transitionBuilder,
+  });
+
   String route;
   dynamic handler;
   TransitionType? transitionType;
   Duration? transitionDuration;
   RouteTransitionsBuilder? transitionBuilder;
-  AppRoute(this.route, this.handler,
-      {this.transitionType, this.transitionDuration, this.transitionBuilder});
 }
 
 /// The type of transition to use when pushing/popping a route.
@@ -72,10 +86,12 @@ enum RouteMatchType {
 
 /// The route that was matched.
 class RouteMatch {
-  RouteMatch(
-      {this.matchType = RouteMatchType.noMatch,
-      this.route,
-      this.errorMessage = "Unable to match route. Please check the logs."});
+  RouteMatch({
+    this.matchType = RouteMatchType.noMatch,
+    this.route,
+    this.errorMessage = "Unable to match route. Please check the logs.",
+  });
+
   final Route<dynamic>? route;
   final RouteMatchType matchType;
   final String errorMessage;
@@ -83,9 +99,13 @@ class RouteMatch {
 
 /// When the route is not found.
 class RouteNotFoundException implements Exception {
+  RouteNotFoundException(
+    this.message,
+    this.path,
+  );
+
   final String message;
   final String path;
-  RouteNotFoundException(this.message, this.path);
 
   @override
   String toString() {

+ 118 - 76
lib/src/fluro_router.dart

@@ -29,20 +29,22 @@ class FluroRouter {
   static final appRouter = FluroRouter();
 
   /// The tree structure that stores the defined routes
-  final RouteTree _routeTree = RouteTree();
+  final _routeTree = RouteTree();
 
   /// Generic handler for when a route has not been defined
   Handler? notFoundHandler;
 
   /// The default transition duration to use throughout Fluro
-  static const defaultTransitionDuration = const Duration(milliseconds: 250);
+  static const defaultTransitionDuration = Duration(milliseconds: 250);
 
   /// Creates a [PageRoute] definition for the passed [RouteHandler]. You can optionally provide a default transition type.
-  void define(String routePath,
-      {required Handler? handler,
-      TransitionType? transitionType,
-      Duration transitionDuration = defaultTransitionDuration,
-      RouteTransitionsBuilder? transitionBuilder}) {
+  void define(
+    String routePath, {
+    required Handler? handler,
+    TransitionType? transitionType,
+    Duration transitionDuration = defaultTransitionDuration,
+    RouteTransitionsBuilder? transitionBuilder,
+  }) {
     _routeTree.addRoute(
       AppRoute(routePath, handler,
           transitionType: transitionType,
@@ -62,30 +64,39 @@ class FluroRouter {
       Navigator.of(context).pop(result);
 
   /// Similar to [Navigator.push] but with a few extra features.
-  Future navigateTo(BuildContext context, String path,
-      {bool replace = false,
-      bool clearStack = false,
-      bool maintainState = true,
-      bool rootNavigator = false,
-      TransitionType? transition,
-      Duration? transitionDuration,
-      RouteTransitionsBuilder? transitionBuilder,
-      RouteSettings? routeSettings}) {
-    RouteMatch routeMatch = matchRoute(context, path,
-        transitionType: transition,
-        transitionsBuilder: transitionBuilder,
-        transitionDuration: transitionDuration,
-        maintainState: maintainState,
-        routeSettings: routeSettings);
+  Future navigateTo(
+    BuildContext context,
+    String path, {
+    bool replace = false,
+    bool clearStack = false,
+    bool maintainState = true,
+    bool rootNavigator = false,
+    TransitionType? transition,
+    Duration? transitionDuration,
+    RouteTransitionsBuilder? transitionBuilder,
+    RouteSettings? routeSettings,
+  }) {
+    RouteMatch routeMatch = matchRoute(
+      context,
+      path,
+      transitionType: transition,
+      transitionsBuilder: transitionBuilder,
+      transitionDuration: transitionDuration,
+      maintainState: maintainState,
+      routeSettings: routeSettings,
+    );
+
     Route<dynamic>? route = routeMatch.route;
     Completer completer = Completer();
     Future future = completer.future;
+
     if (routeMatch.matchType == RouteMatchType.nonVisual) {
       completer.complete("Non visual route type.");
     } else {
       if (route == null && notFoundHandler != null) {
         route = _notFoundRoute(context, path, maintainState: maintainState);
       }
+
       if (route != null) {
         final navigator = Navigator.of(context, rootNavigator: rootNavigator);
         if (clearStack) {
@@ -106,33 +117,44 @@ class FluroRouter {
     return future;
   }
 
-  Route<Null> _notFoundRoute(BuildContext context, String path,
-      {bool? maintainState}) {
-    RouteCreator<Null> creator =
-        (RouteSettings? routeSettings, Map<String, List<String>> parameters) {
+  Route<Null> _notFoundRoute(
+    BuildContext context,
+    String path, {
+    bool? maintainState,
+  }) {
+    RouteCreator<Null> creator = (
+      RouteSettings? routeSettings,
+      Map<String, List<String>> parameters,
+    ) {
       return MaterialPageRoute<Null>(
-          settings: routeSettings,
-          maintainState: maintainState ?? true,
-          builder: (BuildContext context) {
-            return notFoundHandler?.handlerFunc(context, parameters) ??
-                SizedBox.shrink();
-          });
+        settings: routeSettings,
+        maintainState: maintainState ?? true,
+        builder: (BuildContext context) {
+          return notFoundHandler?.handlerFunc(context, parameters) ??
+              SizedBox.shrink();
+        },
+      );
     };
+
     return creator(RouteSettings(name: path), {});
   }
 
   /// Attempt to match a route to the provided [path].
-  RouteMatch matchRoute(BuildContext? buildContext, String? path,
-      {RouteSettings? routeSettings,
-      TransitionType? transitionType,
-      Duration? transitionDuration,
-      RouteTransitionsBuilder? transitionsBuilder,
-      bool maintainState = true}) {
+  RouteMatch matchRoute(
+    BuildContext? buildContext,
+    String? path, {
+    RouteSettings? routeSettings,
+    TransitionType? transitionType,
+    Duration? transitionDuration,
+    RouteTransitionsBuilder? transitionsBuilder,
+    bool maintainState = true,
+  }) {
     RouteSettings settingsToUse = routeSettings ?? RouteSettings(name: path);
 
     if (settingsToUse.name == null) {
       settingsToUse = settingsToUse.copyWith(name: path);
     }
+
     AppRouteMatch? match = _routeTree.matchRoute(path!);
     AppRoute? route = match?.route;
 
@@ -142,56 +164,66 @@ class FluroRouter {
 
     Handler handler = (route != null ? route.handler : notFoundHandler);
     TransitionType? transition = transitionType;
+
     if (transitionType == null) {
       transition = route != null ? route.transitionType : TransitionType.native;
     }
+
     if (route == null && notFoundHandler == null) {
       return RouteMatch(
-          matchType: RouteMatchType.noMatch,
-          errorMessage: "No matching route was found");
+        matchType: RouteMatchType.noMatch,
+        errorMessage: "No matching route was found",
+      );
     }
-    Map<String, List<String>> parameters =
-        match?.parameters ?? <String, List<String>>{};
+
+    final parameters = match?.parameters ?? <String, List<String>>{};
+
     if (handler.type == HandlerType.function) {
       handler.handlerFunc(buildContext, parameters);
       return RouteMatch(matchType: RouteMatchType.nonVisual);
     }
 
-    RouteCreator creator =
-        (RouteSettings? routeSettings, Map<String, List<String>> parameters) {
+    RouteCreator creator = (
+      RouteSettings? routeSettings,
+      Map<String, List<String>> parameters,
+    ) {
       bool isNativeTransition = (transition == TransitionType.native ||
           transition == TransitionType.nativeModal);
+
       if (isNativeTransition) {
         return MaterialPageRoute<dynamic>(
-            settings: routeSettings,
-            fullscreenDialog: transition == TransitionType.nativeModal,
-            maintainState: maintainState,
-            builder: (BuildContext context) {
-              return handler.handlerFunc(context, parameters) ??
-                  SizedBox.shrink();
-            });
+          settings: routeSettings,
+          fullscreenDialog: transition == TransitionType.nativeModal,
+          maintainState: maintainState,
+          builder: (BuildContext context) {
+            return handler.handlerFunc(context, parameters) ??
+                SizedBox.shrink();
+          },
+        );
       } else if (transition == TransitionType.material ||
           transition == TransitionType.materialFullScreenDialog) {
         return MaterialPageRoute<dynamic>(
-            settings: routeSettings,
-            fullscreenDialog:
-                transition == TransitionType.materialFullScreenDialog,
-            maintainState: maintainState,
-            builder: (BuildContext context) {
-              return handler.handlerFunc(context, parameters) ??
-                  SizedBox.shrink();
-            });
+          settings: routeSettings,
+          fullscreenDialog:
+              transition == TransitionType.materialFullScreenDialog,
+          maintainState: maintainState,
+          builder: (BuildContext context) {
+            return handler.handlerFunc(context, parameters) ??
+                SizedBox.shrink();
+          },
+        );
       } else if (transition == TransitionType.cupertino ||
           transition == TransitionType.cupertinoFullScreenDialog) {
         return CupertinoPageRoute<dynamic>(
-            settings: routeSettings,
-            fullscreenDialog:
-                transition == TransitionType.cupertinoFullScreenDialog,
-            maintainState: maintainState,
-            builder: (BuildContext context) {
-              return handler.handlerFunc(context, parameters) ??
-                  SizedBox.shrink();
-            });
+          settings: routeSettings,
+          fullscreenDialog:
+              transition == TransitionType.cupertinoFullScreenDialog,
+          maintainState: maintainState,
+          builder: (BuildContext context) {
+            return handler.handlerFunc(context, parameters) ??
+                SizedBox.shrink();
+          },
+        );
       } else {
         RouteTransitionsBuilder? routeTransitionsBuilder;
 
@@ -226,6 +258,7 @@ class FluroRouter {
         );
       }
     };
+
     return RouteMatch(
       matchType: RouteMatchType.visual,
       route: creator(settingsToUse, parameters),
@@ -234,17 +267,22 @@ class FluroRouter {
 
   RouteTransitionsBuilder _standardTransitionsBuilder(
       TransitionType? transitionType) {
-    return (BuildContext context, Animation<double> animation,
-        Animation<double> secondaryAnimation, Widget child) {
+    return (
+      BuildContext context,
+      Animation<double> animation,
+      Animation<double> secondaryAnimation,
+      Widget child,
+    ) {
       if (transitionType == TransitionType.fadeIn) {
         return FadeTransition(opacity: animation, child: child);
       } else {
-        const Offset topLeft = const Offset(0.0, 0.0);
-        const Offset topRight = const Offset(1.0, 0.0);
-        const Offset bottomLeft = const Offset(0.0, 1.0);
+        const topLeft = const Offset(0.0, 0.0);
+        const topRight = const Offset(1.0, 0.0);
+        const bottomLeft = const Offset(0.0, 1.0);
+
+        var startOffset = bottomLeft;
+        var endOffset = topLeft;
 
-        Offset startOffset = bottomLeft;
-        Offset endOffset = topLeft;
         if (transitionType == TransitionType.inFromLeft) {
           startOffset = const Offset(-1.0, 0.0);
           endOffset = topLeft;
@@ -274,8 +312,12 @@ class FluroRouter {
   /// if any defined handler is found. It can also be used with the [MaterialApp.onGenerateRoute]
   /// property as callback to create routes that can be used with the [Navigator] class.
   Route<dynamic>? generator(RouteSettings routeSettings) {
-    RouteMatch match =
-        matchRoute(null, routeSettings.name, routeSettings: routeSettings);
+    RouteMatch match = matchRoute(
+      null,
+      routeSettings.name,
+      routeSettings: routeSettings,
+    );
+
     return match.route;
   }
 

+ 71 - 42
lib/src/tree.dart

@@ -18,43 +18,40 @@ enum RouteTreeNodeType {
 
 /// A matched [AppRoute]
 class AppRouteMatch {
-  // constructors
   AppRouteMatch(this.route);
 
-  // properties
   AppRoute route;
   Map<String, List<String>> parameters = <String, List<String>>{};
 }
 
 /// A matched [RouteTreeNode]
 class RouteTreeNodeMatch {
-  // constructors
   RouteTreeNodeMatch(this.node);
 
+  RouteTreeNode node;
+
+  var parameters = <String, List<String>>{};
+
   RouteTreeNodeMatch.fromMatch(RouteTreeNodeMatch? match, this.node) {
     parameters = <String, List<String>>{};
     if (match != null) {
       parameters.addAll(match.parameters);
     }
   }
-
-  // properties
-  RouteTreeNode node;
-  Map<String, List<String>> parameters = <String, List<String>>{};
 }
 
 /// A node on [RouteTree]
 class RouteTreeNode {
-  // constructors
   RouteTreeNode(this.part, this.type);
 
-  // properties
   String part;
   RouteTreeNodeType? type;
-  List<AppRoute> routes = <AppRoute>[];
-  List<RouteTreeNode> nodes = <RouteTreeNode>[];
+
   RouteTreeNode? parent;
 
+  var routes = <AppRoute>[];
+  var nodes = <RouteTreeNode>[];
+
   bool isParameter() {
     return type == RouteTreeNodeType.parameter;
   }
@@ -62,11 +59,10 @@ class RouteTreeNode {
 
 /// A [RouteTree]
 class RouteTree {
-  // private
   final List<RouteTreeNode> _nodes = <RouteTreeNode>[];
   bool _hasDefaultRoute = false;
 
-  // addRoute - add a route to the route tree
+  /// Add a route to the route tree
   void addRoute(AppRoute route) {
     String path = route.route;
     // is root/default route, just add it
@@ -76,69 +72,83 @@ class RouteTree {
         // could be affected
         throw ("Default route was already defined");
       }
+
       var node = RouteTreeNode(path, RouteTreeNodeType.component);
       node.routes = [route];
       _nodes.add(node);
       _hasDefaultRoute = true;
       return;
     }
+
     if (path.startsWith("/")) {
       path = path.substring(1);
     }
-    List<String> pathComponents = path.split('/');
+
+    final pathComponents = path.split('/');
+
     RouteTreeNode? parent;
+
     for (int i = 0; i < pathComponents.length; i++) {
       String? component = pathComponents[i];
       RouteTreeNode? node = _nodeForComponent(component, parent);
+
       if (node == null) {
         RouteTreeNodeType type = _typeForComponent(component);
         node = RouteTreeNode(component, type);
         node.parent = parent;
+
         if (parent == null) {
           _nodes.add(node);
         } else {
           parent.nodes.add(node);
         }
       }
+
       if (i == pathComponents.length - 1) {
         node.routes.add(route);
       }
+
       parent = node;
     }
   }
 
   AppRouteMatch? matchRoute(String path) {
-    String usePath = path;
+    var usePath = path;
+
     if (usePath.startsWith("/")) {
       usePath = path.substring(1);
     }
-    List<String> components = usePath.split("/");
+
+    var components = usePath.split("/");
+
     if (path == Navigator.defaultRouteName) {
       components = ["/"];
     }
 
-    Map<RouteTreeNode, RouteTreeNodeMatch> nodeMatches =
-        <RouteTreeNode, RouteTreeNodeMatch>{};
-    List<RouteTreeNode> nodesToCheck = _nodes;
-    for (String checkComponent in components) {
-      Map<RouteTreeNode, RouteTreeNodeMatch> currentMatches =
-          <RouteTreeNode, RouteTreeNodeMatch>{};
-      List<RouteTreeNode> nextNodes = <RouteTreeNode>[];
-      String pathPart = checkComponent;
+    var nodeMatches = <RouteTreeNode, RouteTreeNodeMatch>{};
+    var nodesToCheck = _nodes;
+
+    for (final checkComponent in components) {
+      final currentMatches = <RouteTreeNode, RouteTreeNodeMatch>{};
+      final nextNodes = <RouteTreeNode>[];
+
+      var pathPart = checkComponent;
       Map<String, List<String>>? queryMap;
+
       if (checkComponent.contains("?")) {
         var splitParam = checkComponent.split("?");
         pathPart = splitParam[0];
         queryMap = parseQueryString(splitParam[1]);
       }
-      for (RouteTreeNode node in nodesToCheck) {
-        bool isMatch = (node.part == pathPart || node.isParameter());
+
+      for (final node in nodesToCheck) {
+        final isMatch = (node.part == pathPart || node.isParameter());
+
         if (isMatch) {
           RouteTreeNodeMatch? parentMatch = nodeMatches[node.parent];
-          RouteTreeNodeMatch match =
-              RouteTreeNodeMatch.fromMatch(parentMatch, node);
+          final match = RouteTreeNodeMatch.fromMatch(parentMatch, node);
           if (node.isParameter()) {
-            String paramKey = node.part.substring(1);
+            final paramKey = node.part.substring(1);
             match.parameters[paramKey] = [pathPart];
           }
           if (queryMap != null) {
@@ -148,23 +158,29 @@ class RouteTree {
           nextNodes.addAll(node.nodes);
         }
       }
+
       nodeMatches = currentMatches;
       nodesToCheck = nextNodes;
+
       if (currentMatches.values.length == 0) {
         return null;
       }
     }
-    List<RouteTreeNodeMatch> matches = nodeMatches.values.toList();
+
+    final matches = nodeMatches.values.toList();
+
     if (matches.isNotEmpty) {
-      RouteTreeNodeMatch match = matches.first;
-      RouteTreeNode? nodeToUse = match.node;
+      final match = matches.first;
+      final nodeToUse = match.node;
       final routes = nodeToUse.routes;
+
       if (routes.isNotEmpty) {
-        AppRouteMatch routeMatch = AppRouteMatch(routes[0]);
+        final routeMatch = AppRouteMatch(routes[0]);
         routeMatch.parameters = match.parameters;
         return routeMatch;
       }
     }
+
     return null;
   }
 
@@ -173,13 +189,17 @@ class RouteTree {
   }
 
   void _printSubTree({RouteTreeNode? parent, int level = 0}) {
-    List<RouteTreeNode> nodes = parent != null ? parent.nodes : _nodes;
-    for (RouteTreeNode node in nodes) {
-      String indent = "";
-      for (int i = 0; i < level; i++) {
+    final nodes = parent != null ? parent.nodes : _nodes;
+
+    for (final node in nodes) {
+      var indent = "";
+
+      for (var i = 0; i < level; i++) {
         indent += "    ";
       }
+
       print("$indent${node.part}: total routes=${node.routes.length}");
+
       if (node.nodes.isNotEmpty) {
         _printSubTree(parent: node, level: level + 1);
       }
@@ -187,24 +207,29 @@ class RouteTree {
   }
 
   RouteTreeNode? _nodeForComponent(String component, RouteTreeNode? parent) {
-    List<RouteTreeNode> nodes = _nodes;
+    var nodes = _nodes;
+
     if (parent != null) {
       // search parent for sub-node matches
       nodes = parent.nodes;
     }
-    for (RouteTreeNode node in nodes) {
+
+    for (final node in nodes) {
       if (node.part == component) {
         return node;
       }
     }
+
     return null;
   }
 
   RouteTreeNodeType _typeForComponent(String component) {
-    RouteTreeNodeType type = RouteTreeNodeType.component;
+    var type = RouteTreeNodeType.component;
+
     if (_isParameterComponent(component)) {
       type = RouteTreeNodeType.parameter;
     }
+
     return type;
   }
 
@@ -216,11 +241,14 @@ class RouteTree {
   Map<String, List<String>> parseQueryString(String query) {
     final search = RegExp('([^&=]+)=?([^&]*)');
     final params = Map<String, List<String>>();
+
     if (query.startsWith('?')) query = query.substring(1);
+
     decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' '));
+
     for (Match match in search.allMatches(query)) {
-      String key = decode(match.group(1)!);
-      String value = decode(match.group(2)!);
+      final key = decode(match.group(1)!);
+      final value = decode(match.group(2)!);
 
       if (params.containsKey(key)) {
         params[key]!.add(value);
@@ -228,6 +256,7 @@ class RouteTree {
         params[key] = [value];
       }
     }
+
     return params;
   }
 }