Store multiple values in shared preference in flutter failed - flutter

Basically i am creating an online product app, when ever a user select any product and click on checkout button it checks whether user the is login or not. Here i did the same thing, i select a product and went cart page and clicks on checkout button (Here i am not loggedin) so it went to login page and saved the variables and then i go to the cart page and click on checkout button again it goes to login page. I have already saved the variables in login page but why it is not verifying.
Loginpage.dart
Future<UserRegister> getLogin(UserLogin userLogin) async{
final String apiUrl="http://cashback.us-east-2.elasticbeanstalk.com/user/login";
var userLoginJson = userLogin.toJson();
final response=await http.post(apiUrl,body: json.encode(userLoginJson),headers: {"content-type" : "application/json",
"Accept": "application/json",}
);
print(response);
if(response.statusCode >= 200 && response.statusCode < 300){
final responseString=response.body;
print(responseString);
var result = userRegisterFromJson(responseString);
print(result.user.userId);
print(result.user.name);
print(result.user.token);
print(result.user.mobile);
print(result.user.isDriver);
print(result.driver.driverId);
prefs.setBool('login', true);
prefs.setString('userid', result.user.userId.toString());
prefs.setString('name', result.user.name);
prefs.setString('mobile', result.user.mobile); //Here i am storing the values
prefs.setString('isDriver', result.user.isDriver.toString());
prefs.setString('driverId', result.driver.driverId.toString());
prefs.setString('token', result.user.token);
return result;
}else{
final responseString=response.body;
var result = json.decode(responseString);
print(result);
return null;
}
}
RaisedButton(
onPressed(){
getLogin(login);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => MainPage()));
}
)
Cartpage.dart
SharedPreferences logindata;
bool newuser;
PlatformButton(
onPressed: (){
check_if_already_login();
},
child: Text('Checkout',style: TextStyle(color: Colors.white),),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) =>
CupertinoButtonData(color: Colors.cyan)
),
Future<void> check_if_already_login() async {
logindata = await SharedPreferences.getInstance();
newuser = (logindata.getBool('login') ?? true);
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => Login()));
if (newuser == false) {
print(false);
}
}

Because you put Navigator.pushReplacement before if statement
So it will directly go to Login page
You can move Navigator.pushReplacement inside if
You can change from
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => Login()));
if (newuser == false) {
to
if (newuser == false) {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => Login()));
print(false);
}

Related

Shows warning: Do not use BuildContexts across async gaps

if (_formKey.currentState!.validate()) {
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email.text, password: password.text);
if (newUser != null) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => DashboardScreen(),
// ));
Navigator.pushNamed(context, 'dashboard');
}
setState(() {});
} catch (e) {
print(e);
}
}
},
this warning shown on Navigator.pushNamed(context,'dashboard');
trying to navigate to the dashboar screen.
1.
You have to put delay for other process can finish till then
Future.delayed(Duration(milliseconds: 200)).then((value) {
Navigator.pushNamed(context, 'dashboard')
});
2.
add if (!mounted) return; before Navigator.pushNamed(context, 'dashboard')
3.
Please put await before the navigator flutter because you used an asynchronously method call so you have to wait until the process is finished then you can navigate to your pages
await Navigator.pushNamed(context, 'dashboard');
4.
Also, you can store your navigator into a var and then use it.
final nav = Navigator.of(context);
nav.pushNamed('dashboard');

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

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()),
);
}

why ongenerate route calling my dashboard screen's init method?.....even though i'm still on login or signup screen?

