Skip to content

App Flow | Routing

App Flow leverages AutoRoute to manage application navigation. By leveraging declarative route definitions and automated code generation, AutoRoute minimizes manual work while providing a clean and scalable routing structure.

Additionally, state management is integrated using Riverpod, enabling shared application states, such as authentication, to be easily accessed within the routing logic.

Routing Structure

The routing architecture uses a centralized AppRouter class to define and manage all application routes, defined in app_router.dart.

Integrated with Riverpod, the AppRouter is exposed as a provider, enabling access via dependency injection throughout the app.

    final AppRouter appRouter = ref.read(appRouterProvider);
    appRouter.navigate(const HomeRoute());

Route Overview

App Flow provides a default routing structure, designed to be straightforward and easily extendable.

To add new routes, extend the routes list within the AppRouter class by defining additional AutoRoute objects. Each route specifies the page it maps to, its path, and optional guards or configurations.

Route Details

The following table outlines the current routes, their paths, access levels, and applied guards:

Route Path Access Guard
Auth Page /auth Public (Initial) None
Home Page /home Authenticated AuthGuard

Implementation

The configuration corresponding to the table is shown below:

app_router.dart
  @override
  List<AutoRoute> get routes => [
        AutoRoute(
          page: AuthPageRoute.page,
          path: '/auth',
        ),
        AutoRoute(
          page: HomeRoute.page,
          path: '/home',
        ),
      ];
}

Initial Route

The application starts at the route marked as initial, which serves as the entry point for the application.

app_router.dart
  @override
  List<AutoRoute> get routes => [
        AutoRoute(
          page: AuthPageRoute.page,
          path: '/auth',
          initial: true,
        ),
        AutoRoute(
          page: HomeRoute.page,
          path: '/home',
        ),
      ];
}

Protected Routes

Routes with a gaurds property defined are accessible only after the guard's logic approves the navigation. For example in the case below, the /home is guarded by AuthGaurd. Unauthorized users are redirected to the /auth page to log in or sign up.

app_router.dart
  @override
  List<AutoRoute> get routes => [
        AutoRoute(
          page: AuthPageRoute.page,
          path: '/auth',
          initial: true,
        ),
        AutoRoute(
          page: HomeRoute.page,
          path: '/home',
          guards: [AuthGuard(ref)],
        ),
      ];
}

Route Guards

Route guards in App Flow are implemented using the AutoRouteGuard class to secure specific paths and dynamically control navigation. They act as gatekeepers, ensuring that users meet defined conditions (e.g., authentication) before accessing certain routes.

To create a custom guard, extend the AutoRouteGuard class and define the necessary logic to enforce access control. This approach provides flexibility and allows for implementing route-specific navigation rules as needed.

Authentication Guard

App Flow includes a default AutoRouteGuard implementation: AuthGaurd, a straightforward class designed to enforce secure access for authenticated users.

app_router.dart
class AuthGuard extends AutoRouteGuard {
  final ProviderRef ref;

  AuthGuard(this.ref);

  @override
  Future<void> onNavigation(resolver, router) async {
    // Use the `authServiceProvider` to verify the user's login state.
    final isLoggedIn = ref.read(authServiceProvider).isLoggedIn(); // (1)

    if (isLoggedIn) {
      // Allows authenticated users to proceed to the requested destination.
      resolver.next(true);
    } else {
      // Redirect unauthorized users to the /auth route.
      await router.replaceAll([const AuthPageRoute()]);
    }
  }
}