Home > Enterprise >  send a user to a banned screen using bloc
send a user to a banned screen using bloc

Time:01-18

I'm building a flutter app that uses a profile Bloc provided throughout the entire app. I would like to implement a feature that when the user's isBanned value is true and before the ban expiration, the user is sent to an unescapable banned screen. The best idea I've had so far is to include this statement in the blocbuilder on the first screen rendered when a user opens the app:

      builder: (context, state) {
        if (state is ProfileLoaded) {
          
          if (state.user.isBanned &&
              state.user.banExpiration.isAfter(DateTime.now())) {
            //pop the screen until the route is / then puch banned screen
            Navigator.of(context).popUntil((route) => route.isFirst);
            Navigator.pushNamed(context, BannedScreen.routeName);
          }
          return...

But this is causing errors and does not work. It seems like when the profileBloc is updated, it continues rebuilding the previous screen, and moves the banned user back to that screen. Anyone have any ideas on how to implement something like this?

CodePudding user response:

There are two cases in which you want to send the user to the banned screen:

  • case 1: When the app initially launches and he is banned already
  • case 2: when the app launches and he is not banned, but then sometime during his usage of the app he becomes banned.

Solution For case 1:

  • Use a splash screen as the initial screen of your app, and add an event to the bloc when the app launches to check if the user is banned, and then listen to the emitted state using a bloc listener, like this:
class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  void initState() {
    super.initState();
    // add event to bloc to check if user is banned
    // if user is banned, navigate to banned screen
    // else, navigate to home screen
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      BlocProvider.of<AuthBloc>(context).add(CheckIfUserIsBanned());
    });
  }

  @override
  Widget build(BuildContext context) {
    return BlocListener<AuthBloc,AuthState>(
      listener: (context, state){
        if(state is UserIsBanned){
          Navigator.pushReplacementNamed(context, '/banned');
        }else if(state is UserIsNotBanned){
          Navigator.pushReplacementNamed(context, '/home');
        }
      },
      child: Scaffold(
        body: Center(
          child: CircularProgressIndicator(),
        ),
      ),
    );
  }
}

Solution for case 2:

It is similar to solution for case 1, you need to wrap every screen (not every widget, only the top widget of each screen with the BlocListener as above.

// same logic as above but for home screen
class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return BlocListener<AuthBloc,AuthState>(
      listener: (context, state){
        if(state is UserIsBanned){
          // when the button below is pressed, we reach this statement
          // and the /banned route is pushed
          Navigator.pushReplacementNamed(context, '/banned');
        }
      },
      child: Scaffold(
        body: Center(
          child: Column(
            children: [
              Text('Home Screen'),
              // button that can get the user banned
              ElevatedButton(
                onPressed: (){
                  BlocProvider.of<AuthBloc>(context).add(GetUserBanned());
                },
                child: Text('Ban User'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Another better solution for case 2:

Instead of wrapping each screen with a bloc Listener, you can "lift the state up" and put all your screens under, say for example, a MaterialApp, and then wrap that MaterialApp with the blocListener.

  • Related