How Add a If statement to main.dart file - firebase

I want to add an if statement function where if current user != null it should nav to Home() and not then it should nav to Login().
this is the current main file
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
title: 'TaakStore',
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (snapshot.hasData) {
print(snapshot);
return Home();
} else {
return Login();
}
},
),
));
}
instead of the streambuilder i want to add a firebase auth function
this
if(FirebaseAuth.instance.currentUser != null){
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => Home();));
}
else{
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => Login();));
}
Please help me!!

You can use ternary operation like so:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
bool loggedIn = FirebaseAuth.instance.currentUser !=null;
runApp(MaterialApp(
title: 'TaakStore',
home: loggedIn ? Home(): Login(),
),
);
}

I recommend you to use 'routes' in MaterialApp, I can give you an example here:
initialRoute: await AppRoute.getInitialRoute()
and open AppRoute and define there
static Future<String> getInitialRoute() {
if (FirebaseAuth.instance.currentUser != null) {
return '/home-page';
} else {
return '/login-page';
} }

Related

Ignoring header X-Firebase-Locale because its value was null - Yet app launches after a manual restart

I have a very weird error. When I try to log in/sign up to my app the user gets authenticated in firebase but the screens don't change. What's more, if I manually restart my app the authentication screen changes, and the app works the way it is supposed to. I attach the snippets of code, responsible for authentication and debug console data.
Debug console:
W/System ( 7512): Ignoring header X-Firebase-Locale because its value
was null. 2 I/System.out( 7512): (HTTPLog)-Static: isSBSettingEnabled
false D/InputConnectionAdaptor( 7512): The input method toggled cursor
monitoring off I/SurfaceControl( 7512): nativeRelease nativeObject
s[470179726496] I/SurfaceControl( 7512): nativeRelease nativeObject
Code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
return FutureBuilder<Object>(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
...
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, AsyncSnapshot<User?> userSnapshot) {
if (userSnapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (userSnapshot.hasData) {
print('user exists');
return MainScreen();
}
print('user does not exists');
return AuthScreen();
}),
routes: {
RecipeDetailScreen.routeName: (ctx) => RecipeDetailScreen(),
AddRecipeScreen.routeName: (ctx) => AddRecipeScreen(),
AuthScreen.routeName: (ctx) => AuthScreen(),
DiaryScreen.routeName: (ctx) => DiaryScreen(),
MainScreen.routeName: (ctx) => MainScreen(),
NutritionScreen.routeName: (ctx) => NutritionScreen(),
},
),
);
});
}
}
void authUser(
String email,
String password,
String conPassword,
bool isLogin,
) async {
setState(() {
isLoading = true;
});
FocusScope.of(context).unfocus();
try {
if (isLogin == false) {
await firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} else {
await firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
}
setState(() {
isLoading = false;
});
} on PlatformException catch (err) {
print(err);
var message = 'An error occurred, pelase check your credentials!';
if (err.message != null) {
message = err.message!;
}
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Theme.of(context).errorColor,
),
);
setState(() {
isLoading = false;
});
} catch (e) {
print(e);
setState(() {
isLoading = false;
});
rethrow;
}
}

FutureBuilder can't "see" data / snapshot.hasData

