I'm implementing google sign in using flutter and firestore. On click, user should should sign in with google and navigate user to a create user page - flutter

I have a google_sign_in button which when clicked should present the google sign in then the user should be redirected to a CreateAccountPage. The page has an input and a submit button. When the user submits their preferred username, the google account data together with the created username should be stored as a document in users collection cloud firestore database and the user redirected to another page, say TimelinePage.
Below is my home.dart file:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:musagram/pages/activity_feed.dart';
import 'package:musagram/pages/create_account.dart';
import 'package:musagram/pages/profile.dart';
import 'package:musagram/pages/search.dart';
import 'package:musagram/pages/timeline.dart';
import 'package:musagram/pages/upload.dart';
final GoogleSignIn googleSignIn = GoogleSignIn();
final usersRef = FirebaseFirestore.instance.collection('users');
final DateTime timestamp = DateTime.now();
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool isAuth = false;
PageController pageController;
int pageIndex = 0;
#override
void initState() {
super.initState();
pageController = PageController();
// Detects when user signed in
googleSignIn.onCurrentUserChanged.listen((account) {
handleSignIn(account);
}, onError: (err) {
print('Error signing in: $err');
});
// Reauthenticate user when app is opened
googleSignIn.signInSilently(suppressErrors: false).then((account) {
handleSignIn(account);
}).catchError((err) {
print('Error signing in: $err');
});
}
handleSignIn(GoogleSignInAccount account) {
if (account != null) {
createUserInFirestore();
setState(() {
isAuth = true;
});
} else {
setState(() {
isAuth = false;
});
}
}
createUserInFirestore() async {
// 1) check if user exists in users collection in database (according to their id)
final GoogleSignInAccount user = googleSignIn.currentUser;
final DocumentSnapshot doc = await usersRef.doc(user.id).get();
if (!doc.exists) {
// 2) if the user doesn't exist, then we want to take them to the create account page
final username = await Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateAccount()));
// 3) get username from create account, use it to make new user document in users collection
usersRef.doc(user.id).set({
"id": user.id,
"username": username,
"photoUrl": user.photoUrl,
"email": user.email,
"displayName": user.displayName,
"bio": "",
"timestamp": timestamp
});
}
}
#override
void dispose() {
pageController.dispose();
super.dispose();
}
login() {
googleSignIn.signIn();
}
logout() {
googleSignIn.signOut();
}
onPageChanged(int pageIndex) {
setState(() {
this.pageIndex = pageIndex;
});
}
onTap(int pageIndex) {
pageController.animateToPage(
pageIndex,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
Scaffold buildAuthScreen() {
return Scaffold(
body: PageView(
children: <Widget>[
// Timeline(),
ElevatedButton(
child: Text('Logout'),
onPressed: logout,
),
ActivityFeed(),
Upload(),
Search(),
Profile(),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: CupertinoTabBar(
currentIndex: pageIndex,
onTap: onTap,
activeColor: Theme.of(context).primaryColor,
items: [
BottomNavigationBarItem(icon: Icon(Icons.whatshot)),
BottomNavigationBarItem(icon: Icon(Icons.notifications_active)),
BottomNavigationBarItem(
icon: Icon(
Icons.photo_camera,
size: 35.0,
),
),
BottomNavigationBarItem(icon: Icon(Icons.search)),
BottomNavigationBarItem(icon: Icon(Icons.account_circle)),
]),
);
// return RaisedButton(
// child: Text('Logout'),
// onPressed: logout,
// );
}
Scaffold buildUnAuthScreen() {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Theme.of(context).accentColor,
Theme.of(context).primaryColor,
],
),
),
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'MusaGram',
style: TextStyle(
fontFamily: "Signatra",
fontSize: 90.0,
color: Colors.white,
),
),
GestureDetector(
onTap: login,
child: Container(
width: 260.0,
height: 60.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/google_signin_button.png',
),
fit: BoxFit.cover,
),
),
),
)
],
),
),
);
}
#override
Widget build(BuildContext context) {
return isAuth ? buildAuthScreen() : buildUnAuthScreen();
}
}
And here's the create_account.dart
import 'package:flutter/material.dart';
import 'package:musagram/widgets/header.dart';
class CreateAccount extends StatefulWidget {
#override
_CreateAccountState createState() => _CreateAccountState();
}
class _CreateAccountState extends State<CreateAccount> {
final _formKey = GlobalKey<FormState>();
String username;
submit() {
_formKey.currentState.save();
Navigator.pop(context, username);
}
#override
Widget build(BuildContext parentContext) {
return Scaffold(
appBar: header(context, titleText: "Set up your profile"),
body: ListView(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 25.0),
child: Center(
child: Text(
"Create a username",
style: TextStyle(fontSize: 25.0),
),
),
),
Padding(
padding: EdgeInsets.all(16.0),
child: Container(
child: Form(
key: _formKey,
child: TextFormField(
onSaved: (val) => username = val,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Username",
labelStyle: TextStyle(fontSize: 15.0),
hintText: "Must be at least 3 characters",
),
),
),
),
),
GestureDetector(
onTap: submit,
child: Container(
height: 50.0,
width: 350.0,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(7.0),
),
child: Center(
child: Text(
"Submit",
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),),
),
),
],
),
),
],
),
);
}
}

