Not able to use provider in flutter for handling Authentication flow

Issue

If anyone is not able to understand my problem please inform

I have used Provider package to handle authentication flow.
What I am doing is : Main.dart -> Auth handler widget(Which contain stream builder to check the onAuthChange) -> Page Handler(Here if the user is new it will take the user to onboarding screen from there it is transferred to Login page using push replacement) After login it is taken to check user if the data exist or not -> if exist it is taken to home screen -> Home screen contains 3 tab. In home tab there is signOut button, but when I press it doesn’t work. Help me in this.

Main.dart

Provider<AuthBase>(
      create: (context)=>Auth(),
      child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Rapport',
          theme: ThemeData(
            primaryColor: Color(0xFFE3F2FD),
            visualDensity: VisualDensity.adaptivePlatformDensity,
            pageTransitionsTheme: PageTransitionsTheme(
              builders: {
                TargetPlatform.android: CustomPageTransitionsBuilder(),
                TargetPlatform.iOS: CustomPageTransitionsBuilder(),
              },
            ),
          ),

          /*This is the routes table. Add all the route names used inside the app here
        Add the route name where the route is made as static const String, so as to you don't need to remember anything.
         */
          routes: {
            //the route name / stands for home / first route in the app.
            '/': (ctx) {
              return SplashScreen.navigate(
                name: 'assets/splash.flr',
                next: (context) {
                  print(isLogin.toString());
                  return AuthWidgetBuilder(dataExists: myData.length==0,isLogin: isLogin,builder: (context, userSnapshot,isLogin,dataExist) {
                    return Scaffold(
                      body: AuthWidget(userSnapshot: userSnapshot,dataExists: myData.length==0,isLogin: isLogin,),
                    );
                  });
                },
                startAnimation: 'Untitled',
                until: () => Future.delayed(Duration(seconds: 4)),
                backgroundColor: Colors.white,
              );
            },
            LoginScreen.loginRoute: (ctx) => LoginScreen(),
            CheckUser.checkRoute: (ctx) => CheckUser(),
            OnboardingScreen.onBoardRoute: (ctx) => OnboardingScreen(),
            StudentInfo.studentRoute: (ctx) => StudentInfo(),
            PersonalDetails.routeName:(ctx) => PersonalDetails(),
            ProfessionalDetails.routeName:(ctx) => ProfessionalDetails(),
            AddressDetails.routeName: (ctx) => AddressDetails(),
            TeacherHomeScreen.routeName:(ctx)=>TeacherHomeScreen(),
            TeacherVerification.routeName:(ctx)=>TeacherVerification(),
            StudentHomeScreen.routeName : (ctx)=>StudentHomeScreen(),
          },
        ),
    );

Auth_Widget_Builder

class AuthWidgetBuilder extends StatelessWidget {
  const AuthWidgetBuilder({Key key, @required this.builder,@required this.isLogin,@required this.dataExists}) : super(key: key);
  final Widget Function(BuildContext, AsyncSnapshot<User>,String,bool) builder;
  final String isLogin;
  final bool dataExists;


  @override
  Widget build(BuildContext context) {
    print('AuthWidgetBuilder rebuild');
    print(dataExists);
    final authService =
    Provider.of<AuthBase>(context, listen: false);
    return StreamBuilder<User>(
      stream: authService.onAuthStateChanged,
      builder: (context, snapshot) {
        print('StreamBuilder: ${snapshot.connectionState}');
        final User user = snapshot.data;
        if (user != null) {
          SharedPrefFunction().saveLoginPreference();
          return MultiProvider(
            providers: [
              Provider<User>.value(value: user),
            ],
            child: builder(context, snapshot,'true',dataExists),
          );
        }
        return builder(context, snapshot,isLogin,dataExists);
      },
    );
  }
}

Auth.Widget

class AuthWidget extends StatelessWidget {
  const AuthWidget({Key key, @required this.userSnapshot,this.dataExists,this.isLogin}) : super(key: key);
  final AsyncSnapshot<User> userSnapshot;
  final String isLogin;
  final bool dataExists;

  @override
  Widget build(BuildContext context) {
    if (userSnapshot.connectionState == ConnectionState.active) {
      if(isLogin == null){
        return OnboardingScreen();
      }
      else{
        return userSnapshot.hasData ? CheckUser(dataExist: dataExists,) : LoginScreen();
      }
    }
    return Scaffold(
      body: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

In checkUser.dart if data exist

homePage(BuildContext context) {
    print('checkUser');
    if (dataExists) {
      return Scaffold(
        body: SafeArea(
          child: Container(
            child: Column(
              children: <Widget>[
                Text(
                  'Welcome',
                  style: kTextStyle,
                ),
                FlatButton.icon(
                  onPressed: () {
                    setState(() {
                      Navigator.of(context).pushReplacementNamed(
                        StudentHomeScreen.routeName,   //This line is changed by me. This code is not correct and needs to be changed.
                      );
                    });
                  },
                  icon: Icon(Icons.home),
                  label: Text('Home'),
                ),
              ],
            ),
          ),
        ),
      );
    } else {
      return getInfoPage();
    }
  }

Student_Home_Screen.dart

class _StudentHomeState extends State<StudentHomeScreen> {
  bool _isProfilePicSet = false;
  int _currentTabIndex = 1;
  var _tabs = [
    Center(
      child: Text('Search Tab'),
    ),
    HomeTab(),
    Center(
      child: Text('Profile Tab'),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    var size = MediaQuery.of(context).size;
    return Scaffold(
      backgroundColor: Colors.white,
      body: _tabs[_currentTabIndex],
      bottomNavigationBar: BottomNavigationBar(
//        type: BottomNavigationBarType.shifting,
        backgroundColor: Colors.white,
//        fixedColor: Colors.black,
        iconSize: 24,
        selectedIconTheme: IconThemeData(
          color: themeColor,
          opacity: 1,
        ),
        unselectedIconTheme: IconThemeData(
          color: themeColor,
          opacity: 0.6,
        ),
        showUnselectedLabels: false,
        showSelectedLabels: true,
        elevation: 10,
        currentIndex: _currentTabIndex,
        onTap: (index) {
          setState(() {
            _currentTabIndex = index;
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            title: Text(
              'Search',
              style: subhead2.copyWith(color: themeColor),
            ),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text(
              'Home',
              style: subhead2.copyWith(color: themeColor),
            ),
          ),
          BottomNavigationBarItem(
            icon: CircleAvatar(
              backgroundImage: _isProfilePicSet
                  ? NetworkImage('set link here')
                  : AssetImage('assets/images/default.png'),
              maxRadius: 12,
            ),
            title: Text(
              'Profile',
              style: subhead2.copyWith(color: themeColor),
            ),
          ),
        ],
      ),
    );
  }
}

In Hometab the signOut button function

  Future<void> _signOut(BuildContext context) async {
    try {
      final auth = Provider.of<AuthBase>(context, listen: false);
      await auth.signOut();
    } catch (e) {
      print(e);
    }
  }

Solution

You need to have AuthWidgetBuilder as top-level widget (ideally above MaterialApp) so that the entire widget tree is rebuilt on sign-in / sign-out events.

You could make SplashScreen a child, and have some conditional logic to decide if you should present it.

By the way, if your splash screen doesn’t contain any animations you don’t need a widget at all, and you can use the Launch Screen on iOS or equivalent on Android (there’s tutorials about this online).
By @bizz84

Answered By – Suraj Jha

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *