onTap keeps getting called again and again - flutter

I had an onTap function for an InkWell with the following code:
onTap: () async {
setState(() {
hasPressedLogIn = true;
print(hasPressedLogIn);
});
var loginData = await lib.login(username, password);
print('got loginData');
setState(
() {
if (password == '' && username == '' ||
password == '' ||
username == '') {
loginText = 'username or password empty';
} else {
utils.saveLoginData(username, password, loginData!.token.session,
loginData.token.refresh);
print('saved login data');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(
token: loginData.token.session,
),
),
);
}
},
);
},
Now, the code executes perfectly for the first time and the app successfully navigates to the next page without any error, however the onTap function doesn't stop despite having done it's job resulting in the rate limit being exceeded. The function seems to loop around the line
var loginData = await lib.login(username, password);
which later on exceeds the login attempt limit. How am I supposed to stop these unnecessary calls?

Change it to this:
onTap: () async {
if (password == '' && username == '' || password == '' || username == '') {
setState(() {
loginText = 'username or password empty';
});
} else {
setState(() {
hasPressedLogIn = true;
});
print(hasPressedLogIn);
utils.saveLoginData(
username,
password,
loginData!.token.session,
loginData.token.refresh);
print('saved login data');
var loginData = await lib.login(username, password);
print('got loginData');
Navigator.push(context, MaterialPageRoute(
builder: (context) => HomePage( token: loginData.token.session,),),);}
},

onTap: () async {
if(hasPressedLogIn == false){
setState(() {
hasPressedLogIn = true;
print(hasPressedLogIn);
});
var loginData =
await lib.login(username, password);
print('got loginData');
setState(
() {
if (password == '' && username == '' ||
password == '' ||
username == '') {
loginText = 'username or password empty';
} else {
utils.saveLoginData(
username,
password,
loginData!.token.session,
loginData.token.refresh);
print('saved login data');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(
token: loginData.token.session,
),
),
);
}
},
);}
else{
Future.delayed(const Duration(milliseconds: 1500), () {
//after a limited duration you will be able to tap it again
setState(() {
hasPressedLogIn = false;
print(hasPressedLogIn);
});
});
}
},

Related

how to create redirect to login if not authorized in flutter

how to make if the user's token is expired or not authorized it will be redirected to the login page.
I have a problem when I login, if the user token is expired, it should be redirected to the login page, but in this case it doesn't return to the login page, instead it gives an 'exception' error message, is there a code I missed.
Thank you.
Future<User?> login(String nim, String password) async {
String url = Constant.baseURL;
try {
var body = {
'username': nim,
'password': password,
};
var response = await http.post(
Uri.parse(
'$url/login_mhs',
),
body: body,
);
if (response.statusCode == 200) {
final token = jsonDecode(response.body)['data']['access_token'];
await UtilSharedPreferences.setToken(token);
print(token);
print(await UtilSharedPreferences.getToken());
return User.fromJson(jsonDecode(response.body));
} else {
return null;
}
} catch (e) {
print(e);
throw Exception();
}
}
and this when doing get data
Future<UserBiodata> getDataMahasiswa() async {
String url = Constant.baseURL;
String token = await UtilSharedPreferences.getToken();
final response = await http.get(
Uri.parse(
'$url/auth/mhs_siakad/biodata',
),
headers: {
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 200) {
return UserBiodata.fromJson(jsonDecode(response.body));
} else {
throw Exception();
}
}
this when calling it in the widget
TextButton(
onPressed: () async {
final prefs =
await SharedPreferences.getInstance();
prefs.setString(Constant.token, '');
if (nimController.text.isEmpty ||
passwordController.text.isEmpty) {
showError('NIM tidak sesuai');
} else {
setState(() {
isLoading = true;
});
User? user = await Provider.of<Services>(
context,
listen: false)
.login(nimController.text,
passwordController.text);
setState(() {
isLoading = false;
});
if (user == null) {
showError('NIM/Password tidak sesuai');
} else {
userProvider.user = user;
Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(route) => false,
);
}
}
},
style: TextButton.styleFrom(
backgroundColor: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(66),
),
),
child: Text(
"Login",
style: boldButton,
),
),
this is the result when I have a user whose token is expired or not authorized the result is like this
Use another if else condition (nested into your else of the event) like below:
if (user == null) {
showError('NIM/Password tidak sesuai');
} else {
if (token_is_not_found_equals_true){
Navigator.pushNamedAndRemoveUntil(
context,
'/login',
(route) => false,
);
}
else {
userProvider.user = user;
Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(route) => false,
);
}
}
The way I handle is using the package flutter_modular, there you have a feature call Route Guard. You check details in it's documentation. It's very easy to understand and implement.
I think it's the cleanest way to handle users unauthorized users.

