diff --git a/lib/src/common.dart b/lib/src/common.dart index d47771a..1424ee7 100644 --- a/lib/src/common.dart +++ b/lib/src/common.dart @@ -9,6 +9,6 @@ typedef Widget RouteHandler(Map parameters); /// class AppRoute { String route; - RouteCreator routeCreator; - AppRoute(this.route, this.routeCreator); + RouteHandler handler; + AppRoute(this.route, this.handler); } \ No newline at end of file diff --git a/lib/src/router.dart b/lib/src/router.dart index 21c8992..eb566e0 100644 --- a/lib/src/router.dart +++ b/lib/src/router.dart @@ -1,67 +1,80 @@ part of router; +enum TransitionType { + native, + nativeModal, +} + class Router { /// The tree structure that stores the defined routes RouteTree _routeTree = new RouteTree(); /// Generic handler for when a route has not been defined - AppRoute notFoundRoute; - - /// Creates a custom [Route] definition - void defineRoute(String routePath, {@required RouteCreator creator}) { - _routeTree.addRoute(new AppRoute(routePath, creator)); - } + RouteHandler notFoundHandler; /// Creates a [PageRoute] definition for the passed [RouteHandler]. You can optionally provide a custom /// transition builder for the route. - void defineRouteHandler(String routePath, {@required RouteHandler handler, RouteTransitionsBuilder transitionsBuilder, - Duration duration = const Duration(milliseconds: 250)}) - { - RouteCreator creator = (RouteSettings routeSettings, Map params) { - return new PageRouteBuilder(settings: routeSettings, transitionDuration: duration, - transitionsBuilder: transitionsBuilder, - pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { - return handler(params); - }); - }; - _routeTree.addRoute(new AppRoute(routePath, creator)); - } - - /// Creates a [MaterialPageRoute] definition - void defineMaterialRoute(String routePath, {@required RouteHandler handler}) { - RouteCreator creator = (RouteSettings routeSettings, Map params) { - return new MaterialPageRoute(settings: routeSettings, builder: (BuildContext context) { - return handler(params); - }); - }; - _routeTree.addRoute(new AppRoute(routePath, creator)); - } - - void addRoute(AppRoute route) { - _routeTree.addRoute(route); + void define(String routePath, {@required RouteHandler handler}) { + _routeTree.addRoute(new AppRoute(routePath, handler)); } + /// Finds a defined [AppRoute] for the path value. If no [AppRoute] definition was found + /// then function will return null. AppRoute match(String path) { AppRouteMatch match = _routeTree.matchRoute(path); - return match?.route ?? notFoundRoute; + return match?.route; } + /// + void navigateTo(BuildContext context, String path, {TransitionType transition = TransitionType.native}) { + Route route; + if (transition == TransitionType.native) { + route = matchRoute(path); + } + if (route == null && notFoundHandler != null) { + route = _notFoundRoute(context, path); + } + if (route != null) { + Navigator.push(context, route); + } else { + print("No registered route was found to handle '$path'."); + } + } + + /// + Route _notFoundRoute(BuildContext context, String path) { + RouteCreator creator = (RouteSettings routeSettings, Map params) { + return new MaterialPageRoute(settings: routeSettings, builder: (BuildContext context) { + return notFoundHandler(params); + }); + }; + return creator(new RouteSettings(name: path), null); + } + + /// Route matchRoute(String path, {RouteSettings routeSettings = null}) { RouteSettings settingsToUse = routeSettings; if (routeSettings == null) { settingsToUse = new RouteSettings(name: path); } AppRouteMatch match = _routeTree.matchRoute(path); - AppRoute route = match?.route ?? notFoundRoute; - if (route == null) { + AppRoute route = match?.route; + if (route == null && notFoundHandler == null) { return null; } + RouteHandler handler = (route != null ? route.handler : notFoundHandler); Map parameters = match?.parameters ?? {}; - return route.routeCreator(settingsToUse, parameters); + RouteCreator creator = (RouteSettings routeSettings, Map params) { + return new MaterialPageRoute(settings: routeSettings, builder: (BuildContext context) { + return handler(params); + }); + }; + return creator(settingsToUse, parameters); } - /// used by the [MaterialApp.onGenerateRoute] function as callback to - /// create a route that is able to be consumed. + /// Route generation method. This function can be used as a way to create routes on-the-fly + /// 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 generator(RouteSettings routeSettings) { return matchRoute(routeSettings.name, routeSettings: routeSettings); } diff --git a/lib/src/tree.dart b/lib/src/tree.dart index 8bac42d..bc24051 100644 --- a/lib/src/tree.dart +++ b/lib/src/tree.dart @@ -120,9 +120,17 @@ class RouteTree { RouteTreeNodeMatch match = new RouteTreeNodeMatch.fromMatch(parentMatch, node); if (node.isParameter()) { String paramKey = node.part.substring(1); - match.parameters[paramKey] = checkComponent; + if (checkComponent.contains("?")) { + var splitParam = checkComponent.split("?"); + var namedParam = splitParam[0]; + var queryParams = parseQueryString(splitParam[1]); + match.parameters[paramKey] = namedParam; + match.parameters.addAll(queryParams); + } else { + match.parameters[paramKey] = checkComponent; + } } -// print("matched: ${node.part}, isParam: ${node.isParameter()}, params: ${match.parameters}"); + print("matched: ${node.part}, isParam: ${node.isParameter()}, params: ${match.parameters}"); currentMatches[node] = match; if (node.nodes != null) { nextNodes.addAll(node.nodes); @@ -194,4 +202,15 @@ class RouteTree { bool _isParameterComponent(String component) { return component.startsWith(":"); } + + Map parseQueryString(String query) { + var search = new RegExp('([^&=]+)=?([^&]*)'); + var params = new Map(); + if (query.startsWith('?')) query = query.substring(1); + decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' ')); + for (Match match in search.allMatches(query)) { + params[decode(match.group(1))] = decode(match.group(2)); + } + return params; + } }