'Flutter Firebase Authentication - delay on app startup/refresh

I am running an app that has a 'landing page', Basically, when the user opens/restarts/refreshes the app, the landing screen decides whether to direct the user to the sign-in screen (if the user is not logged in) or the home screen (if they are already logged in).

The code I am using for this functionality (involving a StreamBuilder) is this:

class LandingPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final auth = Provider.of<AuthBase>(context, listen: false);
    return StreamBuilder<User?>(
        stream: auth.authStateChanges(),
        builder: (context, snapshot) {
          /// If the connection state is waiting, show splash screen or loading icon
          if (snapshot.connectionState == ConnectionState.waiting) {
            print('Connection waiting');
            return Scaffold(
              body: Center(
                child: PlatformCircularProgressIndicator(),
              ),
            );
          }

          /// Once the connection is established, then show the disclaimer acceptance or sign-in screen (depending if there is a logged in user or not)
          if (snapshot.connectionState == ConnectionState.active) {
            User? user = snapshot.data;
            return FutureBuilder<IdTokenResult>(
              future: user?.getIdTokenResult(true),
              builder: (
                BuildContext context,
                AsyncSnapshot<IdTokenResult> snapshotData,
              ) {
                if (user == null ||
                    user.emailVerified == false ||
                    snapshotData.data?.claims!['status'] != 'active') {
                  return SignInHomePage.create(context);
                } else {
                  return Provider<User?>.value(
                    value: user,
                    child: DisclaimerAcceptanceHomeScreen(
                      userName: user.displayName,
                    ),
                  );
                }
              },
            );
          } else {
            return Scaffold(
              body: Center(
                child: PlatformCircularProgressIndicator(),
              ),
            );
          }
        });
  }
}

The reason I am using a FutureBuilder is that my app is subscription based and I am using cloud functions and custom claims to check to see if a user has an active subscription before allowing them to log in.

My issue is that when a user refreshes/reloads the app, if they are logged in, there is a brief flash where the sign-in screen is shown (can't be more than a second) before the other screen is shown. That comes across as quite poor from a user impression point of view, so I am trying to fix that. Basically, if a user is logged in, I do not want them to be shown even a flash of the sign in screen. I would like it to go straight from the splash screen to the disclaimer home screen that you see.

I came across this answer in which someone appeared to have the same issue as me. They explained that I need to do something when the connection state is waiting, which is why you see the code in there.

Unfortunately, that isn't working for me. For me, the flash of the sign in screen happens when the connection state is active, not when it is waiting. I am not too sure how to correct this.

Does anyone have thoughts about how I could go about fixing this, so that there is not a flash of the sign-in screen at all?



Solution 1:[1]

You might use firestore exists on snapshots. I think Signin page shows because when user found with emailVerified false and after that claims value comes, which redirects to landing page. So I'd do something like this:

// make sure snapshot completed
if (snapshotData.exists) {
  // if user null or user found but status not verified
  if (user == null) {
    return SignInHomePage.create(context);
  } else {
    if (snapshotData.data?.claims!['status'] != 'active') {
      return SignInHomePage.create(context);
    } else {
      return Provider<User?>.value(
        value: user,
        child: DisclaimerAcceptanceHomeScreen(
          userName: user.displayName,
        ),
      );
    }
  }
} else {
  // show loading indicator or something
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1