i'm using flutter_bloc as a state management and the problem lies within this route file, it's calling dashboard's init method as soon as app starts, which i don't want.
(this is routing)
class AppRouter {
Route onGenerateRoute(RouteSettings routeSettings) {
switch (routeSettings.name) {
case SplashScreen.routeName:
return MaterialPageRoute(builder: (_) => SplashScreen());
case IntroScreen.routeName:
return MaterialPageRoute(builder: (_) => IntroScreen());
case LoginScreen.routeName:
return MaterialPageRoute(builder: (_) => LoginScreen());
case SignUpScreen.routeName:
return MaterialPageRoute(builder: (_) => SignUpScreen());
case DashboardScreen.routeName:
return MaterialPageRoute(builder: (_) => DashboardScreen());
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(
child: Text('No route defined for ${routeSettings.name}'),
),
),
);
}
}
}
(this is startup logic)
class Init {
Future<String> initialize() async {
await _registerServices();
await _loadSettings();
return await _loadInitialRoute();
}
late final SharedPreferences _prefs;
late final SessionManager _sessionManager;
late final AuthRepositoryImpl _authRepository;
late final bool _userSeenIntro;
late final String? _presistentSession;
Future<void> _registerServices() async {
_prefs = await SharedPreferences.getInstance();
_sessionManager = SessionManager();
_authRepository = AuthRepositoryImpl.instance;
}
Future<void> _loadSettings() async {
_userSeenIntro = _prefs.getBool(AppConstants.IS_USER_SEEN_INTRO) ?? false;
_presistentSession = await _sessionManager.getSessionToken();
await _authRepository.recoverSession(_presistentSession);
}
Future<String> _loadInitialRoute() async {
if (_userSeenIntro && _presistentSession != null) {
print('inside dashboardscreen.routename');
return DashboardScreen.routeName;
} else if (_userSeenIntro && _presistentSession == null) {
return LoginScreen.routeName;
} else {
_prefs.setBool(AppConstants.IS_USER_SEEN_INTRO, true);
return IntroScreen.routeName;
}
}
}
this is my onGenerate routes and i don't know why flutter calling my dashboard's init method and even build method too
this is my startup logic I'm setting initial route in material app on the basis of sharedPrefernces

How to handle "Lost connection to device." error

I created an app, which contains login and dashboard screen, i used Nodejs backend and mongodb also. i trying to add functionality when user logged in and close the app without logging out and then when user come to the app it should display where it left last time. so i used shared preference for it. I am testing it now, when i logged in and close the app using the right-most button (which shows all the currently running apps) it send me this "Lost connection to device.
".
login Code:
bool newuser;
String type ;
SharedPreferences myPrefs;
void initState() {
checkIfLoggedinalready();
}
Future login() async {
try {
Dio dio = new Dio();
var data = {
'username':"Munib khatri",
'password': "Munib123",
'date': "5/5/2021"
};
await dio
.post(localhostUrlLogin, data: json.encode(data))
.then((onResponse) async {
type = onResponse.data['User']['Type'];
if (type == 'Employee') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
} else if (type == 'Manager') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Manager()));
}
myPrefs.setBool('login', false);
});
} catch (e) {
}
}
void checkIfLoggedinalready() async{
myPrefs = await SharedPreferences.getInstance();
newuser = (myPrefs.getBool('login') ?? true);
print(newuser);
if (newuser == false && type == 'Employee') {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => Employee()));
}
}
dashboard code:
i am doing this on drawer code where i use logout
new ListTile(
title: new Text('Log out'),
leading: Icon(Icons.logout,color:Colors.grey),
onTap: (){
myPrefs.setBool('login', true); //here i set it to true, if user is new
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>
Login()
)
);
},
),
please help it would be appreciated.
Lost connection to device is not a coding issue, your linked device got disconnected at that time due to data cable, If you will test this on emulator then you will not get this issue.
If you are saving user data on Shared preference then do encode your sensitive data before saving it.
var response =
await http.post(Uri.parse(parseUse), body: json.encode(data), headers: { "Content-Type": "application/json; charset=UTF-8", }).timeout(Duration(minutes: 2));
Updated Answer :
try{
Dio dio = new Dio();
var data = {
'username':"Munib khatri",
'password': "Munib123",
'date': "5/5/2021"
};
await dio
.post(localhostUrlLogin, data: json.encode(data))
.then((onResponse) async {
type = onResponse.data['User']['Type'];
if (type == 'Employee') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
} else if (type == 'Manager') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Manager()));
}
myPrefs.setBool('login', false);
});
}on DioError catch (e){
if(e.type == DioErrorType.connectTimeout){
"You can put a alert dialog or something you prefer".
}
}
or you can also use base Option since your using DIO
var dio = Dio(); // with default Options
// Set default configs
dio.options.baseUrl = 'https://www.xx.com/api';
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout = 3000;
// or new Dio with a BaseOptions instance.
var options = BaseOptions(
baseUrl: 'https://www.xx.com/api',
connectTimeout: 5000,
receiveTimeout: 3000,
);
Dio dio = Dio(options);
response = await dio.request(
'/test',
data: {'id':12,'name':'xx'},
options: Options(method:'GET'),
);