User not able to sign out in firebase Flutter application - firebase

D/FirebaseAuth( 7994): Notifying id token listeners about a sign-out event.
D/FirebaseAuth( 7994): Notifying auth state listeners about a sign-out event.
class LandingPage extends StatefulWidget {
#override
_LandingPageState createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
User _user;
#override
void initState() {
super.initState();
_updateUser(FirebaseAuth.instance.currentUser);
}
void _updateUser(User user) {
setState(() {
_user = user;
});
}
#override
Widget build(BuildContext context) {
if (_user == null) {
return SignInPage(
onSignIn: _updateUser,
);
}
return HomePage(
onSignOut: () => _updateUser(null),
);
}
}
Home page Code:-
class HomePage extends StatelessWidget {
HomePage({#required this.onSignOut});
final VoidCallback onSignOut;
Future<void> _signOut() async {
try {
await FirebaseAuth.instance.signOut();
} catch (e) {
print(e.toString()) ;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
actions: <Widget>[
FlatButton(
child: Text(
'Logout',
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
onPressed: _signOut,
),
],
),
);
}
}
this is my code but the user is not able to log out of my application.Can somebody tell me what to fix

Try to await the signout call:
class HomePage extends StatelessWidget {
HomePage({#required this.onSignOut});
final VoidCallback onSignOut;
Future<void> _signOut() async {
try {
await FirebaseAuth.instance.signOut();
} catch (e) {
print(e.toString()) ;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
actions: <Widget>[
FlatButton(
child: Text(
'Logout',
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
),
),
onPressed: () async => await _signOut(), // Updated code
),
],
),
);
}
}

Related

Flutter Firebase App goes to Waiting Connection State when hot-reloaded

I have a Flutter application running through VS Code which does simple authentication using Firebase. Following is my full program.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:provider/provider.dart';
import 'package:fireauth_starter/views/home_view.dart';
import 'views/login_page_view.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(FireAuthStarter());
}
class FireAuthStarter extends StatelessWidget {
//final Future<FirebaseApp> _initialisation = Firebase.initializeApp();
#override
Widget build(BuildContext context) {
//
return Provider<FirebaseAuth>(
create: (context) => FirebaseAuth.instance,
child: MaterialApp(
title: 'Firebase Authentication',
home: LandingPage(),
),
);
}
}
class LandingPage extends StatelessWidget {
const LandingPage();
#override
Widget build(BuildContext context) {
final firebaseAuth = Provider.of<FirebaseAuth>(context);
return StreamBuilder<User>(
stream: firebaseAuth.authStateChanges(),
builder: (context, AsyncSnapshot<User> snapshot) {
print(snapshot.connectionState.toString());
if (snapshot.connectionState == ConnectionState.active) {
//final bool signedIn = snapshot.hasData;
User user = snapshot.data;
return user == null ? LoginPageView() : HomeView();
//return signedIn ? DashBoard() : FirstView();
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
});
}
}
class LoginPageView extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseAuth = Provider.of<FirebaseAuth>(context);
return MaterialApp(
home: Center(
child: Container(
child: TextButton(
child: Text('Sign In'),
onPressed: () {
firebaseAuth.signInWithEmailAndPassword(
email: 'myemail#email.com',
password: '1234567',
);
},
),
),
),
);
}
}
class HomeView extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseAuth = Provider.of<FirebaseAuth>(context);
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Home View'),
actions: [
TextButton(
child: Text('Sign Out'),
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.white),
),
onPressed: () {
firebaseAuth.signOut();
},
),
],
),
body: Center(
child: Container(child: Text('Home View content')),
),
),
);
}
}
The application works as expected but when I use hot reload or hot restart, app get stuck in Progress Indicator because the snapshot.connectionState returns 'ConnectionState.waiting'
https://api.flutter.dev/flutter/widgets/ConnectionState-class.html states waiting: indicating that the asynchronous operation has begun, typically with the data being null.
I though the hot restart will reset all the states and app will perform as initial load. But it doesn't. What am I missing in this?

Flutter - widget variables are always null

