How to redirect users to landing page when they first install using goRouter

189 Views Asked by At

In my previous method I had a Riverpod provider returning auth state changes and I would simply redirect based on that like so inside the build of myapp:

 return user.when(
  data: (userData) {
    // if (userData != null) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      themeMode: activetheme,
      theme: MyThemes.lightTheme,
      darkTheme: MyThemes.darkTheme,
      home: const MyHomePage(),
    );
     } else {
      //if user is null they have opened the app for the first time so we send them to the Welcome Page
      return MaterialApp(
        title: 'Flutter Demo',
        debugShowCheckedModeBanner: false,
        themeMode: activetheme,
        theme: MyThemes.lightTheme,
        darkTheme: MyThemes.darkTheme,
        home: const WelcomePage(),
      );
    }*/
  },
  loading: () =>
      const CircularProgressIndicator(), // Replace with your loading widget
  error: (error, stackTrace) => ErrorWidget('Error: $error'),
);

But now I have switched to GoRouter and I am unable to replicate this, what im trying to do is send the user to he landing page if they are not signed in or at least signed in anonymously, I can't read the AuthProvider inside my goRouter redirect constructor so how is it best To do this?

final goRouter = GoRouter(
  initialLocation: '/',
  navigatorKey: _rootNavigatorKey,
  debugLogDiagnostics: true,
  routes: [
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) {
        return ScaffoldWithNestedNavigation(navigationShell: navigationShell);
      },
      branches: [
        StatefulShellBranch(
          navigatorKey: _shellNavigatorHomeKey,
          routes: [
            // Shopping Cart
            GoRoute(
              path: '/',
              builder: (BuildContext context, GoRouterState state) =>
                  const MyHomePage(),
              routes: [
                GoRoute(
                  path: 'settimer',
                  parentNavigatorKey: _rootNavigatorKey,
                  builder: (context, state) {
                    return SetTimer();
                  },
                ),
                GoRoute(
                  path: 'countdown',
                  parentNavigatorKey: _rootNavigatorKey,
                  builder: (context, state) {
                    return CountDownPage();
                  },
                ),
              ],
            ),
          ],
        ),
        StatefulShellBranch(
          navigatorKey: _shellNavigatorStatsKey,
          routes: [
            GoRoute(
              path: '/statspage',
              builder: (BuildContext context, GoRouterState state) =>
                  const StatsPage(),
            ),
          ],
        ),
        StatefulShellBranch(
          navigatorKey: _shellNavigatorMoreKey,
          routes: [
            GoRoute(
              path: '/morepage',
              builder: (BuildContext context, GoRouterState state) =>
                  const MorePage(),
            ),
          ],
        ),
      ],
    ),
  ],
);

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  usePathUrlStrategy();
  runApp(const ProviderScope(
    child: MyApp(),
  ));
}

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userAuthProvider);
//returns which theme is active light or dark
    final activetheme = ref.watch(thememodeProvider);
    return MaterialApp.router(
      title: 'Flutter Demo',
      routerConfig: goRouter,
      debugShowCheckedModeBanner: false,
      themeMode: activetheme,
      theme: MyThemes.lightTheme,
      darkTheme: MyThemes.darkTheme,
      //home: const MyHomePage(),
    ); 
1

There are 1 best solutions below

3
On

Refer to the code below and change it according to your situation.

  1. Make a SharedPreferences provider.

    @riverpod
    SharedPreferences sharedPrefs(SharedPrefsRef ref) {
      return throw UnimplementedError();
    }
    
  2. Override this provider in the main.dart.

    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      // Get SharedPrefences
      final SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
    
      runApp(
        ProviderScope(
          overrides: [
            sharedPrefsProvider.overrideWithValue(sharedPrefs),
          ],
          child: const MyApp(),
        ),
      );
    }
    
  3. Make a onboarding controller or something. (I used BuildContext in the provider in this example, but you should use it in an external widget such as the Lading page skip button or complete button.)

    @riverpod
    class OnboardingController extends _$OnboardingController {
      late final SharedPreferences _prefs;
    
      /// If prefs key is not exist, return true and show onboarding screen.
      @override
      bool build() {
        _prefs = ref.watch(sharedPrefsProvider);
    
        bool showOnboarding = _prefs.getBool('showOnboarding') ?? true; 
    
        return showOnboarding;
      }
    
      void completeShowOnboarding(BuildContext context) {
        state = false;
        _prefs.setBool('showOnboarding', false);
        if(context.mounted) context.go(AppRoute.splash.routePath); // Use your path.
      }
    }
    
  4. Make GoRouter a provider and use the providers in redirection.

    @riverpod
    Raw<GoRouter> appRouter(AppRouterRef ref) {
      // Add your providers.
      final User? authState = ref.watch(authRepositoryProvider);
      final bool showOnboarding = ref.watch(onboardingControllerProvider);
    
      return GoRouter(
        navigatorKey: _rootNavigatorKey,
        initialLocation: AppRoute.splash.routePath,
        routes: [
          // Add your routes
        ],
        redirect: (context, state) {
          // If you run the app for the first time, the onboarding page is shown.
          if (showOnboarding) {
            return AppRoute.onboarding.routePath;
          }
    
          final isSplash = state.uri.toString() == AppRoute.splash.routePath;
    
          if (isSplash) {
            return authState == null
                ? AppRoute.auth.routePath
                : AppRoute.home.routePath;
          }
    
          return null;
        },
      );
    }