Reputation: 17
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:
User signs in successfully.
Authentication side creates a stream that sends data to a Wrapper class indicating successful sign in.
Wrapper returns the home screen if the stream doesn't return null, else stays on the login screen.
User goes to the Profile screen.
User taps the sign out buttons and gets returned to the login screen. This should happen via the wrapper.
Actual:
User signs in successfully.
Authentication side creates a stream that sends data to wrapper indicating successful sign in.
Wrapper returns the home screen if the stream doesn't return null, else stays on the login screen.
User goes to the settings screen.
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.
User goes back to the home screen, and THEN gets sent to the login screen.
Code (in steps):
User signs in
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;
}
}
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();
}
}
}
// 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,
)));
}
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
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
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