I have a Flutter app connected to firebase, and I'm using it to receive push notifications from Firebase Cloud Messaging, using this code. Whenever I call the variables widget.title, widget.body, they are null, but when the method receives a notification, they have the value that came from FCM. What should I do?
class PushList extends StatefulWidget {
Map<dynamic, dynamic> notific;
String title, body;
Future<dynamic> fcmMessageReceiver() async {
FirebaseMessaging.instance.getInitialMessage().then((value) {
if (value != null) {}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) {
notificacao = {
'title': message.notification.title,
'body': message.notification.body
};
title = message.notification.title;
body = message.notification.body;
print('MENSAGEM: $notific');
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {});
}
PushList() {
}
#override
_PushListState createState() => _PushListState();
}
class _PushListState extends State<PushList> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
backgroundColor: Colors.white,
appBar: null,
body: ListView(
children: [
widget.notific != null
? Card(
margin: EdgeInsets.all(10),
elevation: 4,
child: ListTile(
title: Text(
widget.title,
),
subtitle: Text(
widget.body,
),
),
)
: Container(
child: Text("U don't have new notifcs."),
),
],
),
);
}
}
PushList should be immutable. Define the properties inside the state and call fcmMessageReceiver inside initState. Also you need to call setState to trigger rebuild after you set title and body:
class PushList extends StatefulWidget {
#override
_PushListState createState() => _PushListState();
}
class _PushListState extends State<PushList> {
Map<dynamic, dynamic> notific;
String title, body;
#override
void initState() {
super.initState();
fcmMessageReceiver();
}
Future<dynamic> fcmMessageReceiver() async {
FirebaseMessaging.instance.getInitialMessage().then((value) {
if (value != null) {}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.notification != null) {
if (mounted) {
setState(() {
notificacao = {
'title': message.notification.title,
'body': message.notification.body
};
title = message.notification.title;
body = message.notification.body;
});
}
print('MENSAGEM: $notific');
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
backgroundColor: Colors.white,
appBar: null,
body: ListView(
children: [
notific != null
? Card(
margin: EdgeInsets.all(10),
elevation: 4,
child: ListTile(
title: Text(
title ?? '',
),
subtitle: Text(
body ?? '',
),
),
)
: Container(
child: Text("U don't have new notifcs."),
),
],
),
);
}
}

FirebaseAuth.instance.userChanges stream does not emit the signed in user after page reload (web)

On Flutter Web, the userChanges stream from a FirebaseAuth instance never emits the signed in user after a page reload. Instead, it only emits null. With the example below, the app gets stuck on the loading page.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/loading',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/error':
return MaterialPageRoute(builder: (_) => ErrorScreen());
case '/loading':
return MaterialPageRoute(builder: (_) => LoadingScreen());
case '/signin':
return MaterialPageRoute(builder: (_) => SignInScreen());
case '/welcome':
return MaterialPageRoute(builder: (_) => WelcomeScreen());
default:
return MaterialPageRoute(
builder: (_) => Center(child: Text('Unknown route')));
}
},
);
}
}
class ErrorScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Text('An error occurred.'),
),
);
}
}
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
#override
void initState() {
init();
super.initState();
}
init() async {
try {
await Firebase.initializeApp();
if (kDebugMode) {
await FirebaseAuth.instance.useEmulator('http://localhost:1001');
}
final preferences = await SharedPreferences.getInstance();
bool signedIn = preferences.getBool('IS_SIGNED_IN') ?? false;
String landingPath = '/signin';
if (signedIn) {
landingPath = '/welcome';
// Wait for the userChanges to emit a non-null element.
await FirebaseAuth.instance
.userChanges()
.firstWhere((user) => user != null);
}
Navigator.of(context).pushReplacementNamed(landingPath);
} catch (error) {
print(error);
Navigator.of(context).pushReplacementNamed('/error');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: Text('Loading...'),
),
);
}
}
class SignInScreen extends StatelessWidget {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email address'),
),
TextField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
),
ElevatedButton(
onPressed: () => _submit(context),
child: Text('SIGN IN'),
),
],
),
),
);
}
void _submit(BuildContext context) async {
final email = _emailController.text;
final password = _passwordController.text;
FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password)
.then((credential) async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('IS_SIGNED_IN', true);
Navigator.of(context).pushReplacementNamed('/welcome');
});
}
}
class WelcomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Text('Welcome!'),
ElevatedButton(
onPressed: () => _signOut(context),
child: Text('SIGN OUT'),
)
],
),
),
);
}
void _signOut(BuildContext context) {
FirebaseAuth.instance.signOut().then((_) async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('IS_SIGNED_IN', false);
Navigator.of(context).pushReplacementNamed('/signin');
});
}
}
If it helps, I'm using version 8.3.0 of the Firebase Javascript libraries in my index.html file.
Am I missing something here?
It turns out the code above is fine. The issue is the emulator. Commenting out these lines of code makes the app behave as expected:
if (kDebugMode) {
FirebaseAuth.instance.useEmulator('http://localhost:1001');
}
I've filed a bug report on FlutterFire's repo about this emulator issue.

null an the Display in Flutter but with the right Value in Future