User gets internaly loged in, but UI does not change

So I have a problem with my app's login. When a user enters correct login data, he gets recognized on the firebase console, debug console also shows the user now exists, but the screen (which is controlled by StreamBuilder) does not change.
home: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, AsyncSnapshot<User?> userSnapshot) {
if (userSnapshot.connectionState ==
ConnectionState.waiting) {
return LoadingSpinner();
}
if (userSnapshot.hasData) {
return MainScreen();
}
return AuthScreen();
}),
//.............
void authUser(String email, String password, bool isLogin,
String username) async {
setState(() {
isLoading = true;
});
UserCredential userCreadencial;
FocusScope.of(context).unfocus();
if (isLogin == false) {
userCreadencial = await firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} else {
userCreadencial = await firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
}
FirebaseFirestore.instance
.collection('users_info')
.orderBy(userCreadencial.user!.uid, descending: true);
await FirebaseFirestore.instance
.collection('users_info')
.doc(userCreadencial.user!.uid)
.set({
'email': userCreadencial.user!.email,
'username': username,
});
setState(() {
isLoading = false;
});
Debug console log:
W/System (14293): Ignoring header X-Firebase-Locale because its value
was null. 2 I/System.out(14293): (HTTPLog)-Static: isSBSettingEnabled
false D/FirebaseAuth(14293): Notifying id token listeners about user (
55epaBG5sGYJ7YWq1QZosJqrajT2 ).
I faced a simillar problem recently. I have found a workaround for this problem. You can use "whenComplete" function & a condition if the current user uid is not empty to navigate to the route after the signIn or login is successful. This is how your code might look like:
void authUser(String email, String password, bool isLogin,
String username) async {
setState(() {
isLoading = true;
});
UserCredential userCreadencial;
FocusScope.of(context).unfocus();
//to get current uid
String get currentUserUid => FirebaseAuth.instance.currentUser?.uid ?? '';
if (isLogin == false) {
//add whenComplete & check if the current uid is not empty.
userCreadencial = await firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
).whenComplete(
() => currentUserUid.isNotEmpty
? Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => MainScreen(),
),
(route) => false,
):null,
);;
} else {
//add whenComplete.
userCreadencial = await firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
).whenComplete(
() => currentUserUid.isNotEmpty
? Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => MainScreen(),
),
(route) => false,
): null,
);;
}
FirebaseFirestore.instance
.collection('users_info')
.orderBy(userCreadencial.user!.uid, descending: true);
await FirebaseFirestore.instance
.collection('users_info')
.doc(userCreadencial.user!.uid)
.set({
'email': userCreadencial.user!.email,
'username': username,
});
setState(() {
isLoading = false;
});
you should also wrap your signIn and createUser function with try catch blocks

How to send a verification email on registerUsingEmailPassword() in flutter

