Skip to content

Instantly share code, notes, and snippets.

@definev
Created December 31, 2025 18:17
Show Gist options
  • Select an option

  • Save definev/359de9afe5320989b4c2fd02c9e70e59 to your computer and use it in GitHub Desktop.

Select an option

Save definev/359de9afe5320989b4c2fd02c9e70e59 to your computer and use it in GitHub Desktop.
How to use redirect
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:zenrouter/zenrouter.dart';
final authState = ValueNotifier(true);
abstract class AppRoute extends RouteTarget with RouteUnique {}
typedef RedirectFunction =
Future<AppRoute?> Function(AppCoordinator coordinator);
extension RedirectExtension on RouteRedirect<AppRoute> {
Future<AppRoute?> combineRedirect(
AppCoordinator coordinator,
List<RedirectFunction> redirects,
) async {
for (final redirect in redirects) {
final route = await redirect(coordinator);
if (route != null) return route;
}
return this as AppRoute;
}
}
RedirectFunction requireLogin({AppRoute? redirectRoute}) =>
(coordinator) async {
if (authState.value == false) {
return AuthRoute(redirectRoute: redirectRoute);
}
return null;
};
RedirectFunction alreadyLoggedIn({AppRoute? redirectRoute}) =>
(coordinator) async {
if (authState.value == true) return redirectRoute ?? HomeRoute();
return null;
};
mixin RequireAuth on RouteRedirect<AppRoute> {
@override
FutureOr<AppRoute?> redirectWith(AppCoordinator coordinator) =>
combineRedirect(coordinator, [
requireLogin(redirectRoute: this as AppRoute),
]);
}
mixin AlreadyLoggedIn on RouteRedirect<AppRoute> {
AppRoute? get redirectRoute;
@override
FutureOr<AppRoute?> redirectWith(AppCoordinator coordinator) =>
combineRedirect(coordinator, [
alreadyLoggedIn(redirectRoute: redirectRoute),
]);
}
class HomeRoute extends AppRoute with RouteRedirect<AppRoute>, RequireAuth {
@override
Uri toUri() => Uri.parse('/');
@override
Widget build(AppCoordinator coordinator, BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
ElevatedButton(
onPressed: () {
coordinator.push(SettingsRoute());
},
child: Text('Go to Settings'),
),
ElevatedButton(
onPressed: () {
authState.value = false;
coordinator.replace(AuthRoute());
},
child: Text('Sign out'),
),
],
),
),
);
}
}
class OnboardingRoute extends AppRoute
with RouteRedirect<AppRoute>, RequireAuth {
@override
Uri toUri() => Uri.parse('/onboarding');
@override
Widget build(AppCoordinator coordinator, BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Onboarding')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
ElevatedButton(
onPressed: () {
coordinator.replace(HomeRoute());
},
child: Text('Complete onboarding'),
),
],
),
),
);
}
}
class SettingsRoute extends AppRoute with RouteRedirect<AppRoute>, RequireAuth {
@override
Uri toUri() => Uri.parse('/settings');
@override
Widget build(AppCoordinator coordinator, BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Settings')),
body: Center(child: const Text('Settings Page')),
);
}
}
class AuthRoute extends AppRoute with RouteRedirect<AppRoute>, AlreadyLoggedIn {
AuthRoute({this.redirectRoute});
@override
final AppRoute? redirectRoute;
@override
Uri toUri() => Uri.parse('/auth');
@override
Widget build(AppCoordinator coordinator, BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Auth')),
body: Center(
child: ElevatedButton(
onPressed: () {
authState.value = true;
coordinator.replace(HomeRoute());
},
child: Text('Sign in'),
),
),
);
}
}
class AppCoordinator extends Coordinator<AppRoute> {
late final authGroup = NavigationPath<AppRoute>.createWith(
coordinator: this,
label: 'auth',
);
late final nonAuthGroup = NavigationPath<AppRoute>.createWith(
coordinator: this,
label: 'nonAuth',
);
@override
List<StackPath<RouteTarget>> get paths => [
...super.paths,
authGroup,
nonAuthGroup,
];
@override
FutureOr<AppRoute> parseRouteFromUri(Uri uri) {
return switch (uri.pathSegments) {
['auth'] => AuthRoute(),
['settings'] => SettingsRoute(),
['onboarding'] => OnboardingRoute(),
_ => HomeRoute(),
};
}
/// You override this method for custom root layout
@override
Widget layoutBuilder(BuildContext context) {
// return ToastProvider(child: super.layoutBuilder(context));
return super.layoutBuilder(context);
}
}
void main() {
final coordinator = AppCoordinator();
runApp(
MaterialApp.router(
routerDelegate: coordinator.routerDelegate,
routeInformationParser: coordinator.routeInformationParser,
),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment