mirror of
https://github.com/lucavenir/go_router_riverpod.git
synced 2025-08-06 14:59:53 +08:00
62 lines
2.4 KiB
Dart
62 lines
2.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
|
|
import '../state/auth_controller.dart';
|
|
import 'routes.dart';
|
|
|
|
part 'router.g.dart';
|
|
|
|
/// Exposes a [GoRouter] that uses a [Listenable] to refresh its internal state.
|
|
///
|
|
/// With Riverpod, we can't register a dependency via an Inherited Widget,
|
|
/// thus making this implementation the "leanest" possible
|
|
///
|
|
/// To sync our app state with this our router, we simply update our listenable via `ref.listen`,
|
|
/// and pass it to GoRouter's `refreshListenable`.
|
|
/// In this example, this will trigger redirects on any authentication change.
|
|
///
|
|
/// Obviously, more logic could be implemented here, but again, this is meant to be a simple example.
|
|
/// You can always build more listenables and even merge more than one into a more complex `ChangeNotifier`,
|
|
/// but that's up to your case and out of this scope.
|
|
@riverpod
|
|
GoRouter router(RouterRef ref) {
|
|
final routerKey = GlobalKey<NavigatorState>(debugLabel: 'routerKey');
|
|
final isAuth = ValueNotifier<AsyncValue<bool>>(const AsyncLoading());
|
|
ref
|
|
..onDispose(isAuth.dispose) // don't forget to clean after yourselves (:
|
|
// update the listenable, when some provider value changes
|
|
// here, we are just interested in wheter the user's logged in
|
|
..listen(
|
|
authControllerProvider.select((value) => value.whenData((value) => value.isAuth)),
|
|
(_, next) {
|
|
isAuth.value = next;
|
|
},
|
|
);
|
|
|
|
final router = GoRouter(
|
|
navigatorKey: routerKey,
|
|
refreshListenable: isAuth,
|
|
initialLocation: const SplashRoute().location,
|
|
debugLogDiagnostics: true,
|
|
routes: $appRoutes,
|
|
redirect: (context, state) {
|
|
if (isAuth.value.unwrapPrevious().hasError) return const LoginRoute().location;
|
|
if (isAuth.value.isLoading || !isAuth.value.hasValue) return const SplashRoute().location;
|
|
|
|
final auth = isAuth.value.requireValue;
|
|
|
|
final isSplash = state.uri.path == const SplashRoute().location;
|
|
if (isSplash) return auth ? const HomeRoute().location : const LoginRoute().location;
|
|
|
|
final isLoggingIn = state.uri.path == const LoginRoute().location;
|
|
if (isLoggingIn) return auth ? const HomeRoute().location : null;
|
|
|
|
return auth ? null : const SplashRoute().location;
|
|
},
|
|
);
|
|
ref.onDispose(router.dispose); // always clean up after yourselves (:
|
|
|
|
return router;
|
|
}
|