I am pretty new in Flutter and i can not solve this problem.
i have a really simple application. it is just a login with google an a User is created in Firebase, that user have a counter and a button this button increased the counter (int _user.count++).
Then my problem: after the login in the next window, it is not visible the count variable until I click "plus" button. the variable is right and the query with fireStore work great I got the variable but if I do not click the button I got an the display in the place of the variable "null".
Thanks a lot for you Help and Time, I really hope that you can help me. maybe it is a tiny problem I have not found information about it but it is happen when some start to learn.
MyDAO: Hier the Method Future it is the responsable of make the Query to FireStore.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:gauth/user_model.dart';
import 'package:rxdart/rxdart.dart';
final UserDAO userDAO = UserDAO();
class UserDAO {
final Firestore _db = Firestore.instance;
PublishSubject loading;
Observable<Future<QuerySnapshot>> profile;
void updateData(UserModel user) async {
DocumentReference documentReference =
_db.collection("users").document(user.uid);
return documentReference.setData({
"uid": user.uid,
"userName": user.name,
"email": user.email,
"photoUrl": user.photoUrl,
"count": user.count,
"lastIn": DateTime.now()
}, merge: true);
}
Future<QuerySnapshot> readDateFutur(String email) async {
// loading.add(true);
QuerySnapshot querySnapshot = await (_db
.collection("users")
.where("email", isEqualTo: email)
.getDocuments());
// loading.add(false);
return querySnapshot;
}
}
hier in the method "void initState()" I hold the variable _user.couner, that works.
class PlusCounter extends StatefulWidget {
UserModel user;
PlusCounter(this.user);
#override
_PlusCounterState createState() => _PlusCounterState();
}
class _PlusCounterState extends State<PlusCounter> {
UserModel _user;
PublishSubject loading;
#override
void initState() {
// TODO: implement initState
super.initState();
setState(() {
_user = widget.user;
//loading.add(false);
userDAO.readDateFutur(_user.email).then((QuerySnapshot docs) {
if (docs.documents.isNotEmpty) {
print("::::::::::NOESTOY VACIO:::::::::::::::::::::");
print(docs.documents.last.data["count"]);
if (docs.documents.last.data["count"] != null) {
_user.count = docs.documents.last.data["count"];
} else {
_user.count = 0;
}
} else {
print(":::::::::::ESTOY VACIO:::::::::::::::::");
_user.count = 0;
}
});
});
}
void _plus() {
setState(() {
_user.count++;
});
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text("Cuantas veces te has \n lavado las manos:"),
Text("${_user.count}"),
MaterialButton(
onPressed: () {
_plus();
},
child: Text("Plus"),
textColor: Colors.white,
color: Colors.blue,
),
MaterialButton(
onPressed: () => userDAO.updateData(_user),
child: Text("Guardar"),
textColor: Colors.white,
color: Colors.blue,
),
],
);
}
}
WelcomePage code is this one.
class userDataWelcome extends StatelessWidget {
UserModel _userModel;
userDataWelcome(this._userModel);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Welcome"),
),
body: Center(
child: Column(
children: <Widget>[
Center(
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(_userModel.photoUrl),
),
),
),
),
Text("${_userModel.name}"),
PlusCounter(_userModel),
MaterialButton(
onPressed: () => authService.SingOut(),
child: Text("Logout"),
textColor: Colors.white,
color: Colors.deepOrange,
)
],
),
),
);
}
}
Then I really do not why I need to click "plus" button before I can see the Value of _user.count, because I just see null in otherwise. just again I want to say Thanks for your help.
Try wrapping this line in initStat() _user.count = docs.documents.last.data["count"]; in setState((){}); like this
setState((){
_user.count = docs.documents.last.data["count"];
)};

Flutter Firestore error with BLoC pattern

A newbie in flutter has a lot of stuff that is just starting to figure out now it's BLoC pattern and now I ran into a problem
I can not understand how to fix this error, seems to have written everything correctly
Here generic Interface for all BLoCs
abstract class BlocBase {
void dispose();
}
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
#required this.child,
#required this.bloc,
}) : super(key: key);
final T bloc;
final Widget child;
#override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState<T> extends State<BlocProvider<BlocBase>> {
#override
void dispose() {
widget.bloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
Here is the second file in which I use BLoC and where it gives an error
Here I use function validateAndCreateData through which I add Tickets
#override
Widget build(BuildContext context) {
final bloc = BlocProvider.of<TicketsBloc>(context);
return Scaffold(
drawer: MyDrawer(),
appBar: AppBar(
title: Text('Sports'),
backgroundColor: Colors.blueGrey[900],
// automaticallyImplyLeading: false,
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
tooltip: 'Share',
onPressed: () {
Navigator.of(context).pushNamed('/second_screen');
}),
IconButton(
icon: Icon(Icons.account_circle),
tooltip: 'Your account',
onPressed: () {
Navigator.of(context)
.pushReplacementNamed('/account_screen');
}),
IconButton(
icon: Icon(Icons.add),
tooltip: 'Add Tickets',
onPressed: () => validateAndCreateData(bloc),
)
]),
body: MyTab(),
);
}
void validateAndCreateData(TicketsBloc bloc) async {
bloc.createData(description, image, name, price);
}
Your error mean you don't have access to the bloc. You must wrap your app with the provider. If not you cannot inherited from this.
return BlocProvider(
child: MaterialApp(
title: 'My App',
home: HomeScreen(),
),
);

Resources