Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use GoRouter redirects to handle app startup state changes #151

Merged
merged 4 commits into from
Mar 18, 2024

Conversation

bizz84
Copy link
Owner

@bizz84 bizz84 commented Mar 17, 2024

Closes #150.

Motivation

While AppStartupWidget is a great way to initialize dependencies with eager provider initialization, particular care must be taken for apps that support navigation by URL or deep links.

For those apps, the root-level widget must be configured immediately (with GoRouter or equivalent).

To account for this, I've modified the GoRouter code as follows:

@riverpod
GoRouter goRouter(GoRouterRef ref) {
  // rebuild GoRouter when app startup state changes
  final appStartupState = ref.watch(appStartupProvider);
  final authRepository = ref.watch(authRepositoryProvider);
  return GoRouter(
    initialLocation: '/signIn',
    ...
    redirect: (context, state) {
      // If the app is still initializing, show the /startup route
      if (appStartupState.isLoading || appStartupState.hasError) {
        return '/startup';
      }
      ...
    },
    refreshListenable: GoRouterRefreshStream(authRepository.authStateChanges()),
    routes: [
      GoRoute(
        path: '/startup',
        pageBuilder: (context, state) => NoTransitionPage(
          child: AppStartupWidget(
            // * This is just a placeholder
            // * The loaded route will be managed by GoRouter on state change
            onLoaded: (_) => const SizedBox.shrink(),
          ),
        ),
      ),
      ...
    ],
    errorPageBuilder: (context, state) => const NoTransitionPage(
      child: NotFoundScreen(),
    ),
  );
}

Additionally, this PR moves the Firebase initialization code back in the main() function:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  ...
  // * Initialize Firebase
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  // * Entry point of the app
  runApp(const ProviderScope(
    child: MyApp(),
  ));
}

This prevents any "Firebase app not initialized" errors that would otherwise occur ref.watch(authRepositoryProvider) is called inside the GoRouter body.
Besides, the Firebase initialization code will only fail in case of a configuration error (which can be immediately spotted when running the app) - so it's best to keep this inside main().

@bizz84 bizz84 marked this pull request as ready for review March 18, 2024 16:01
@bizz84 bizz84 merged commit 2e6495b into master Mar 18, 2024
1 check passed
@bizz84 bizz84 deleted the app-startup-gorouter branch March 18, 2024 16:26
@devloic
Copy link

devloic commented Mar 18, 2024

I created a fresh clone of starter_architecture_flutter_firebase.
there is a redirect loop problem.

...
[GoRouter] Full paths for routes:
=> /startup
=> /onboard…edit
entries => /entries
profile => /account

[GoRouter] setting initial location /signIn
[GoRouter] redirecting to RouteMatchList(/onboarding)
[GoRouter] Redirection exception: redirect loop detected /signIn => /onboarding => /onboarding => /signIn
[GoRouter] Using MaterialApp configuration
[GoRouter] redirecting to RouteMatchList(/onboarding)
[GoRouter] Redirection exception: redirect loop detected /signIn => /onboarding => /onboarding => /signIn

image

I managed to bypass this problem so I could test the urls and they are working.

@bizz84
Copy link
Owner Author

bizz84 commented Mar 19, 2024

I fixed the redirect loop here:
93d8aa6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Could not navigate to initial route. The requested route name was: "/entries"
2 participants