Flutter Shared preference Login not working properly - flutter

I have created Login Page, User is able to login, but problem is that after I navigate to New screen userId is not getting passed from Shared preference. If i close and re-open app then userId is passed properly. How Can I manage this properly.
Future loginUser(String email, String password) async {
String url = 'https://androidapp.factory2homes.com/api/login';
final response =
await http.post(url, body: {'email': email, 'password': password});
print(response.body);
var result = jsonDecode(response.body);
return result;
}
onPressed: () async {
var email = emailController.text;
var password = passwordController.text;
setState(() {
message = 'Please wait...';
});
var result = await loginUser(email, password);
if(result ['result']== true ){
SharedPreferences _prefs = await SharedPreferences.getInstance();
_prefs.setInt('userId', result['user']['id']);
_prefs.setString('userName', result['user']['name']);
_prefs.setString('userEmail', result['user']['email']);
Navigator.push(context, MaterialPageRoute(builder: (context)=>HomeScreen()));
} else {
print('incorrect password');
}
},

Add await as setInt & setString both use Future which perform operation asynchronously
await _prefs.setInt('userId', result['user']['id']);
await _prefs.setString('userName', result['user']['name']);
await _prefs.setString('userEmail', result['user']['email']);

Related

How to pass uid and email to sharedpreference method When signUp in flutter?

I built the google signin and email password signup app using flutter,
I want when user log to application then user's "uid" and "email" save in shared preference.
In google login I built when login then pass the boolean value and pass uid and email to shared preference. Then when users close app and when reopen then login in home screen and can get uid and email.
But when user signup or login using email password then can not pass the boolean value and uid and email to google login shared preference. In below I'll mentioned google login method and email password method.
googlelogin method
// handling google sigin in
Future handleGoogleSignIn() async {
final sp = context.read<SignInProvider>();
final ip = context.read<InternetProvider>();
await ip.checkInternetConnection();
if (ip.hasInternet == false) {
openSnackbar(context, 'Check your Internet connection', Colors.red);
googleController.reset();
} else {
await sp.signInWithGoogle().then((value) {
if (sp.hasError == true) {
openSnackbar(context, sp.errorCode.toString(), Colors.white);
googleController.reset();
} else {
// checking whether user exists or not
sp.checkUserExists().then((value) async {
if (value == true) {
// user exists
await sp.getUserDataFromFirestore(sp.uid).then((value) => sp
.saveDataToSharedPreferences()
.then((value) => sp.setSignIn().then((value) {
googleController.success();
handleAfterSignIn();
})));
} else {
// user does not exist
sp.saveDataToFirestore().then((value) => sp
.saveDataToSharedPreferences()
.then((value) => sp.setSignIn().then((value) {
googleController.success();
handleAfterSignIn();
})));
}
});
}
});
}
//login function
}
saveDataToSharedPreferences method and setSignIn boolean value (it has in a siginprovider class in another file)
class SignInProvider extends ChangeNotifier {
//instantiate of firebaseAuth, facebook and google
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
bool _isSignedIn = false;
bool get isSignedIn => _isSignedIn;
//hasError, errorCode, provider,uid,email,name,imageUrl
bool _hasError = false;
bool get hasError => _hasError;
String? _errorCode;
String? get errorCode => _errorCode;
String? _uid;
String? get uid => _uid;
String? _email;
String? get email => _email;
SignInProvider() {
checkSignInUser();
}
Future checkSignInUser() async {
final SharedPreferences s = await SharedPreferences.getInstance();
_isSignedIn = s.getBool('signed_in') ?? false;
notifyListeners();
}
Future setSignIn() async {
final SharedPreferences s = await SharedPreferences.getInstance();
s.setBool('signed_in', true);
_isSignedIn = true;
notifyListeners();
}
Future saveDataToSharedPreferences() async {
final SharedPreferences s = await SharedPreferences.getInstance();
await s.setString('email', _email!);
await s.setString('uid', _uid!);
notifyListeners();
}
Future getDataFromSharedPreferences() async {
final SharedPreferences s = await SharedPreferences.getInstance();
_email = s.getString('email');
_uid = s.getString('uid');
notifyListeners();
}
}
**email password signup**
void signUp(String email, String password) async {
if (_formkey.currentState!.validate()) {
await _auth
.createUserWithEmailAndPassword(email: email, password: password)
.saveDataToSharedPreferences()
.sp.setSignIn()
.then((value) => {postDetailsToFirestore()})
.catchError((e) {
Fluttertoast.showToast(msg: e!.message);
});
}
}
in email password signup has postDetailsToFirestore method
postDetailsToFirestore() async {
// calling our fireStore
//calling our user model
// sending these values
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
User? user = _auth.currentUser;
UserModel userModel = UserModel();
if (user != null) {
//writing all the values
userModel.email = user?.email;
userModel.uid = user?.uid;
await firebaseFirestore
.collection("users")
.doc(user?.uid)
.set(userModel.toMap());
Fluttertoast.showToast(msg: "Account created successfully ");
Navigator.pushAndRemoveUntil(
(context),
MaterialPageRoute(builder: (context) => HomeScreen()),
(route) => false);
}
}
in email password signup I called
these 2 methods but show this error
when signup how to pass uid and emaill to saveDataToSharedPreferences method and pass sp.setSignIn() boolean like as in google signing?
You are trying to use method saveDataToSharedPreferences from Future class, not from auth. For fix this issue, call prefs from main object:
final result = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
result.saveDataToSharedPreferences()
.sp.setSignIn()
// etc.

