Sath. K
Sath. K

Reputation: 17

Flutter provider not updating variable values

Context: I'm trying to create an authentication flow with firebase_auth for my app where the user can sign out through a button on a Profile page.

Originally the logout button was on a home page (named Maps) that appears right after sign in. This is called by a wrapper class that opens Maps upon successful login.

However, when the user clicks on the sign out button in the Profile page, it doesn't take them back to the login screen UNTIL they go back to the Maps page.

Expected results:

  1. User signs in successfully.

  2. Authentication side creates a stream that sends data to a Wrapper class indicating successful sign in.

  3. Wrapper returns the home screen if the stream doesn't return null, else stays on the login screen.

  4. User goes to the Profile screen.

  5. User taps the sign out buttons and gets returned to the login screen. This should happen via the wrapper.

Actual:

  1. User signs in successfully.

  2. Authentication side creates a stream that sends data to wrapper indicating successful sign in.

  3. Wrapper returns the home screen if the stream doesn't return null, else stays on the login screen.

  4. User goes to the settings screen.

  5. User taps the sign out button and nothing happens on the front-end (console shows that the user has logged out on the back-end.

  6. User goes back to the home screen, and THEN gets sent to the login screen.

Code (in steps):

  1. User signs in

  2. Stream gets set up + code that signs the user out (not sure if relevant)

 // auth change user stream
  // set up a stream so that everytime someone signs in/out, we get a response
  // down the stream
  Stream<User> get user {
    return _auth.onAuthStateChanged
        .map(_userFromFirebaseUser); // same as line above
  }

// sign out
  Future signOut() async {
    try {
      return await _auth.signOut();
    } catch (e) {
      print(e.toString());
      return null;
    }
  }
  1. Wrapper
class Wrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);

    // return either Maps or Login widget
    if (user == null) {
      return Authenticate();
    } else {
      return MapsPage();
    }
  }
}
  1. Relevant Map code (StreamProvider here is not used for login anymore)
// Function is for when a navigation icon is tapped
  void onTabTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });

    if (index == 1) {
      startCamera();
    } else if (index == 2) {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (BuildContext context) => new UserProfile()));
    }
  }

@override
  Widget build(BuildContext context) {

    return StreamProvider<QuerySnapshot>.value(
        value: DatabaseService().users,
        child: Scaffold(
            body: // some code here,

            bottomNavigationBar: BottomNavigationBar(
              items: const <BottomNavigationBarItem>[
                BottomNavigationBarItem(
                  icon: Icon(Icons.map),
                  title: Text('Map'),
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.camera),
                  title: Text("Camera"),
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.account_circle),
                  title: Text('Profile'),
                ),
              ],
              currentIndex: _selectedIndex,
              selectedItemColor: Colors.white,
              backgroundColor: Color(0xFFFFA600),
              onTap: onTabTapped,
            )));
  }
  1. Relevant user profile code
final AuthService _auth = AuthService();

@override
  Widget build(BuildContext context) {
    return StreamProvider<User>.value(
      value: AuthService().user,
      child: Scaffold(
          body: Column(
            children: <Widget>[
              ButtonTheme(
                child: FlatButton(
                  child: const Text('Log Out'),
                  onPressed: () async {
                    await _auth.signOut();
                  },
                ),
              )
            ],
          ),
          ),
    );
  }

Please let me know if more information is needed and thanks in advance.

Upvotes: 1

Views: 1622

Answers (2)

SempaiLeo
SempaiLeo

Reputation: 344

final AuthService _auth = AuthService(); shouldn't exist inside your profile page, rather the _auth should be provided/injected with provider.

Using final _auth = Provider.of<AuthService>(context); would be better. I'd have to know more about the architecture you are using.

Upvotes: 1

Sarvesh Bhatnagar
Sarvesh Bhatnagar

Reputation: 1122

When I log out of my app, I usually do the following:

onTap: () {
  Navigator.popUntil(context, ModalRoute.withName("/"));
  _auth.signOut();
},

Try this, it might work.

Upvotes: 3

Related Questions