Anyway to enable 'remember me' function using sharedPreferences in flutter? - flutter

Currently, I have enabled 'keep logging in' function if the user log in once successfully. However, I still want to make a 'remember me' checkbox to save the success login information for user. Can anyone please help me with this?
Need: a checkbox that enables the user to store email and password if the user logged in once successfully.
Code is shown below:
signIn(String email, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String url = ServerDetails.ip +
':' +
ServerDetails.port +
ServerDetails.api +
'login';
Map<String, String> headers = {"Content-type": "application/json"};
var data = jsonEncode({
'email': email,
'password': pass,
'token': FirebaseNotifications.fcmtoken
});
var jsonResponse = null;
var response = await http.post(url, headers: headers, body: data);
if (response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if (jsonResponse != null) {
setState(() {
_isLoading = false;
});
sharedPreferences.setString("token", jsonResponse['token']);
sharedPreferences.setString(
"token_expire_date", jsonResponse['token_expire_date']);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) => MainPage()),
(Route<dynamic> route) => false);
}
} else {
setState(() {
_isLoading = false;
});
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => MainPage()));
});
setState(() {
AlertDialog alert = AlertDialog(
title: Text("Error message"),
content: Text("Oops! The password is wrong or the email is invalid."),
actions: [
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
});
print(response.headers);
print(response.body);
}
}

Of course, you can create a simple checkbox for remember me. In the login button, you can check if this checkbox is checked. If it is, you can set email & password in shared_preferences.
Next time, when the user comes again you can get these fields automatically from shared_preferences.
Here is an example.

Related

How I can exit from next line code in flutter

I have a function:
onTap: () {
FunctionsClass.checkToken(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AttackDetailScreen(
idAttack:
data[index]['id'].toString())));
},
Checktoken function:
static Future<http.Response> checkToken(BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var url = kUrlAPI + 'checkToken/';
var response = await http.get(Uri.encodeFull(url),
headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer ' + prefs.getString('token'),
});
var convertDataToJson = jsonDecode(response.body);
if(convertDataToJson['code'] == 401){
Loader.hide();
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) => CustomDialog(
pressedAction: () {
Navigator.of(context).pop();
},
type: 'w',
title: kWarningTitle,
description: kGenericError,
buttonText: kCloseText,
),
);
//exit for next function
}
}
I want if convertDataToJson['code'] == 401, show dialog and not execute Navigator.
Something to not execute the next method
Return a value from your checkToken function that indicates whether the navigator should push or not. For example you can return null in case of an error or simply return boolean where true means push or false means don't push (or you could return the error string and check it inside onTap if you prefer that).
Let's assume you choose to return null if the navigator shouldn't push the page, then you can do this:
onTap: () {
FunctionsClass.checkToken(context).then((value) {
if(value == null) {
return; // don't do anything
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AttackDetailScreen(idAttack: data[index]['id'].toString())));
}
}
}
Try using try/catch for unexpected error too. And 'throw' a custom error.
This is consider a good practice.
static Future<http.Response> checkToken(BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var url = kUrlAPI + 'checkToken/';
try {
var response = await http.get(Uri.encodeFull(url),
headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer ' + prefs.getString('token'),
});
var convertDataToJson = jsonDecode(response.body);
if(convertDataToJson['code'] == 401){
//exit for next function
throw Exception('some error');
}
} catch (error) {
throw error;
}
}
And use ".then" and '.catchError' while calling a Future function.
onTap: () {
FunctionsClass.checkToken(context).then((_) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AttackDetailScreen(
idAttack:
data[index]['id'].toString(),
),
),
);
}).catchError((onEroor){
Loader.hide();
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) => CustomDialog(
pressedAction: () {
Navigator.of(context).pop();
},
type: 'w',
title: kWarningTitle,
description: kGenericError,
buttonText: kCloseText,
),
);
};
},

FutureBuilder does not get into builder?

