Line data Source code
1 : import 'package:flutter/widgets.dart'; 2 : import 'package:get/src/routes/get_route.dart'; 3 : 4 : class GetPageMatch { 5 1 : GetPageMatch(this.route); 6 : 7 : GetPage route; 8 : Map<String, String> parameters = <String, String>{}; 9 : } 10 : 11 : class ParseRouteTree { 12 : final List<ParseRouteTreeNode> _nodes = <ParseRouteTreeNode>[]; 13 : bool _hasDefaultRoute = false; 14 : 15 1 : void addRoute(GetPage route) { 16 1 : String path = route.name; 17 : 18 1 : if (path == Navigator.defaultRouteName) { 19 1 : if (_hasDefaultRoute) { 20 : throw ("Default route was already defined"); 21 : } 22 1 : var node = ParseRouteTreeNode(path, ParseRouteTreeNodeType.component); 23 2 : node.routes = [route]; 24 2 : _nodes.add(node); 25 1 : _hasDefaultRoute = true; 26 : return; 27 : } 28 1 : if (path.startsWith("/")) { 29 1 : path = path.substring(1); 30 : } 31 1 : List<String> pathComponents = path.split('/'); 32 : ParseRouteTreeNode parent; 33 3 : for (int i = 0; i < pathComponents.length; i++) { 34 1 : String component = pathComponents[i]; 35 1 : ParseRouteTreeNode node = _nodeForComponent(component, parent); 36 : if (node == null) { 37 1 : ParseRouteTreeNodeType type = _typeForComponent(component); 38 1 : node = ParseRouteTreeNode(component, type); 39 1 : node.parent = parent; 40 : if (parent == null) { 41 2 : _nodes.add(node); 42 : } else { 43 0 : parent.nodes.add(node); 44 : } 45 : } 46 3 : if (i == pathComponents.length - 1) { 47 1 : if (node.routes == null) { 48 0 : node.routes = [route]; 49 : } else { 50 2 : node.routes.add(route); 51 : } 52 : } 53 : parent = node; 54 : } 55 : } 56 : 57 1 : GetPageMatch matchRoute(String path) { 58 : String usePath = path; 59 1 : if (usePath.startsWith("/")) { 60 1 : usePath = path.substring(1); 61 : } 62 1 : List<String> components = usePath.split("/"); 63 1 : if (path == Navigator.defaultRouteName) { 64 0 : components = ["/"]; 65 : } 66 : 67 : Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> nodeMatches = 68 1 : <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{}; 69 1 : List<ParseRouteTreeNode> nodesToCheck = _nodes; 70 2 : for (String checkComponent in components) { 71 : Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> currentMatches = 72 1 : <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{}; 73 1 : List<ParseRouteTreeNode> nextNodes = <ParseRouteTreeNode>[]; 74 2 : for (ParseRouteTreeNode node in nodesToCheck) { 75 : String pathPart = checkComponent; 76 1 : Map<String, String> queryMap = {}; 77 : 78 1 : if (checkComponent.contains("?") && !checkComponent.contains("=")) { 79 0 : var splitParam = checkComponent.split("?"); 80 0 : pathPart = splitParam[0]; 81 0 : queryMap = {pathPart: splitParam[1]}; 82 1 : } else if (checkComponent.contains("?")) { 83 0 : var splitParam = checkComponent.split("?"); 84 0 : var splitParam2 = splitParam[1].split("="); 85 0 : if (!splitParam2[1].contains("&")) { 86 0 : pathPart = splitParam[0]; 87 0 : queryMap = {splitParam2[0]: splitParam2[1]}; 88 : } else { 89 0 : pathPart = splitParam[0]; 90 0 : final segunda = splitParam[1]; 91 0 : var other = segunda.split(RegExp(r"[&,=]")); 92 0 : for (var i = 0; i < (other.length - 1); i++) { 93 0 : bool impar = (i % 2 == 0); 94 : if (impar) { 95 0 : queryMap.addAll({other[0 + i]: other[1 + i]}); 96 : } 97 : } 98 : } 99 : } 100 : 101 3 : bool isMatch = (node.part == pathPart || node.isParameter()); 102 : if (isMatch) { 103 2 : ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent]; 104 : ParseRouteTreeNodeMatch match = 105 1 : ParseRouteTreeNodeMatch.fromMatch(parentMatch, node); 106 1 : if (node.isParameter()) { 107 0 : String paramKey = node.part.substring(1); 108 0 : match.parameters[paramKey] = pathPart; 109 : } 110 : if (queryMap != null) { 111 2 : match.parameters.addAll(queryMap); 112 : } 113 : 114 1 : currentMatches[node] = match; 115 1 : if (node.nodes != null) { 116 2 : nextNodes.addAll(node.nodes); 117 : } 118 : } 119 : } 120 : nodeMatches = currentMatches; 121 : nodesToCheck = nextNodes; 122 3 : if (currentMatches.values.length == 0) { 123 : return null; 124 : } 125 : } 126 2 : List<ParseRouteTreeNodeMatch> matches = nodeMatches.values.toList(); 127 2 : if (matches.length > 0) { 128 1 : ParseRouteTreeNodeMatch match = matches.first; 129 1 : ParseRouteTreeNode nodeToUse = match.node; 130 : 131 : if (nodeToUse != null && 132 1 : nodeToUse.routes != null && 133 3 : nodeToUse.routes.length > 0) { 134 1 : List<GetPage> routes = nodeToUse.routes; 135 2 : GetPageMatch routeMatch = GetPageMatch(routes[0]); 136 : 137 2 : routeMatch.parameters = match.parameters; 138 : 139 : return routeMatch; 140 : } 141 : } 142 : return null; 143 : } 144 : 145 1 : ParseRouteTreeNode _nodeForComponent( 146 : String component, ParseRouteTreeNode parent) { 147 1 : List<ParseRouteTreeNode> nodes = _nodes; 148 : if (parent != null) { 149 0 : nodes = parent.nodes; 150 : } 151 2 : for (ParseRouteTreeNode node in nodes) { 152 2 : if (node.part == component) { 153 : return node; 154 : } 155 : } 156 : return null; 157 : } 158 : 159 1 : ParseRouteTreeNodeType _typeForComponent(String component) { 160 : ParseRouteTreeNodeType type = ParseRouteTreeNodeType.component; 161 1 : if (_isParameterComponent(component)) { 162 : type = ParseRouteTreeNodeType.parameter; 163 : } 164 : return type; 165 : } 166 : 167 1 : bool _isParameterComponent(String component) { 168 1 : return component.startsWith(":"); 169 : } 170 : 171 0 : Map<String, String> parseQueryString(String query) { 172 0 : var search = RegExp('([^&=]+)=?([^&]*)'); 173 0 : var params = Map<String, String>(); 174 0 : if (query.startsWith('?')) query = query.substring(1); 175 0 : decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' ')); 176 0 : for (Match match in search.allMatches(query)) { 177 0 : String key = decode(match.group(1)); 178 0 : String value = decode(match.group(2)); 179 0 : params[key] = value; 180 : } 181 : return params; 182 : } 183 : } 184 : 185 : class ParseRouteTreeNodeMatch { 186 0 : ParseRouteTreeNodeMatch(this.node); 187 : 188 1 : ParseRouteTreeNodeMatch.fromMatch(ParseRouteTreeNodeMatch match, this.node) { 189 2 : parameters = <String, String>{}; 190 : if (match != null) { 191 0 : parameters.addAll(match.parameters); 192 : } 193 : } 194 : 195 : ParseRouteTreeNode node; 196 : Map<String, String> parameters = <String, String>{}; 197 : } 198 : 199 : class ParseRouteTreeNode { 200 1 : ParseRouteTreeNode(this.part, this.type); 201 : 202 : String part; 203 : ParseRouteTreeNodeType type; 204 : List<GetPage> routes = <GetPage>[]; 205 : List<ParseRouteTreeNode> nodes = <ParseRouteTreeNode>[]; 206 : ParseRouteTreeNode parent; 207 : 208 1 : bool isParameter() { 209 2 : return type == ParseRouteTreeNodeType.parameter; 210 : } 211 : } 212 : 213 12 : enum ParseRouteTreeNodeType { 214 12 : component, 215 12 : parameter, 216 : }