An optimize way for tryAutoLogin function in flutter?

I want to create a function for auto login like Facebook in flutter but don't know the best way to do it.
My function for login and auto login, I used SharedPreferences plugin for store data.
SignIn function:
Future<void> signIn(String userName, String pass) async {
final url = Uri.parse('MyAPI_login');// sorry it for privacy
debugPrint("$userName / $pass");
try {
var respone = await http.post(url, body: {
'user_name': userName,
'password': pass,
'platform': 'mobile',
'device_token': '',
});
final reponseData = jsonDecode(respone.body);
_userName = userName;
_token = reponseData['data']['accessToken'];
_expiryDate = DateTime.now().add(Duration(
seconds: int.parse(reponseData['data']['tokenExpireAt'].toString())));
_refreshToken = reponseData['data']['refreshToken'].toString();
_timerRefreshToken =
int.parse(reponseData['data']['refreshTokenExpireAt'].toString());
// debugPrint(
// '$_token \n $_expiryDate \n $_refreshToken \n $_timerRefreshToken');
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'_userId': _userName.toString(),
'token': _token.toString(),
'expiryDate': _expiryDate!.toIso8601String(),
'refreshToken': _refreshToken,
'timerRefreshToken': _timerRefreshToken.toString(),
});
await prefs.setString('userData', userData);
} catch (error) {
throw Exception(error.toString());
}}
TryAutoLogin function:
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final extractedUserData = json
.decode(prefs.getString('userData').toString()) as Map<String, dynamic>;
final expiryDate =
DateTime.parse(extractedUserData['expiryDate'].toString());
if (expiryDate.isBefore(DateTime.now())) {
_token = extractedUserData['refreshToken'].toString();
_expiryDate = DateTime.now().add(
Duration(seconds: int.parse(extractedUserData['timerRefreshToken'])));
_refreshNewToken(extractedUserData['refreshToken'].toString());
}
return true;}
RefreshNewToken function:
Future<void> _refreshNewToken(String oldRefreshToken) async {
final url =
Uri.parse('MyAPI_refreshtoken');
var respone = await http.post(url, body: {'refreshToken': oldRefreshToken});
debugPrint(respone.body);}
My API for login response is like this:
{"data":{"tokenKey":"Authorization","tokenType":"Bearer","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1YzkyMTQwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTMsImV4cCI6MTY1ODI4NTk5M30.3kMByfweUhzQM-4d5S0G7tUaC0e-nZLJF3_dbdV_7fM","tokenExpireAt":1658285940964,"refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1YzkyMTQwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTMsImV4cCI6MTY1ODM2ODc5M30.Bv7PZrnx9zDzwIuxNMppFxlwZlJEnthVjEYBKYl-aWM","refreshTokenExpireAt":1658368740964},"message":"Logged in successfully!","status":200,"errors":null}
Also, my API has a refresh token request, it returns like this:
{"data":{"tokenKey":"Authorization","tokenType":"Bearer","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1ZjQyOGUwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTQsImV4cCI6MTY1ODI4NTk5NH0.wcyouoprMHFnRD4_oSpP9RSasxMBrktX6nZI2x2PQec","tokenExpireAt":1658285940242,"refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1ZjQyOGUwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTQsImV4cCI6MTY1ODM2ODc5NH0.y-8MP4M_1LzCwmqo_KQZGyQXkycrxdOLWz_fdqIPRyQ","refreshTokenExpireAt":1658368740242},"message":"Request successfully!","status":200,"errors":null}

Passing token in Flutter from auth to http-request