I want to get two parameters from createUser response.
I have a raisedbutton and i want to use FutureBuilder when onPressed.
future property works well, but i can not get in builder property. I tried everything but i could not find solution.
...
RaisedButton(
elevation: 5.0,
onPressed: (){
FutureBuilder(
future: createUser(usernameController.text, emailController.text, passwordController.text, '1', 1),
builder: (context, snapshot) {
if (snapshot.hasData) {
saveLogin(snapshot.data.userUnique);
nextScreen(
context,
UserDetail(
userUnique: snapshot.data.userUnique,
));
} else {
return MyHomePage();
}
return MyHomePage();
});
},
...
Future createUser(String username, String password, String email,
String logintype, int userUnique) async {
String url =
"http://api.xx.com/api/register?username=$username&password=$password&email=$email&logintype=$logintype&userUnique=$userUnique";
final response =
await http.get(url, headers: {'Content-Type': 'application/json'});
return registerFromJson(utf8.decode(response.bodyBytes));
I changed FutureBuilder to async / await method
thanks for your help #pskink
onPressed: () async {
var xx = await createUser( usernameController.text, emailController.text, passwordController.text, '1',userUnique());
print(xx.responseCode.toString());
print(xx.userUnique.toString());
saveLogin(userUnique());
},

How to implement CircularProgressIndicator in Flutter

I am trying to implement a CircularProgressIndicator when waiting user to finish their authentication process, here's the code, I am using Firebase as the auth backend
Future<void> signIn() async {
if (_formKey.currentState.validate()) {
new Loading();
_formKey.currentState.save();
try {
final user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
if (user != null) {
final FirebaseUser user = await auth.currentUser();
print('success login');
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(user: user),
));
}
} catch (e) {
print(e);
}
}
}
how to implement the circularprogressindicator into the code?
CircularProgressIndicator can be implemented in UI with a condition.If you want to implement it in some area of your page you can use boolean to make it work like this:
bool showCircular = false;
Future<void> signIn() async {
if (_formKey.currentState.validate()) {
new Loading();
_formKey.currentState.save();
setState(() {
showCircular=true;
});
try {
final user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
if (user != null) {
final FirebaseUser user = await auth.currentUser();
setState(() {
showCircular=false;
});
print('success login');
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(user: user),
));
}
} catch (e) {
print(e);
}
}
}
Now anywhere in your UI add this widget:
showCircular ? CircularProgressIndicator() : SizedBox(),
Recommended way is using an AlertDialog to show progress indicator. Here is an example with AlertDialog.To open Dialogs you need context so take BuildContext as a parameter and call signIn(context); from sign in button.We will call dialog using openLoadingDialog function and when sign in is completed we will pop it using Navigator.of(context).pop();
Future<void> signIn(BuildContext context) async {
if (_formKey.currentState.validate()) {
new Loading();
_formKey.currentState.save();
openLoadingDialog(context, 'Signing In...');
try {
final user = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: _email, password: _password);
if (user != null) {
final FirebaseUser user = await auth.currentUser();
Navigator.of(context).pop();
print('success login');
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(user: user),
));
}
} catch (e) {
print(e);
}
}
}
Paste this dialog anywhere in your app.You can call it by passing context and message you want to show.
openLoadingDialog(BuildContext context, String text) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
content: Row(children: <Widget>[
SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(
strokeWidth: 1,
valueColor: AlwaysStoppedAnimation(Colors.black)
)
),
SizedBox(width: 10),
Text(text)
]),
)
);
}

cannot navigate form login screen to bottom_tab_screen with provider