I have a Future function to get data from Firebase, that is not empty queries correctly:
Future getProducts(vendorId) async {
await vendorsInfoColl.doc(vendorId)
.collection("products")
.get()
.then((QuerySnapshot querySnapShot) async {
if (querySnapShot.docs.isNotEmpty){
print('not empty');
print(querySnapShot.docs);
return querySnapShot.docs;
} else {
print('snapshot empty');
return null;
}
});
}
I just have trouble getting a FutureBuilder see it. Keeps saying there is empty data.
Widget build(BuildContext context) {
return AlertDialog(
// pull title from db
// title: Future Text(vendorTitle.toString()),
title: Text(vendorTitle.toString()),
content: FutureBuilder(
future: VendorDatabase().getProducts(widget.vendorId),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print(snapshot.connectionState);
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Error');
} else if (snapshot.hasData) {
var blabla = snapshot.data;
print('there is snapshot data: $blabla');
return ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return ListTile(
title: Text(blabla['products']) //<-- i know this is wrong but can't fixt it till future builder actually sees some data.
);
}
);
} else {
return const Text('Empty data');
}
} else {
return Text('State: ${snapshot.connectionState}');
}
}
)
);
}
It would be great if can also get some tips on how to put it in a list :)
You're not returning anything inside getProducts:
Future getProducts(vendorId) async {
return await vendorsInfoColl.doc(vendorId)
.collection("products")
.get()
.then((QuerySnapshot querySnapShot) async {
if (querySnapShot.docs.isNotEmpty){
return querySnapShot.docs;
} else {
return null;
}
});
}
To avoid this in the future, declare a type in your Future:
// vvvvvvvvvvvvvvvv
Future<List<Document>> getProducts(vendorId) async {

The getter 'uid' was called on null

Guys I have this login page with email and password and when the user is succesfully logged it takes him to a chatscreen. On the chatscreen I need to access users uid to check who is sending the message, but I am getting the "The getter 'uid' was called on null.". I am using bloc pattern to login with validators. How can I fix this situation?
class LoginScreen extends StatefulWidget {
FirebaseUser user;
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _loginBloc = LoginBloc();
#override
void initState() {
super.initState();
_loginBloc.outState.listen((state) async {
switch (state) {
case LoginState.SUCCESS:
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => ComercialUserScreen()));
break;
case LoginState.FAIL:
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Erro'),
content: Text('Revise seu email e senha'),
));
break;
case LoginState.LOADING:
case LoginState.IDLE:
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<LoginState>(
stream: _loginBloc.outState,
initialData: LoginState.LOADING,
// ignore: missing_return
builder: (context, snapshot) {
print(snapshot.data);
switch (snapshot.data) {
case LoginState.LOADING:
return Center(
child: CircularProgressIndicator(),
);
case LoginState.FAIL:
case LoginState.SUCCESS:
case LoginState.IDLE:
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
InputField(
icon: Icons.person_outline,
hint: 'Usuário',
obscure: false,
stream: _loginBloc.outEmail,
onChanged: _loginBloc.changeEmail,
),
InputField(
icon: Icons.lock_outline,
hint: 'Senha',
obscure: true,
stream: _loginBloc.outEmail,
onChanged: _loginBloc.changePassword,
),
SizedBox(
height: 32,
),
StreamBuilder<bool>(
stream: _loginBloc.outSubmitValid,
builder: (context, snapshot) {
return RaisedButton(
child: Text("Entrar"),
onPressed:
snapshot.hasData ? _loginBloc.submit : null,
);
})
],
);
}
}),
);
}
}
class LoginBloc extends BlocBase with LoginValidators{
FirebaseUser _currentUser;
final _emailController = BehaviorSubject<String>();
final _passwordController = BehaviorSubject<String>();
final _stateController = BehaviorSubject<LoginState>();
Stream<String> get outEmail => _emailController.stream.transform(validateEmail);
Stream<String> get outPassword =>_passwordController.stream.transform(validatePassword);
Stream<LoginState> get outState => _stateController.stream;
Stream<bool> get outSubmitValid => Observable.combineLatest2(
outEmail, outPassword, (a, b) => true);
Function(String) get changeEmail => _emailController.sink.add;
Function(String) get changePassword => _passwordController.sink.add;
StreamSubscription _streamSubscription;
LoginBloc(){
_streamSubscription = FirebaseAuth.instance.onAuthStateChanged.listen((user) async {
if(user != null) {
if(await verifyAdmins(user)) {
_stateController.add(LoginState.SUCCESS);
} else {
FirebaseAuth.instance.signOut();
_stateController.add(LoginState.FAIL);
}
} else {
_stateController.add(LoginState.IDLE);
}
});
}
void submit (){
final email = _emailController.value;
final password = _passwordController.value;
_stateController.add(LoginState.LOADING);
FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password
).catchError((e) {
_stateController.add(LoginState.FAIL);
});
}
Future<bool> verifyAdmins (FirebaseUser user) async {
return await Firestore.instance.collection('users').document(user.uid).get().then((doc)
{
if(doc.data != null){
return true;
} else {
return false;
}
}).catchError((e) {
return false;
});
}
#override
void dispose() {
_emailController.close();
_passwordController.close();
_stateController.close();
_streamSubscription.cancel();
// TODO: implement dispose
}
}
class _AdminChatState extends State<AdminChat> {
bool _isLoading = false;
void _sendMessage({String text, File imgFile}) async {
DocumentSnapshot snapshot;
FirebaseUser user = await FirebaseAuth.instance.currentUser();
Map<String, dynamic> data = {
"uid" : user.uid,
'name' : user.displayName,
'photo' : user.photoUrl,
'time' : Timestamp.now()
};
if (imgFile != null){
StorageUploadTask task = FirebaseStorage.instance.ref().child('users').child(
DateTime.now().millisecondsSinceEpoch.toString()
).putFile(imgFile);
setState(() {
_isLoading = true;
});
StorageTaskSnapshot taskSnapshot = await task.onComplete;
String url = await taskSnapshot.ref.getDownloadURL();
data['imgUrl'] = url;
setState(() {
_isLoading = false;
});
}
if(text != null) data["text"] = text;
Firestore.instance.collection("users").document(snapshot.documentID)
.collection('messages').add(data);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hello'),
),
body: Column(
children: <Widget>[
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream:
Firestore.instance.collection('users').document(widget.snapshot.documentID)
.collection('messages').orderBy('time').snapshots(),
builder: (context, snapshot){
switch(snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
List<DocumentSnapshot> documents =
snapshot.data.documents.reversed.toList();
return ListView.builder(
itemCount: documents.length,
reverse: true,
itemBuilder: (context, index){
// ignore: unrelated_type_equality_checks
return ChatMessage(documents[index].data, true);
});
}
},
),
),
_isLoading ? LinearProgressIndicator() : Container(),
TextComposer(_sendMessage),
],
),
);
}
}
The command await FirebaseAuth.instance.currentUser(); in the _AdminChatState doesn't return any data so when you try to insert data based on the user is returns null. This happens because you can't use await while the state hasn't initialized. If that happened the entire class would wait with nothing show until the user was returned. Furthermore, you use a storage query with the same logic. If you want a state widget to run something when it starts up you can use the initState() function. If you want do display a progress bar while waiting for the data to return a FutureBuilder or StreamBuilder are great choices.