method of google sign in looks like this. It will first authenticate the user then it will check is users data present on the firestore. if it's present data will not be overridden and else data will be added.
also at the end you can navigate to your createAccountPage. and you can pass the required values to the constructor. directly map of data or values.
Future<UserCredential> signInWithGoogle() async {
//first trigger authentication
final GoogleSignInAccount googleUser = await GoogleSignIn().signIn();
//obtain the auth details
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
//create a new credentials
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
//saving the user data to shared preferences
SharedPrefsHelper _sharedpref = new SharedPrefsHelper();
// // sign in method
try {
UserCredential firebaseUser =
await FirebaseAuth.instance.signInWithCredential(credential);
if (firebaseUser != null) {
// Check is already sign up
final QuerySnapshot result = await FirebaseFirestore.instance
.collection('users')
.where('id', isEqualTo: firebaseUser.user.uid)
.get();
//userdata to update at firebase
//passing this via constructor to the next page
Map<String, dynamic> userdata = {
'useremail': firebaseUser.user.email,
'displayname': firebaseUser.user.displayName,
'photoUrl': firebaseUser.user.photoURL,
'userid': firebaseUser.user.uid,
};
// navigate . if you don't have context here you can pass this as a paramater to the
method. no issue if you call inside build or init
//userdata is map. just for handling easily
//you can also create simple variables and pass each value to them.
Navigator.pushReplacement(context, CreateUserAccount(userdata));
}
return firebaseUser;
} catch (error) {
print(error);
}
}
Inside the CreateUserAccount
class CreateUserAccount extends StatefulWidget {
final Map<String, dynamic> userdata;
CreateUserAccount(this.userdata);
#override
CreateUserAccountState createState() => CreateUserAccountState();
}
class CreateUserAccountState extends State<CreateUserAccount> {
TextEditingController _textController = new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
child: TextField(
controller: _textController,
),
),
ElevatedButton(
onPressed: () async{
//get the username from textfield
//and update data to firebase
widget.userdata['username'] = _textController.text;
await FirebaseFirestore.instance
.collection('users')
.doc(widget.userdata['userId'])
.set(
widget.userdata,
SetOptions(merge: true),
);
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => TimeLinePage());
},
child: Text("submit"),
),
],
),
));
}
}
Inside the CreateUserAccount we simply added the username in map and added record in firebase. Then you can navigate to the timeline after this.

Related

How to call a function only once while the page is active in flutter