I wan't when a user clicks sign up button an email verification is sent. So far with my code on signup an email verification is sent but user can't navigate to the next page (CircularProgressIndicator keeps on loading)
Here is my code
onPressed: () async {
if (_regFormKey.currentState!.validate()) {
setState(() {
_isProcessing = true;
});
User? user = await FireAuth.registerUsingEmailPassword(
name: nameController,
email: _emailController.text,
password: _passwordController.text,
);
if (user != null) {
bool EmailSent = user.sendEmailVerification() as bool;
//I think something is wrong here
if (EmailSent) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => ProfilePage(user: user),
),
ModalRoute.withName('/'),
); }
} else{
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(' Account exists or Network problems'),
backgroundColor: Colors.red,
));}
setState(() {
_isProcessing = false;
});
}}
sendEmailVerification() returns a Future<void> so EmailSent is not going to get set. You should await the verification call in a try...catch to handle the response.
More like this:
if (user != null) {
try {
await user.sendEmailVerification();
/// sent successfully
// TODO: put your navigation here
} catch (e) {
/// error sending verification
// TODO: show snackbar
// TODO: set _isProcessing to false
}
}

Flutter field has not been initialized

i have a bool that i set to true if the account datas is right but my bool is set to late and it doesnt works
My Model:
bool _result = false;
Future login(String username, String password) async {
var url = "http://192.168.178.75/flutterconn/login.php";
var response = await http.post(Uri.parse(url), body: {
"username": username,
"password": password,
});
var data = await json.decode(response.body);
if (data == "success") {
setResult(true);
Fluttertoast.showToast(msg: "Erfolgreich Eingeloggt",toastLength: Toast.LENGTH_SHORT,gravity: ToastGravity.CENTER,fontSize: 16.0);
}else {
Fluttertoast.showToast(msg: "Nicht Eingeloggt",toastLength: Toast.LENGTH_SHORT,gravity: ToastGravity.CENTER,fontSize: 16.0);
}
//print(_result);
notifyListeners();
}
Future setResult(bool rs) async{
_result = await rs;
notifyListeners();
}
bool getResult(){
return _result;
}
My onPressed Method:
context.read<LoginModel>().login(
usernameController.text, passwordController.text);
print(context.read<LoginModel>().getResult());
if (context.read<LoginModel>().getResult()) {
context.read<FoodSelectionModel>().loadGalleryLinks();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FoodSelectionScreen()),
);
}
My Error:
The following LateError was thrown while handling a gesture:
LateInitializationError: Field '_result#21188420' has not been initialized.
The Bool is turned to late to true how can i set it faster.
i tried with putting async on my onPressed method and await it works thank you guys.
onPressed: () async {
await context.read<LoginModel>().login(
usernameController.text, passwordController.text);
print(context.read<LoginModel>().getResult());
if (context.read<LoginModel>().getResult()) {
context.read<FoodSelectionModel>().loadGalleryLinks();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FoodSelectionScreen()),
);
}

Login is successful even if it is invalid user

I simply want to accept username and password while login and check in the database if user is valid or not but the problem is for any username and password it shows "login successful". Whatever values I give it shows login successful but it should show "user doesnt exist." Please help me.
db_service.dart
Future<RegisterUser> getLogin(String user, String password) async {
await DB.init();
var res = await DB.rawQuery("userDetails WHERE emailId = '$user' and password = '$password'");
if (res.length > 0) {
return RegisterUser.fromMap(res.first);
}
return null;
}
UserLogin.dart (Code for the login button)
bool validateAndSave() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
void _submit(){
final form = _formKey.currentState;
var res;
if (validateAndSave()) {
setState(() {
res=dbService.getLogin(_email, _password).then((value) {
if(res!=0){
FormHelper.showMessage(
context,
"Login",
"Login Successfull",
"Ok",
() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => People_List(),
),
);
},
);}
else {
FormHelper.showMessage(
context,
"Login",
"Login not Successfull",
"Ok", () {}
);
}
});
});
}
}
It seems you are using the Future function in the wrong way.
res= await dbService.getLogin(_email, _password);
if(res != 0){
} else {
}
Or
dbService.getLogin(_email, _password).then((value) {
if(value != 0){
}else {
}
}, onError(e){});