how to pass the token value from above code to another screen into a http-request as variable.
class AppStarted extends AuthenticationEvent {}
class LoggedIn extends AuthenticationEvent {
final String token;
const LoggedIn({#required this.token});
#override
List<Object> get props => [token];
#override
String toString() => 'LoggedIn { token: $token }';
}
Thank you for your help, haning on this for 2 hours now...
first create a class where your where https request handle & token store
class Network {
var token;
final string base= "/api";
//token get when needed
_getToken() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('data'));
token = user['token'];
}
//signup
signUp(data, apiUrl) async {
var fullUrl = baseUrl + apiUrl;
return await http.post(fullUrl,
body: jsonEncode(data), headers: _setHeaders());
}
//login
signIn(apiUrl) async {
var fullUrl = baseUrl + apiUrl;
await _getToken();
return await http.get(fullUrl, headers: _setHeaders());
}
}
in sign up page use this method where you use sign up button on pressed
void _signUp() async {
var data = {
'mobile': mobileController.text,
'password': mobileController.text,
};
var res = await Network().signUp(data, '/register');
var body = json.decode(res.body);
if (body.statusCode == 200) {
SharedPreferences localStorage = await SharedPreferences.getInstance();
localStorage.setString('token', json.encode(body['data']['token']));
localStorage.setString('data', json.encode(body['data']));
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => Home()),
);
} else {
// errorMessage = "as you want to show ";
}
}
in sign up page , use this method same as sign up pages
void signIn() async {
var data = {'mobile': mobile, 'password': password};
var res = await Network().signIn(data, '/login');
var body = json.decode(res.body);
if (res.statusCode == 200) {
SharedPreferences localStorage = await SharedPreferences.getInstance();
localStorage.setString('token', json.encode(body['data']['token']));
localStorage.setString('data', json.encode(body['data']));
Navigator.pushReplacement(
context,
new MaterialPageRoute(builder: (context) => HomePage()),
);
} else if (res.statusCode != 200) {
// mobileError = "These credentials do not match our records.";
}
}
now you can have the token when u signup/singIn and store token in sharedSharedPreferences
whenever you try to acces token just called _getToken() method

Flutter: What is the Correct approach to get value from Future?

I have a function that which returns user token, and saves it to shared preference, if token is present it saves it to SP. Another method awaits for the token and if token is present authenticates user
Here is my code
login(username, password) async {
final String url = "http://10.0.2.2:8080/api/auth/signin"; // iOS
final http.Response response = await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'username': username,
'password': password,
}),
);
LoginModel userSave = loginModelFromJson(response.body);
print(response.body);
final SharedPreferences prefs = await SharedPreferences.getInstance();
bool result = await prefs.setString('user', jsonEncode(userSave));
print(result);
}
This piece of code works as expected, but I'm having issue getting the token value from Future.
Case Scenario: User enters username and password and authenticates with server. Incase account exists a token is generated from server and sent to app and stored in shared prefs. token if available is picked from shared prefs and used to login to app, but the check of the token is done before it is generated and saved
Future<LoginModel> getUserInfo() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
Map<String, dynamic> userMap;
final String userStr = prefs.getString('user');
if (userStr != null) {
userMap = jsonDecode(userStr) as Map<String, dynamic>;
}
if (userMap != null) {
final LoginModel user = LoginModel.fromJson(userMap);
print(user);
return user;
}
return null;
}
the token gets called way before it is saved throwing an error of null
RoundedButton(
text: "LOGIN",
press: () async {
if (_formKey.currentState.validate()) {
progressDialog.show();
await login(
username,
password,
);
SharedPreferences prefs =
await SharedPreferences.getInstance();
String token = prefs.getString("accessToken");
getUserInfo();
// ignore: null_aware_in_condition
if (token == null) {
progressDialog.hide();
showAlertsDialog(context);
// ignore: null_aware_in_condition
} else {
progressDialog.hide();
showAlertzDialog(context);
}
}
},
),
I believe there is very small logical mistake, but unable to find it myself.
I believe you cannot directly call jsonEncode with a custom object like the way you do it in jsonEncode(userSave). Do print(jsonEncode(userSave)); to see if the value is properly being converted into a string.

How to use response after POST Request?

How to use data from response after POST request in Flutter/Dart?
this is my function:
signIn(String email, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map data = {
'email': email,
'password': pass
};
var jsonResponse = null;
var response = await http.post("http://10.0.2.2:80/user/login", body: data);
if(response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if(jsonResponse != null) {
print(jsonResponse);
setState(() {
_isLoading = true;
});
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => MainPage()), (Route<dynamic> route) => false);
}
}
else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}
after run this function, my jsonResponse returns this data to me:
{id: 1, firstName: admin, lastName: admin, accountName: Kot filemon, email: admin#admin.pl, active: false, activateCode: 0, admin: true, latitude: xxx, longitude: xxx, profileImage: null}
so, how can I use this data(without another request to server) in my app on different screen?
I know how to use this type of data in react, because i'm a frontend developer but i don't have any idea how to use this here.
thanks for any help :)
You can save it to SharedPreferences if all the data in this response are common for all screens.
At this moment you cant store all that jsondata in one SharedPreferenceValue. You need to create one value foreach userdata like this:
signIn(String email, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map data = {
'email': email,
'password': pass
};
var jsonResponse = null;
var response = await http.post("http://10.0.2.2:80/user/login", body: data);
if(response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if(jsonResponse != null) {
print(jsonResponse);
// this lines save the user data in the sharedpreferenceinstance
await prefs.setString('email',jsonResponse[email]);
await prefs.setString('accountName', jsonResponse[accountName]);
//-----------------now you cant send to another page
// if you need to read the saved data use=>prefs.getInt('email');
setState(() {
_isLoading = true;
});
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => MainPage()), (Route<dynamic> route) => false);
}
}
else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}