I have a dart page voterhome(like dashboard),at first when I arrive at voterhome it will call the getuserdetails() function and get the adhar of user to pass it to other pages so I can navigate to other pages (like vote,voteregister ..etc)
when I return back to voterhome from other pages it will call the getuserdetails()function again because the function is inside initstate() I don't want this to happen how can I do that
my code :
voterhome.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:election/services/IntoLogin.dart';
import 'package:election/pages/Voter/Vote.dart';
import 'package:election/pages/Voter/VoteRegister.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart';
import '../../services/Auth.dart';
import '../../utils/Constants.dart';
import '../../services/Electioninfo.dart';
import '../../services/VerifyEmail.dart';
class VoterHome extends StatefulWidget {
//getting required parameters to pass on to vote and authorize
final Web3Client ethClient;
final String electionName;
final String electionaddress;
const VoterHome({Key? key, required this.ethClient, required this.electionName, required this.electionaddress}) : super(key: key);
#override
State<VoterHome> createState() => _VoterHomeState();
}
class _VoterHomeState extends State<VoterHome> {
//creating clients
late Client? httpClient;//http client
late Web3Client? ethclient;// eth client
//sign out user
final User? user = Auth().currentuser;
Future<void>signOut()async{
await Auth().signOut();
if(!mounted)return;
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context)=>IntroLogin()), (route) => false);
}
// voters info
var email;
var adhar;
var name;
var phone;
//checking if voter authorized or voted // dont have to do this because we does this on the respected pages
late bool isAuth = false;//if he is authorized
late bool isVoted = false;//if he is voted
Future<void>getUserDetail() async {
try {
final DocumentSnapshot voters = await FirebaseFirestore.instance
.collection('voters')
.doc(user?.email)
.get();
if (voters.data() != null) {
email = voters.get('email');
name = voters.get('name');
phone = voters.get('phone');
adhar = voters.get('adharnum');
print('adhar is $adhar');
}else{
print('cannot find details');
}
showSnackBar(succesdetailsnackSnack);
} catch (e) {
if (kDebugMode) {
print('get check user ::::: $e');
showSnackBar(errordetailsnackSnack);
}
}
}//function to check ends
#override
void initState() {
httpClient = Client();
ethclient = Web3Client(infura_url, httpClient!);
WidgetsBinding.instance.addPostFrameCallback((_) async {
await getUserDetail();
setState(() { });
});
super.initState();
}
#override
Widget build(BuildContext context) {
Map<String,dynamic> voterdata = {'name':name,'adharnum':adhar.toString(),'email':email,};
if(user!.emailVerified){
return Scaffold(
appBar: AppBar(
leading: IconButton(onPressed: () { signOut(); }, icon: const Icon(Icons.logout),),
actions: [IconButton(onPressed:(){setState(() {});}, icon: const Icon(Icons.refresh))],
title: const Text('Voter DASHBOARD'),backgroundColor: Colors.cyan,),
body: SingleChildScrollView(
child: Column(
children: [
Container(
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.only(bottom: 16),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VoteRegister(electionName:widget.electionName,
ethClient: widget.ethClient, electionaddress:widget.electionaddress,adhar:adhar,)));
},
child: Card(borderOnForeground: true,elevation: 4,
child: Column(
children: [
Container(height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
image: const DecorationImage(
image: AssetImage('assets/undraw/electionday.png')))),
Container(decoration: const BoxDecoration(color: Colors.cyan),width: double.infinity,
child: const Center(
child: Text('Register to Vote',style: TextStyle(
fontWeight: FontWeight.bold,fontSize:16,color: Colors.white),),
),
)
],
),
),
),
),
Container(
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.only(bottom: 16),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VoterVote(ethClient:ethclient!,electionName:widget.electionName,
electionaddress:widget.electionaddress ,votermap:voterdata,)));
},
child: Card(borderOnForeground: true,elevation: 4,
child: Column(
children: [
Container(height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
image: const DecorationImage(
image: AssetImage('assets/undraw/upvote.png')))),
Container(decoration: const BoxDecoration(color: Colors.cyan),width: double.infinity,
child: const Center(
child: Text('Vote',style: TextStyle(fontWeight: FontWeight.bold,fontSize:16,color: Colors.white),),
),
)
],
),
),
),
),
Container(
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.only(bottom: 16),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ElectionInfo(ethClient:ethclient!,electionName:widget.electionName,
electionAddress:widget.electionaddress,)));
},
child: Card(borderOnForeground: true,elevation: 4,
child: Column(
children: [
Container(height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
image: const DecorationImage(
image: AssetImage('assets/undraw/electionday.png')))),
Container(decoration: const BoxDecoration(color: Colors.cyan),width: double.infinity,
child: const Center(
child: Text('Election details',style: TextStyle(
fontWeight: FontWeight.bold,fontSize:16,color: Colors.white),),
),
)
],
),
),
),
),
],
),
)
);
}else{
return Scaffold(
appBar:AppBar( ///app bar
backgroundColor: Colors.cyan,
leading: IconButton(
onPressed: () {
signOut();
},
icon: const Icon(Icons.logout_sharp),
),
title: const Text('Verify Voter email'),
actions: [
IconButton(
onPressed: () {
refresh();
},
icon: const Icon(Icons.refresh))
],
),
body: Container(margin: const EdgeInsets.only(top: 56),
child: Center(
child: Column(
children: [
Text('Your Email ${user?.email} is not verified'),
const SizedBox(height: 24,),
ElevatedButton(
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const VerifyEmail()),
(route) => false);
},
child: const Text('Verify Email'))
],
),
),
),
);
}
}
//function to refresh using setstate
void refresh() {
setState(() {});
}
//snackbar
SnackBar errordetailsnackSnack = const SnackBar(content: Text('You are not logged in if you are please check your internet connection'));
SnackBar succesdetailsnackSnack = const SnackBar(content: Text('successfull'));
SnackBar votedSnack = const SnackBar(content: Text('You have already voted'));
SnackBar RegisterSnack = const SnackBar(content: Text('You have already registered'));
// SnackBar errorSnack = const SnackBar(content: Text('Fill all the details'));
// SnackBar datanullSnack = const SnackBar(content: Text('No users registerd yet'));
//function to show snackbar
ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showSnackBar(SnackBar snackBar) {
return ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
vote.dart //when i go to voterhome() from this it again calls the function
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:election/pages/Voter/VoterHome.dart';
import 'package:election/utils/Constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:web3dart/web3dart.dart';
import '../../services/Auth.dart';
import '../../services/functions.dart';
import '../../services/IntoLogin.dart';
class VoterVote extends StatefulWidget {
final Web3Client ethClient;
final String electionName;
final String electionaddress;
final votermap;
const VoterVote({Key? key, required this.ethClient, required this.electionName, required this.electionaddress, this.votermap,}) : super(key: key);
#override
State<VoterVote> createState() => _VoterVoteState();
}
class _VoterVoteState extends State<VoterVote> {
final User? user = Auth().currentuser;//fi// rebase auth current user initialization
//sign out user function
Future<void> signOut() async {
if (!mounted) return;
await Auth().signOut();
if (!mounted) return;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => IntroLogin()),
(route) => false);
}
//checking if the voter is already voted
late bool isAuth = false;
late bool isVoted = false;
Future<void>getUserDetail() async {
var voterdetails = widget.votermap;
try {
final DocumentSnapshot voters = await FirebaseFirestore.instance
.collection('Election')
.doc(widget.electionName).collection('voterAuth').doc(voterdetails['adharnum'])
.get();
if (voters.data() != null) {
isAuth = voters.get('isAuth');
isVoted = voters.get('isVoted');
}else{
isAuth = false;
isVoted= false;
print('cannot find details');
}
} catch (e) {
if (kDebugMode) {
print('get check user ::::: $e');
}
}
}//function to check ends
TextEditingController privatekeyController = TextEditingController();
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await getUserDetail();
setState(() { });
});
super.initState();
}
#override
Widget build(BuildContext context) {
if(isVoted== true && isAuth == true){
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.cyan,
leading: IconButton(onPressed: (){signOut();},icon: const Icon(Icons.logout_sharp),),
title:const Text('Vote'),
actions: [
IconButton(onPressed:(){
refresh();
}, icon: const Icon(Icons.refresh))
],
),
body: const Center(child: Text('you have already voted sir'),),
);
}else if(isVoted == false&&isAuth == true){
return Scaffold(
appBar:AppBar(
backgroundColor: Colors.cyan,
leading: IconButton(onPressed: (){signOut();},icon: const Icon(Icons.logout_sharp),),
title:const Text('Vote'),
actions: [
IconButton(onPressed:(){
refresh();
}, icon: const Icon(Icons.refresh))
],
),
body: Container(margin:const EdgeInsets.only(bottom: 56,top: 24),alignment: Alignment.topCenter,
child:SingleChildScrollView(
child: Column(
children: [
Center(
child: SelectableText("$voter_private_key && $voter_key2 && $voter_key3")
),
const SizedBox(height: 24,),
Container(padding: const EdgeInsets.all(16),
child: TextField(
controller: privatekeyController,
decoration:
const InputDecoration(hintText: 'Private key for voting',border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(8))))),
),
const SizedBox(height: 24,),
SingleChildScrollView(
child: StreamBuilder<List>(stream:getCandidatesNum(widget.ethClient,widget.electionaddress).asStream(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return Column(
children: [
for (int i = 0; i < snapshot.data![0].toInt(); i++)
FutureBuilder<List>(
future: candidateInfo(i, widget.ethClient,widget.electionaddress),
builder: (context, candidatesnapshot) {
if (candidatesnapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return Card( //card to represent the candidate
color: Colors.cyan,
child: SizedBox(height: 100,
child: Center(
child: ListTile(
title: Text('Name: ${candidatesnapshot.data![0][0]}'),
subtitle: Text('Votes: ${candidatesnapshot.data![0][1]}'),
leading: ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 90,
minWidth: 90,
maxHeight: 100,
maxWidth: 100,
),
child:const Image(image: AssetImage('assets/undraw/electionday.png')),
),
trailing: ElevatedButton(
onPressed: ()async {
try{
await vote(i,widget.ethClient,privatekeyController.text,widget.electionaddress);
await registerAuth();
gotoDashboard();
showSnackBar(succesdetailsnackSnack);
}catch(e){
if (kDebugMode) {
print(e);
}
showSnackBar(errordetailsnackSnack);
gotoDashboard();
}
}, child: const Text('Vote'),),
),
),
),
);
}
})
],
);
}
},
),
),
],
),
),
),
);
}else{
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.cyan,
leading: IconButton(onPressed: (){signOut();},icon: const Icon(Icons.logout_sharp),),
title:const Text('Vote'),
actions: [
IconButton(onPressed:(){
refresh();
}, icon: const Icon(Icons.refresh))
],
),
body: const Center(child: Text('you are not authorized please authorize first'),),
);
}
}
//snackbar
SnackBar errordetailsnackSnack = const SnackBar(content: Text(' already voted or please check your internet connection'));
SnackBar succesdetailsnackSnack = const SnackBar(content: Text('successfull'));
SnackBar voterSnack = const SnackBar(content: Text('you are a voter logout from voter account'));
SnackBar adminSnack = const SnackBar(content: Text('you are an admin logout from Admin account'));
// SnackBar errorSnack = const SnackBar(content: Text('Fill all the details'));
// SnackBar datanullSnack = const SnackBar(content: Text('No users registerd yet'));
//function to show snackbar
ScaffoldFeatureController<SnackBar, SnackBarClosedReason> showSnackBar(SnackBar snackBar) {
return ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void refresh() {
setState(() {});
}
Future<void> registerAuth() async {
var voterdetails = widget.votermap;
try {
await FirebaseFirestore.instance.collection('Election').doc(widget.electionName).collection('voterAuth').doc(voterdetails['adharnum']).update({'isVoted':true});
print('updated data aaaaaaaaaaaaaaa');
} catch (e) {
if (kDebugMode) {
print('failed to register on firebase $e');
}
}
}
void gotoDashboard(){
Navigator.pushAndRemoveUntil(context,MaterialPageRoute(builder:(context)=>VoterHome(ethClient: widget.ethClient,
electionName: widget.electionName, electionaddress: widget.electionaddress)), (route) => false);
}
}
One way to achieve what you want is by making your page retain its state.
Try this code
You have to add with AutomaticKeepAliveClientMixin to the screen like in the snippet below.
Override this #override bool get wantKeepAlive => true;.
Inside build method, add this super.build(context);.
class _TestScreen extends State<TestScreen> with AutomaticKeepAliveClientMixin<TestScreen> {
#override
bool get wantKeepAlive => true;
Widget build(BuildContext context) {
super.build(context);
return Scaffold();
}
}
After doing this, your page will not call initState() everytime that page is loaded.
When you navigate from VoteHome page to VoteRegister page, you use the push method. The push method returns a Future object. You can use the then method of Future to execute your code after VoteRegister was popped from the navigation stack or in other words the user pressed back button in appbar.
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => VoteRegister(electionName:widget.electionName,ethClient: widget.ethClient, electionaddress:widget.electionaddress,adhar:adhar,)))
.then((value) {
// you can do what you need here
// setState etc.
// also reload your data here
});

State not triggering while clicking login button

Every thing is working fine except that the page is not navigating while I press login button. The user is logged in and The screen is changing once I reload it. But the screen has to change when I click the login button. I used the setState fuction But still not working.Please help me solve this. Thanks in advance.
This is my root page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
class Root extends StatefulWidget {
const Root({Key? key}) : super(key: key);
#override
State<Root> createState() => _RootState();
}
enum AuthState { signedIn, signedOut }
class _RootState extends State<Root> {
AuthState _authState = AuthState.signedOut;
AuthService auth = AuthService();
String authuser = "ghnfgjy";
void signOut() async {
await auth.signOut();
setState(() {
_authState = AuthState.signedOut;
});
}
void signIn() async {
setState(() {
_authState = AuthState.signedIn;
});
}
#override
void initState() {
super.initState();
auth.currentUser().then((user) {
print("check check $user ");
setState(() {
_authState = user == null ? AuthState.signedOut : AuthState.signedIn;
});
});
}
#override
Widget build(BuildContext context) {
if (_authState == AuthState.signedOut) {
return Login();
} else {
return Scaffold(
body: Center(
child: Column(
children: [
SizedBox(
height: 69,
),
Text("Helllloooooooo $authuser"),
SizedBox(
height: 45,
),
FlatButton(
onPressed: () {
signOut();
},
child: Text("Sign out"))
],
),
));
}
}
}
This is my login.dart page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
import 'package:login/share/constant.dart';
class Login extends StatefulWidget {
const Login({Key? key}) : super(key: key);
#override
_LoginState createState() => _LoginState();
}
enum FormType {
login,
register,
}
class _LoginState extends State<Login> {
dynamic _email;
dynamic _password;
final formkey = GlobalKey<FormState>();
FormType _formType = FormType.login;
dynamic result;
AuthService auth = AuthService();
bool validateandsave() {
final form = formkey.currentState;
if (form!.validate()) {
form.save();
print('form is valid');
print('$_email $_password');
return true;
} else {
print('form is not valid');
return false;
}
}
Future validateandsumit() async {
if (validateandsave()) {
if (_formType == FormType.register) {
auth.register(_email, _password);
setState(() {
_formType = FormType.login;
});
} else {
auth.signIn(_email, _password);
}
}
}
void moveToRegister() {
formkey.currentState!.reset();
setState(() {
_formType = FormType.register;
});
}
void moveToLogin() {
formkey.currentState!.reset();
setState(() {
_formType = FormType.login;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Colors.blueAccent,
Colors.purple,
],
),
),
padding: EdgeInsets.all(16),
child: Form(
key: formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: openText() + inputFields() + buttons(),
),
),
),
);
}
List<Widget> openText() {
if (_formType == FormType.register) {
return [
Text(
'Please Register to continue',
style: TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
SizedBox(
height: 40,
),
];
} else {
return [
Text('Please Login to continue',
style: TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
SizedBox(
height: 40,
),
];
}
}
List<Widget> inputFields() {
return [
TextFormField(
decoration: inputDecoration.copyWith(
labelText: 'Email Address',
),
style: TextStyle(color: Colors.black),
validator: (val) => val!.isEmpty ? 'Enter the email address' : null,
onSaved: (val) => _email = val),
SizedBox(
height: 20,
),
TextFormField(
obscureText: true,
decoration: inputDecoration.copyWith(
labelText: 'Password',
),
style: TextStyle(color: Colors.black),
validator: (val) => val!.isEmpty ? 'Enter the password' : null,
onSaved: (val) => _password = val),
SizedBox(
height: 60,
),
];
}
List<Widget> buttons() {
if (_formType == FormType.register) {
return [
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: validateandsumit,
child: Text(
'Register',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
SizedBox(
height: 20,
),
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: moveToLogin,
child: Text(
'Have an account? Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
];
} else {
return [
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: validateandsumit,
child: Text(
'Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
SizedBox(
height: 20,
),
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: moveToRegister,
child: Text(
'Register',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
];
}
}
}
This is my authservice file
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class AuthService {
FirebaseAuth _auth = FirebaseAuth.instance;
//Stream <User>? get authStateChanges => _auth.authStateChanges();
Stream<User?> get authStateChanges => _auth.authStateChanges();
CollectionReference users = FirebaseFirestore.instance.collection('users');
late User user;
//register in with email and password
Future register(email, password) async {
try {
UserCredential userCredential = await _auth
.createUserWithEmailAndPassword(email: email, password: password);
user = userCredential.user!;
print('Registered ${user.uid}');
var userdata = {
'email': email,
'password': password,
'role': 'user',
};
users.doc(user.uid).get().then((doc) {
if (doc.exists) {
doc.reference.update(userdata);
} else {
users.doc(user.uid).set(userdata);
}
});
} catch (e) {
print(e);
}
}
//sign in with email and password
Future signIn(email, password) async {
try {
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email, password: password);
user = userCredential.user!;
print('logged in ${user.uid}');
var userdata = {
'email': email,
'password': password,
'role': 'user',
};
users.doc(user.uid).get().then((doc) {
if (doc.exists) {
doc.reference.update(userdata);
} else {
users.doc(user.uid).set(userdata);
}
});
} catch (e) {
print(e);
}
}
Future currentUser() async {
try {
User user = await _auth.currentUser!;
return user.uid;
} catch (e) {
print(e);
}
}
//sign out
Future signOut() async {
try {
await _auth.signOut();
} catch (e) {
print(e);
}
}
}
I think the problem is that the build function in _RootState does not rebuild when you login.
One possible solution is to use StreamBuilder to rebuild whenever auth changes (login/logout).
Add this function to your AuthService class:
class AuthService {
final _auth = FirebaseAuth.instance;
...
Stream<User?> authStream() => _auth.authStateChanges(); // add this line
}
Then write your build function (in _RootState) as below:
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: auth.authStream(), // auth here is AuthService.
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
// StreamBuilder will automatically rebuild anytime you log in or log
// logout. No need for your initState or signout & signin functions.
if (snapshot.hasError) return const Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.data == null) return Login();
// snapshot.data is User.
// print(snapshot.data?.email); print(snapshot.data?.displayName);
return Scaffold(
body: Center(
child: Column(
children: [
const SizedBox(height: 69),
Text('Hello ${snapshot.data?.email}'),
const SizedBox(height: 45),
FlatButton(
onPressed: () async {
// no need to call sign out here.
await auth.signOut();
},
child: const Text('Sign out'),
)
],
),
),
);
},
);
// you can delete your initState, signin and signout functions in _RootState

Everything matches but I still get "Bad state: field does not exist within the DocumentSnapshotPlatform"

So i'm pretty lost trying to get my app to fetch not only the desired text from firestore but also the image i placed there. I know the error "Bad state: field does not exist within the DocumentSnapshotPlatform" implies that either I'm missing field or there's something wrong with at least one of those fields. There's only four things I'm trying to fetch from firestore "imgUrl, title, desc, organizer" i have checked for spelling and order and i can't figure it out. I have also checked firestore to see if the order and spelling was correct and i dont see what's the issue. Please help, Thank you so much in advanced.
////////////////////////////// News Class Starts\\\\\\\\\\\\\\
import 'package:myfuji/screens/CrudMethods.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'CrudMethods.dart';
import 'add_blog.dart';
class News extends StatefulWidget {
#override
_NewsState createState() => _NewsState();
}
class _NewsState extends State<News> {
CrudMethods crudMethods = CrudMethods();
late QuerySnapshot blogSnapshot;
#override
void initState() {
crudMethods.getData().then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList() {
return ListView.builder(
padding: const EdgeInsets.only(top: 24),
itemCount: blogSnapshot.docs.length,
itemBuilder: (context, index) {
return BlogTile(
organizer: blogSnapshot.docs[index].get('Organizer'),
desc: blogSnapshot.docs[index].get('desc'),
imgUrl: blogSnapshot.docs[index].get('imgUrl'),
title: blogSnapshot.docs[index].get('title'),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Events"),
),
body: Container(
child: blogSnapshot != null
? blogsList()
: const Center(
child: CircularProgressIndicator(),
)),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddBlog()));
},
),
);
}
}
class BlogTile extends StatelessWidget {
final String imgUrl, title, desc, organizer;
const BlogTile(
{required this.organizer,
required this.desc,
required this.imgUrl,
required this.title});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 24, right: 16, left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Image.network(
imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
height: 200,
),
),
),
const SizedBox(height: 16),
Text(
title,
style: const TextStyle(fontSize: 17),
),
const SizedBox(height: 2),
Text(
'$desc - By $organizer',
style: const TextStyle(fontSize: 14),
)
],
),
);
}
}
///////////////////////////////////////////// class AddBlog begins here \\\\\\\\\\\
import 'dart:io';
import 'package:myfuji/screens/CrudMethods.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:random_string/random_string.dart';
class AddBlog extends StatefulWidget {
#override
_AddBlogState createState() => _AddBlogState();
}
class _AddBlogState extends State<AddBlog> {
//
late File selectedImage;
final picker = ImagePicker();
bool isLoading = false;
CrudMethods crudMethods = new CrudMethods();
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
selectedImage = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
Future<void> uploadBlog() async {
if (selectedImage != null) {
// upload the image
setState(() {
isLoading = true;
});
Reference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child("events/")
.child("${randomAlphaNumeric(9)}.jpg");
final UploadTask task = firebaseStorageRef.putFile(selectedImage);
var imageUrl;
await task.whenComplete(() async {
try {
imageUrl = await firebaseStorageRef.getDownloadURL();
} catch (onError) {
print("Error");
}
print(imageUrl);
});
// print(downloadUrl);
Map<String, dynamic> blogData = {
"imgUrl": imageUrl,
"Organizer": authorTextEditingController.text,
"title": titleTextEditingController.text,
"desc": descTextEditingController.text
};
crudMethods.addData(blogData).then((value) {
setState(() {
isLoading = false;
});
Navigator.pop(context);
});
// upload the blog info
}
}
//
TextEditingController titleTextEditingController =
new TextEditingController();
TextEditingController descTextEditingController = new TextEditingController();
TextEditingController authorTextEditingController =
new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Create Blog"),
actions: [
GestureDetector(
onTap: () {
uploadBlog();
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.file_upload)),
)
],
),
body: isLoading
? Container(
child: Center(
child: CircularProgressIndicator(),
))
: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
GestureDetector(
onTap: () {
getImage();
},
child: selectedImage != null
? Container(
height: 150,
margin: EdgeInsets.symmetric(vertical: 24),
width: MediaQuery.of(context).size.width,
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(8)),
child: Image.file(
selectedImage,
fit: BoxFit.cover,
),
),
)
: Container(
height: 150,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius:
BorderRadius.all(Radius.circular(8))),
margin: EdgeInsets.symmetric(vertical: 24),
width: MediaQuery.of(context).size.width,
child: Icon(
Icons.camera_alt,
color: Colors.white,
),
),
),
TextField(
controller: titleTextEditingController,
decoration: InputDecoration(hintText: "enter title"),
),
TextField(
controller: descTextEditingController,
decoration: InputDecoration(hintText: "enter desc"),
),
TextField(
controller: authorTextEditingController,
decoration:
InputDecoration(hintText: "enter author name"),
),
],
)),
),
);
}
}
///////////////////////////////////////////// class CrudMethods begins here \\\\\\\\\\\
import 'package:cloud_firestore/cloud_firestore.dart';
class CrudMethods {
Future<void> addData(blogData) async {
print(blogData);
FirebaseFirestore.instance
.collection("events/")
.add(blogData)
.then((value) => print(value))
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance.collection("events/").get();
}
}
/////////////////////////////////////////////firestore\\\\\\\\\\\\\
This maybe related to having “/“ after collection name here:
.collection("events/")
Instead try this:
.collection("events")
Also it may be best to change child to collection here:
Reference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child("events/")
Try to see if you get data back by running this:
itemCount: blogSnapshot.docs.length,
itemBuilder: (context, index) {
QuerySnapshot snap = blogSnapshot.data; // Snapshot
List<DocumentSnapshot> items = snap.documents; // List of Documents
DocumentSnapshot item = items[index]; Specific Document
return BlogTile(
organizer: item.data['Organizer'],
desc: item.data['desc'],
imgUrl: item.data['imgUrl'],
title: item.data['title'],
);
},
I think you need to utilize a QueryDocumentSnapshot to access the data in the document.

Issue with Flutter retrieving data from Firestore (Authenticating different users types from collection)

I am having an issue with trying to route different users to different views in flutter.
I will attach my code below. I have authentication working and routing to the main view. I am now trying to query a Users table in my database (screenshot attached). I want to check by email that the user isStudent and route to menu page. if not a student then route to a separate page.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_tex/flutter_tex.dart';
import 'package:maths_for_computing/components/roundedButton.dart';
import 'package:maths_for_computing/screens/chat_screen.dart';
import 'package:flutter/material.dart';
import 'package:maths_for_computing/components/roundedButton.dart';
import 'package:maths_for_computing/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:maths_for_computing/screens/latex_example.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'chat_screen.dart';
import 'menu_student.dart';
final GlobalKey<ScaffoldState> _key = GlobalKey(); // Create a key
final _firestore = FirebaseFirestore.instance;
class LoginScreen extends StatefulWidget {
static const String id = 'login_screen';
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
bool showSpinner = false;
final _auth = FirebaseAuth.instance;
late String email;
late String password;
Future getUsers(String email) async {
final users = await _firestore
.collection('Users')
.where('email', isEqualTo: email)
.get();
for (var user in users.docs) {
print(user.get("email"));
//return user.get("isStudent") as String;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),
const SizedBox(
height: 48.0,
),
TextField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
//Do something with the user input.
email = value;
},
decoration:
kTextFieldDecoration.copyWith(hintText: 'Enter your email'),
),
const SizedBox(
height: 8.0,
),
TextField(
obscureText: true,
textAlign: TextAlign.center,
onChanged: (value) {
//Do something with the user input.
password = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your password'),
),
const SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Log In',
colour: Colors.lightBlueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final user = await _auth.signInWithEmailAndPassword(
email: email, password: password);
String userType = getUsers(email) ;
// getUsers(email);
if (user != null) {
if (isStudent == 'N') {
Navigator.pushNamed(context, ChatScreen.id);
} else {
Navigator.pushNamed(context, MenuScreen.id);
}
}
} catch (e) {
print(e);
}
setState(() {
showSpinner = false;
});
},
),
],
),
),
),
);
}
}
Any help or advice on this or best practice would be much appreciated. This is a small app so trying to stay away from Custom claims as I am very new to flutter and don't want to overcomplicate things.
Many thanks
E
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_tex/flutter_tex.dart';
import 'package:maths_for_computing/components/roundedButton.dart';
import 'package:maths_for_computing/screens/chat_screen.dart';
import 'package:flutter/material.dart';
import 'package:maths_for_computing/components/roundedButton.dart';
import 'package:maths_for_computing/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:maths_for_computing/screens/latex_example.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'chat_screen.dart';
import 'menu_student.dart';
final GlobalKey<ScaffoldState> _key = GlobalKey(); // Create a key
final _firestore = FirebaseFirestore.instance;
class LoginScreen extends StatefulWidget {
static const String id = 'login_screen';
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
bool showSpinner = false;
final _auth = FirebaseAuth.instance;
late String email;
late String password;
Future getUsers(String email) async {
final users = await _firestore
.collection('Users')
.where('email', isEqualTo: email)
.get();
for (var user in users.docs) {
print(user.get("email"));
//return user.get("isStudent") as String;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),
const SizedBox(
height: 48.0,
),
TextField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
//Do something with the user input.
email = value;
},
decoration:
kTextFieldDecoration.copyWith(hintText: 'Enter your email'),
),
const SizedBox(
height: 8.0,
),
TextField(
obscureText: true,
textAlign: TextAlign.center,
onChanged: (value) {
//Do something with the user input.
password = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your password'),
),
const SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Log In',
colour: Colors.lightBlueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final _auth = FirebaseAuth.instance;
await _auth.signInWithEmailAndPassword(email: email, password: password).then((uid) => {
FirebaseFirestore.instance.collection("users").doc(uid.user.uid).get().then((value) {
Map<dynamic, dynamic> currentUser = value.data();
if(currentUser['isStudent']=="N") {
Navigator.pushNamed(context, ChatScreen.id);
}
else {
Navigator.pushNamed(context, MenuScreen.id);
}
}),
});
} catch (e) {
print(e);
}
setState(() {
showSpinner = false;
});
},
),
],
),
),
),
);
}
}

