Home > Software design >  Flutter Firebase authstatechanges
Flutter Firebase authstatechanges

Time:12-27

My app has a bottom navigation bar with 4 items one of them being home. Basically you need to login to use the other 3 items such as profile,messages,orders So i created a login page for profile if the user is not logged it sends the user to that page and if the user is logged in it sends the user to the actual profile page. It works but the problem is if the user is logged in and wants to switch between tabs using the navigation bar like going to messages and back to profile etc. It shows the login page for a split second then the actual page it is hard to notice but very annoying.

I dont understand why it doesnt see that it has data the first time. I tried delaying reading of data by 100ms so that it wouldnt rush it but couldnt get that to work. I used a pageview to animate between tabs on navigation bar that way it didnt flicker between loginPage and the actual page but animating from Home(page 0) to profile(page 3) it animates between the pages and it looks like fast forwarded rubbish. Is there a way to make this work?

 class AuthProfile extends StatelessWidget {
  AuthProfile({Key? key}) : super(key: key);
  final Stream<User?> authInstance = FirebaseAuth.instance.authStateChanges();
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
        stream: authInstance,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return const Profile();
          }
            else{
            return const ProfileLogin();
          }
        });
  }
}

main:


void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
        statusBarColor: Colors.transparent,
        statusBarBrightness: Brightness.light,
        statusBarIconBrightness: Brightness.light,
        systemNavigationBarColor: Colors.white,
        systemNavigationBarIconBrightness: Brightness.light));

    return const MaterialApp(
      home: Main(),
    );
  }
}

class Main extends StatefulWidget {
  const Main({super.key});

  @override
  State<Main> createState() => _Main();
}

class _Main extends State<Main> {
  int _selectedIndex = 0;

  final PageController _pageController = PageController(initialPage: 0);


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: PageView(
          controller: _pageController,
          physics: const NeverScrollableScrollPhysics(),
          children: [
            const Home(),
            AuthListings(),
            AuthMessages(),
            AuthProfile(),
            
          ]),
      bottomNavigationBar: BottomNavigationBar(
        iconSize: 30,
        type: BottomNavigationBarType.fixed,
        backgroundColor: Colors.white,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home_rounded),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.insert_chart_rounded),
            label: 'Listings',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.mark_as_unread_rounded),
            label: 'Messages',
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.account_circle_rounded), label: 'Profile')
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.purple,
        unselectedItemColor: Colors.black,
        showUnselectedLabels: false,
        showSelectedLabels: false,
        onTap: _onTappedBar,
      ),
    );
  }

  void _onTappedBar(int value) {
    setState(() {
      _selectedIndex = value;
    });

    _pageController.jumpToPage(value);
  }
}

EDIT: Fixed it with the help of solution

created two different lists for loggedIn and loggedOut scenario


void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
        statusBarColor: Colors.transparent,
        statusBarBrightness: Brightness.light,
        statusBarIconBrightness: Brightness.light,
        systemNavigationBarColor: Colors.white,
        systemNavigationBarIconBrightness: Brightness.light));

    return const MaterialApp(
      home: Main(),
    );
  }
}

class Main extends StatefulWidget {
  const Main({super.key});

  @override
  State<Main> createState() => _Main();
}

class _Main extends State<Main> {
  int _selectedIndex = 0;

  static final List<Widget> _loggedIn = <Widget>[
    const Home(),
    const Listings(),
    const Messages(),
    const Profile(),
  ];
  static final List<Widget> _loggedOut = <Widget>[
    const Home(),
    const ListingsLogin(),
    const MessagesLogin(),
    const ProfileLogin(),
  ];

  @override
  Widget build(BuildContext context) {
    final Stream<User?> authInstance = FirebaseAuth.instance.authStateChanges();
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Center(
        child: StreamBuilder<User?>(
            stream: authInstance,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return _loggedIn.elementAt(_selectedIndex);
              } else {
                return _loggedOut.elementAt(_selectedIndex);
              }
            }),
      ),
      bottomNavigationBar: BottomNavigationBar(
        iconSize: 30,
        type: BottomNavigationBarType.fixed,
        backgroundColor: Colors.white,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home_rounded),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.insert_chart_rounded),
            label: 'Listings',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.mark_as_unread_rounded),
            label: 'Messages',
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.account_circle_rounded), label: 'Profile')
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.purple,
        unselectedItemColor: Colors.black,
        showUnselectedLabels: false,
        showSelectedLabels: false,
        onTap: _onTappedBar,
      ),
    );
  }

  void _onTappedBar(int value) {
    setState(() {
      _selectedIndex = value;
    });
  }
}

CodePudding user response:

The problem is everytime you go to AuthProfile() Stream checks the authStateChanges() so everytime it shows ProfileLogin() by default and update it with Profile() screen, what you can do is move the logic in your onTapBar function, there check if the user is logged in, then send him only to Profile() or ProfileLogin().

  • Related