I'm trying to navigate from login screen to the bottom tab screen but nothing happen and now i have no error
it is the main
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: UserProvider()),
ChangeNotifierProvider.value(value: AppProvider()),
],
child:MaterialApp(
key: key,
title: 'Voyager',
debugShowCheckedModeBanner: false,
theme: AppTheme.getTheme(),
routes: routes,
),
);
}
my dialog which has two cases if success or fail to login or sign up
import 'package:flutter/material.dart';
class Dialogs {
static showErrorDialog(BuildContext context,
{#required String message, #required int code}) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Ok'),
)
],
title: Text('error $code'),
content: Text(message),
backgroundColor: Colors.white,
);
},
);
}
}
my login method and it depend on user api provider
signIn() async {
var res = await userProvider.login(
_userNameController.text, _passwordController.text);
if (res is FailedRequest) {
Dialogs.showErrorDialog(widget._context , message: res.message, code: res.code);
print('results ${res.toString()}');
} else {
print("Signing in success");
Navigator.pushReplacement(
widget._context, MaterialPageRoute(builder: (context) => BottomTabScreen()));
}
userProvider.isLoading = false;
}
and the api provider which use in the login
Future<dynamic> login(String email, String password) async {
final Map<String, dynamic> body = {'email': email, 'password': password};
_isLoading = true;
notifyListeners();
print('Starting request');
http.Response response = await http.post(Environment.userLogin,
body: json.encode(body), headers: Environment.requestHeader);
print('Completed request');
print('user login response : ${response.body}');
Map<String, dynamic> res = json.decode(response.body);
var results;
if (res['code'] == 200) {
// login successful
_user = User.fromJson(res['message']);
results = true;
} else {
// login failed;
results =
FailedRequest(code: 400, message: res['error'], status: false);
}
_isLoading = false;
notifyListeners();
return results;
}
finally the failed request class if request not done
import 'package:flutter/foundation.dart';
class FailedRequest {
String message;
int code;
bool status;
FailedRequest({
#required this.message,
#required this.code,
#required this.status,
});
}
The Issue seems to be with the res['error'] can you verify that the field error actually exists and is not null.
At this block can you print the value of res['error']
else {
print(res['error']);
// login failed;
results =
FailedRequest(code: 400, message: res['error'], status: false);
}

Refresh on back using MaterialPageRoute

I want to refresh my List when hitting the back button on the details page (which the List page links from). However, the method I need to run is a Future and it seems that causes some issues.
I have used this approach: https://stackoverflow.com/questions/49933272/how-to-refresh-a-page-after-back-bottun-pressed?rq=1#=
Here is a shot of the error:
And here is the method:
// Load list items
Future _loadItems() async {
// setState(() => _isLoading = true);
List<CNotification> _listItems = new List<CNotification>();
SharedPreferences prefs = await SharedPreferences.getInstance();
String _usr = prefs.getString('usr');
String _pwd = prefs.getString('pwd');
String _communityId = prefs.getInt('communityid').toString();
final response = await http.get(helperConnectionString +
'GetNotifications?usr=$_usr&pwd=$_pwd&communityid=$_communityId');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
List data = json.decode(response.body);
for (var i = 0; i < data.length; i++) {
String _title = "";
data[i]['MessageText'].toString().length > 25
? _title =
data[i]['MessageText'].toString().substring(0, 25) + '...'
: _title = data[i]['MessageText'].toString();
DateTime entryCreated =
DateTime.parse(data[i]['DateCreated'].toString());
String _dRead =
DateFormat.yMd().add_jms().format(entryCreated).toString();
_listItems.add(new CNotification(int.parse(data[i]['Id'].toString()),
_title, _dRead, data[i]['DateRead'] == null ? false : true));
}
setState(() {
_items = _listItems;
_isLoading = false;
});
} else {
setState(() {
_isLoading = false;
});
print('Error');
}
}
Anyone?
/Bob
Here is what you are looking for.
Navigator.of(context).push(MaterialPageRoute(builder: (context) => SomePage())).then((_) => _loadItems())
But I would recommend you to use async/await everywhere:
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: _showSomePage,
child: Text('Show some page'),
);
}
void _showSomePage() async {
await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SomePage(),
));
await _loadItems();
}
Future<void> _loadItems() async {
// ...
}
Inline version:
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SomePage(),
));
await _loadItems();
},
child: Text('Show some page'),
);
}