Skip to content

Instantly share code, notes, and snippets.

@lukepighetti
Last active March 27, 2021 00:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukepighetti/85285136eacf1558761b98a9bb8c2c93 to your computer and use it in GitHub Desktop.
Save lukepighetti/85285136eacf1558761b98a9bb8c2c93 to your computer and use it in GitHub Desktop.
Simple route generator that exposes arguments and query params to route builders
main() {
BuildContext context;
final router = NavigationService(context);
return MaterialApp(
onGenerateRoute: (settings) => router.handleGenerateRoute(
settings,
routes: {
'/': (params, context) => HomeView(),
/// You can get here with a few methods
///
/// 1) Navigator.of(context).push('/inbox')
/// 2) Navigator.of(context.push('/inbox?thread_id=foo'))
/// 3) Navigator.of(context.push('/inbox', arguments: {'thread_id': 'foo'}))
///
/// 4) router.to('/inbox')
/// 5) router.to('/inbox?thread_id=foo')
/// 6) router.to('/inbox', {'thread_id': 'foo'})
'/inbox': (params, context) {
final threadId = params['thread_id'];
if (threadId != null)
return InboxView(threadId: threadId);
else
return InboxView();
}
},
),
);
}
class NavigationService {
/// An opinionated navigation service that exposes methods for simple navigation
/// on web/desktop.
NavigationService(this.context);
/// The context used to get [Navigator] from [MaterialApp]
final BuildContext context;
/// Navigate to a path on web/desktop with optional string arguments
Future<T> to<T>(String path, {Map<String, String> arguments}) {
return Navigator.of(context)
.pushReplacementNamed(path, arguments: arguments);
}
/// Connect this to [MaterialApp.onGenerateRoute] along with a fallback route
/// string and a list of routes.
///
/// Will parse query params, ie `/inbox?foo=42` and pass `{"foo":"42"}` to
/// `/inbox` route. Will also merge [RouteSettings.arguments] if they are of
/// the type `Map<String, String>`
Route<dynamic> handleGenerateRoute(
RouteSettings settings, {
String fallbackRoute = '/',
@required Map<String, RouteBuilder> routes,
}) {
/// Parse the route to extract query params
final uri = Uri.tryParse(settings.name);
/// Build params from query params and route arguments
final params = <String, String>{
/// Path parameters
...uri.queryParameters,
/// Route arguments if it's a `Map<String, String>`
if (settings.arguments is Map<String, String>)
...settings.arguments as Map<String, String>,
};
final route = uri.path;
/// Get the route, or fallback to the previous route
final builder = routes[route] ?? routes[fallbackRoute];
if (builder == null)
throw StateError(
"Couldn't find route $route or the fallback route $fallbackRoute");
return MaterialPageRoute(
settings: settings,
builder: (context) => builder(params, context),
);
}
}
typedef RouteBuilder = Widget Function(
Map<String, String> params, BuildContext context);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment