Created
December 31, 2025 18:17
-
-
Save definev/359de9afe5320989b4c2fd02c9e70e59 to your computer and use it in GitHub Desktop.
How to use redirect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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