Getting null value (Firestore query result) in Flutter app

I have an application and In this i'm making a query for get user details by the e-mail account.
I'm using Future class to get data and fill my variable but the widget Text always show null value.
Please let me now if i am doing something wrong.
class _HomePageAppState extends State<HomePageApp> {
String _emailUsuario;
Usuario usuario;
void initState() {
super.initState();
Autenticacao().getCurrentUser().then((user) {
setState(() {
if (user != null) {
_emailUsuario = user.email.toString(); //the user email is returnig correctly
recuperarDadosUsuarioFirebase().then((ds) {
usuario = Usuario(
email: _emailUsuario,
nome: ds['nome'] != null ? ds['nome'] : null,
);
});
}
});
});
}
Future<DocumentSnapshot> recuperarDadosUsuarioFirebase() async {
DocumentSnapshot ds;
await Firestore.instance
.collection('usuarios')
.document(_emailUsuario)
.get()
.then((DocumentSnapshot _ds) {
ds = _ds;
});
return ds;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.white10,
child: ListView(
children: <Widget>[
Text('Bem vindo ${usuario.nome} !!!'),
],
),
),
);
}
}
U might want to use Future Builder for such async work cause build method was called before usuario is assign so like this :
FutureBuilder(
future: getCurrentUser(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
// after getting data
},
);
Method getCurrentUser() needs to be created :)

Flutter/FirebaseAuth : How can I autologin a user at app launch?

I have the following methods to see if the user is already logged in, which in this case I did log in and the getCurrentUser() function works because in the console it does return "USER IS NOT NULL" but the home widget is still null giving me the "EXCEPTION CAUGHT BY WIDGETS LIBRARY" saying that the home can't be null and stuff.
userAPI.dart
Future<FirebaseUser> getCurrentUser() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
if (user != null) {
return user;
} else {
return null;
}
}
main.dart
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
Widget home;
APIs().usersAPI.getCurrentUser().then((u) {
if (u == null) {
print('USER IS NULL');
home = WelcomePage();
} else {
print('USER IS NOT NULL');
home = FeedPage();
}
});
return MaterialApp(
title: "Jedi",
debugShowCheckedModeBanner: false,
home: home,
routes: {
'/login' : (context) => new LoginPage(),
'/feed' : (context) => new FeedPage(),
},
);
}
}
You need to make the App a StatefulWidget and call setState when setting the home page
setState(() {
home = WelcomePage();
});
setState(() {
home = FeedPage();
});
Plus you may need to set the home page to something other than null before the API returns.
What probably would be a better pattern is to use a FutureBuilder. This way you will be returning the correct Widget depending on the state you are in.
return MaterialApp(
title: "Jedi",
debugShowCheckedModeBanner: false,
home: FutureBuilder<FirebaseUser>(
future: APIs().usersAPI.getCurrentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return CircularProgressIndicator();
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
if(snapshot.data == null)
return WelcomePage();
else
return FeedPage();
}
}
),
routes: {
'/login' : (context) => new LoginPage(),
'/feed' : (context) => new FeedPage(),
},
);
}
Advancing the answer given by #aqwert, you need to check for the user is not null/is null after the connection status. See below working example - this assumes autologin if user is not null.
class LandingPage extends StatelessWidget {//call this class from the main.dart
#override
Widget build(BuildContext context) {
return StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
FirebaseUser user = snapshot.data;//get the user status once the connection is established
if (user == null) {
//print("User is NULL::: " + user.toString());
return LoginScreen();//
}
print("User is NOT NULL::: " + user.toString());
return DefaultScreen();//home screen
} else {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),//called in case all fails while waiting for connection status
),
);
}
},
);
Here is my simple solution you can try this, First we need a stateful widget and override the function initState() inside initState() we can work something look like this-
class _MyAppState extends State<MyApp> {
String initPage;
final FirebaseAuth auth=FirebaseAuth.instance;
User currentUser;
#override
void initState() {
super.initState();
try {
currentUser = auth.currentUser;
if(currentUser!=null){
initPage=Chat.id;
/*
here id is static variable which declare as a page name.
*/
}
else{
initPage=Home.id;
}
}
catch(e){
print(e);
initPage=Home.id;
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: initPage,
routes: {
Home.id: (context) => Home(),
Login.id: (context) => Login(),
Registration.id: (context) => Registration(),
Chat.id: (context) => Chat(),
},
);
}
}

Resources