pod_router 0.0.1+2 copy "pod_router: ^0.0.1+2" to clipboard
pod_router: ^0.0.1+2 copied to clipboard

A Flutter navigation package that combines go_router with Riverpod for clean, testable routing with authentication support.

pod_router #

A Flutter package that simplifies integration between Go Router and Riverpod state management with authentication handling. This package helps you manage routing based on authentication state and other app conditions, reducing boilerplate and providing a standardized approach.

Pub Version License: MIT

Features #

  • πŸ” Authentication-aware routing - Automatically redirect users based on auth state
  • πŸ”„ State-driven navigation - Route changes respond to Riverpod state changes
  • 🌊 Simplified navigation flow - Handle onboarding, authentication flow, and protected routes
  • πŸ“ Declarative route definition - Define protected and public routes clearly
  • πŸͺ Easy integration - Works with your existing Go Router and Riverpod setup

Installation #

dependencies:
  pod_router : ^0.0.1

Run:

flutter pub get

Quick Start #

import 'package:pod_router/pod_router.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

// 1. Create your auth notifier
class MyAuthNotifier extends BaseAuthNotifier {
  MyAuthNotifier(Ref ref) : super(ref);
  
  @override
  void initialize() {
    // Your auth initialization logic here
  }
  
  Future<void> login() async {
    setLoading();
    // Login implementation
    setAuthenticated();
  }
  
  Future<void> logout() async {
    setLoading();
    // Logout implementation
    setUnauthenticated();
  }
}

// 2. Create the auth provider
final authProvider = createAuthNotifierProvider<MyAuthNotifier>(
  (ref) => MyAuthNotifier(ref)
);

// 3. Define your routes manager
class AppRoutesManager extends RoutesManager {
  AppRoutesManager(Ref ref) : super(ref);
  
  @override
  List<String> get protectedRoutes => ['/profile', '/settings'];
  
  @override
  List<String> get publicRoutes => ['/login', '/register'];
  
  @override
  String get splashRoute => '/splash';
  
  @override
  String get defaultAuthenticatedRoute => '/home';
  
  @override
  String get defaultUnauthenticatedRoute => '/login';
  
  @override
  void initializeListeners() {
    // Connect auth state to router
    ref.listen(
      authProvider.select((value) => value.status),
      (prev, next) {
        authState.value = next;
      },
      fireImmediately: true,
    );
    
    // Connect loading state
    ref.listen(authProvider.select((value) => value.isLoading),
      (prev, next) {
        isLoading.value = next;
      },
      fireImmediately: true,
    );
  }
}

// 4. Create the router provider
final routesProvider = routesManagerProvider<AppRoutesManager>(
  (ref) => AppRoutesManager(ref)
);

// 5. Set up the Go Router
final routerProvider = Provider<GoRouter>((ref) {
  final routesManager = ref.watch(routesProvider);
  
  return GoRouter(
    redirect: routesManager.onRedirect,
    refreshListenable: CombinedListen(routesManager.refreshables),
    routes: [
      // Your routes here
    ],
  );
});

Detailed Usage #

Authentication State Management #

The package provides a BaseAuthNotifier class that handles authentication state. Extend this class to implement your specific authentication logic:

class FirebaseAuthNotifier extends BaseAuthNotifier {
  FirebaseAuthNotifier(Ref ref) : super(ref);
  
  @override
  void initialize() {
    // Listen to Firebase auth changes
    FirebaseAuth.instance.authStateChanges().listen((user) {
      if (user != null) {
        setAuthenticated();
      } else {
        setUnauthenticated();
      }
    });
  }
  
  Future<void> signIn(String email, String password) async {
    setLoading();
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
    } catch (e) {
      setUnauthenticated();
      rethrow;
    }
  }
  
  Future<void> signOut() async {
    setLoading();
    await FirebaseAuth.instance.signOut();
  }
}

Route Management #

The RoutesManager class handles route redirects based on authentication state:

class MyRoutesManager extends RoutesManager {
  MyRoutesManager(Ref ref) : super(ref);
  
  @override
  List<String> get protectedRoutes => [
    '/profile', 
    '/settings',
    '/dashboard'
  ];
  
  @override
  List<String> get publicRoutes => [
    '/login', 
    '/register',
    '/forgot-password'
  ];
  
  @override
  String get splashRoute => '/splash';
  
  @override
  String get defaultAuthenticatedRoute => '/home';
  
  @override
  String get defaultUnauthenticatedRoute => '/login';
  
  @override
  String? get initialAppFlowRoute => '/onboarding';
  
  @override
  void initializeListeners() {
    // Listen to auth state
    ref.listen(
      authProvider.select((value) => value.status),
      (prev, next) {
        authState.value = next;
      },
      fireImmediately: true,
    );
    
    // Optional: Listen to onboarding completion
    ref.listen(onboardingCompletedProvider, (prev, next) {
      appFlowNotifier.value = !next;
    });
    
    // Other state listeners...
  }
}

Setting Up Go Router #

Integrate with Go Router using the CombinedListen utility:

final goRouterProvider = Provider<GoRouter>((ref) {
  final routesManager = ref.watch(routesManagerProvider);
  
  return GoRouter(
    debugLogDiagnostics: true,
    redirect: routesManager.onRedirect,
    refreshListenable: CombinedListen(routesManager.refreshables),
    initialLocation: '/splash',
    routes: [
      // Your routes...
    ],
  );
});

Complete Example #

See the example folder for a complete implementation.

Debugging #

Enable debug logs to help troubleshoot routing issues:

void main() {
  PackageLogger.enableDebugLogs = true;
  runApp(ProviderScope(child: MyApp()));
}

Additional Configuration #

Customizing Redirect Logic #

You can override the onRedirect method in your RoutesManager subclass to customize the redirect logic:

@override
FutureOr<String?> onRedirect(BuildContext context, GoRouterState state) async {
  // Custom logic before calling super
  if (specialCondition) {
    return '/special-route';
  }
  
  // Use default logic
  return await super.onRedirect(context, state);
}

Adding Custom State Triggers #

You can add additional ValueNotifier objects to trigger route refreshes:

final themeChanged = ValueNotifier<bool>(false);

@override
List<ChangeNotifier> get refreshables => [
  ...super.refreshables,
  themeChanged,
];

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

4
likes
0
points
0
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter navigation package that combines go_router with Riverpod for clean, testable routing with authentication support.

Topics

#navigation #routing #riverpod #go-router #authentication

License

unknown (license)

Dependencies

equatable, flutter, flutter_riverpod, go_router

More

Packages that depend on pod_router