Flutter pressing back button pops up previous snackBar from Login page again

I have a LoginPage in Flutter. After login, it shows a small snackbar with "success" or "failure.." if password is wrong, then it navigates to the todo list.
When I now press the "back" button on an Android device, it navigates back to the login screen. However, there is still the snackbar popping up and saying "Login successful, redirecting..", and also, my textfields are not emptied and still have the values from the first login, why? That should not happen, but I cannot figure out why that is... here is my code:
import 'package:flutter/material.dart';
import 'package:todoey_flutter/components/rounded_button.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todoey_flutter/util/file_handler.dart';
import 'package:provider/provider.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
String username;
String password;
String hashedPW;
// Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
var _nameController = TextEditingController();
var _pwController = TextEditingController();
#override
Widget build(BuildContext context) {
CryptOid cy = Provider.of<CryptOid>(context, listen: true);
FileHandler fh = Provider.of<FileHandler>(context, listen: true);
return Scaffold(
backgroundColor: Colors.white,
body: Builder(
builder: (BuildContext scaffoldBuildContext) {
return Container(
//inAsyncCall: isSpinning,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 34.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
/*
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),*/
SizedBox(
height: 48.0,
),
TextField(
controller: _nameController,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
username = value.toLowerCase();
},
decoration: InputDecoration(
hintText: 'Enter your username',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: _pwController,
obscureText: true,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
password = value;
},
decoration: InputDecoration(
hintText: 'Enter your password',
),
),
SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Login',
colour: Colors.lightBlueAccent,
onPressed: () async {
Scaffold.of(scaffoldBuildContext).removeCurrentSnackBar();
print("user: $username, pw: $password");
if ((username != '' && username != null) && (password != '' && password != null)) {
SharedPreferences prefs = await SharedPreferences.getInstance();
// cy.test();
if ((username != '' && username != null) && prefs.containsKey(username)) {
hashedPW = prefs.getString(username);
bool decryptPW = await cy.deHash(hashedPW, password);
if (decryptPW) {
cy.setUsername(username);
fh.setUser(username);
prefs.setString('activeUser', username);
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("Login successful! redirecting.."),
),
);
Navigator.pushNamed(context, 'taskScreen');
} else {
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("Wrong password for user $username!"),
),
);
}
} else {
String hashedPW = await cy.hashPW(password);
prefs.setString('activeUser', username);
prefs.setString(username, hashedPW);
cy.setUsername(username);
fh.setUser(username);
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("User created successful! redirecting.."),
),
);
Navigator.pushNamed(context, 'taskScreen');
//prefs.setString(username, hashedPW);
}
_nameController.clear();
_pwController.clear();
} else {
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("User and password may not be empty.."),
),
);
_nameController.clear();
_pwController.clear();
return;
}
},
),
],
),
),
);
},
),
);
}
}
You should create a ScaffoldState GlobalKey then assign the to the scaffold.
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Container());
}
The use the key to showSnackBar
void _showInSnackBar(String value) {
_scaffoldKey.currentState
.showSnackBar(new SnackBar(content: new Text(value)));
}
So your full code would look like this:
import 'package:flutter/material.dart';
import 'package:todoey_flutter/components/rounded_button.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todoey_flutter/util/file_handler.dart';
import 'package:provider/provider.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String username;
String password;
String hashedPW;
// Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
var _nameController = TextEditingController();
var _pwController = TextEditingController();
#override
Widget build(BuildContext context) {
CryptOid cy = Provider.of<CryptOid>(context, listen: true);
FileHandler fh = Provider.of<FileHandler>(context, listen: true);
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
body: Builder(
builder: (BuildContext scaffoldBuildContext) {
return Container(
//inAsyncCall: isSpinning,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 34.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
/*
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),*/
SizedBox(
height: 48.0,
),
TextField(
controller: _nameController,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
username = value.toLowerCase();
},
decoration: InputDecoration(
hintText: 'Enter your username',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: _pwController,
obscureText: true,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
password = value;
},
decoration: InputDecoration(
hintText: 'Enter your password',
),
),
SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Login',
colour: Colors.lightBlueAccent,
onPressed: () async {
_scaffoldKey.currentState.removeCurrentSnackBar();
print("user: $username, pw: $password");
if ((username != '' && username != null) &&
(password != '' && password != null)) {
SharedPreferences prefs =
await SharedPreferences.getInstance();
// cy.test();
if ((username != '' && username != null) &&
prefs.containsKey(username)) {
hashedPW = prefs.getString(username);
bool decryptPW = await cy.deHash(hashedPW, password);
if (decryptPW) {
cy.setUsername(username);
fh.setUser(username);
prefs.setString('activeUser', username);
_showInSnackBar("Login successful! redirecting..");
Navigator.pushNamed(context, 'taskScreen');
} else {
_showInSnackBar(
"Wrong password for user $username!");
}
} else {
String hashedPW = await cy.hashPW(password);
prefs.setString('activeUser', username);
prefs.setString(username, hashedPW);
cy.setUsername(username);
fh.setUser(username);
_showInSnackBar(
"User created successful! redirecting..");
Navigator.pushNamed(context, 'taskScreen');
//prefs.setString(username, hashedPW);
}
_nameController.clear();
_pwController.clear();
} else {
_showInSnackBar("User and password may not be empty..");
_nameController.clear();
_pwController.clear();
return;
}
},
),
],
),
),
);
},
),
);
}
void _showInSnackBar(String value) {
_scaffoldKey.currentState
.showSnackBar(new SnackBar(content: new Text(value)));
}
}