Async not waiting for complete - flutter

I'm trying to make the following method wait for complete but it stops before the line "print(user)":
Future<ModelUser> createUserWithEmailAndPassword({
#required String email,
#required String password,
}) async {
assert(email != null);
assert(password != null);
var user = new ModelUser(email: email, password: password);
final response = await post(Uri.http(_options.baseUrl, '/createAccount'),
headers: _headers, body: jsonEncode(user.toJson()));
if (response.statusCode == 200) {
Map<String, dynamic> userMap = jsonDecode(response.body);
var user = ModelUser.fromJson(userMap);
print(user);
return ModelUser.fromJson(jsonDecode(response.body));
}
return null;
}
I'm calling it from another method, using await:
Future<ModelUser> registerWithEmailAndPassword(
String email, String password) async {
try {
return _user(await _auth.createUserWithEmailAndPassword(
email: email, password: password));
} catch (e) {
return null;
}
}

Related

How to dynamically save token after logging to shared prefernces

How to dynamically auth users and save tokens in shared pref?
I understood how to save token in sharedprefernces, but can't understand how to take it dynamically by login/password and pass token from it to sharedpref dynamically in loginWithToken(); beacuse I use this function for auth in
final httpConnectionOptions = HttpConnectionOptions(
accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
and it is required only String
My code now is like that:
Here is request where I am making request to get token:
Future<String?> getToken(String password, String login) async {
String _email = "admin";
String _password = "123";
Map<String, String> headers = {
'Content-Type': 'application/json',
'accept': ' */*'
};
final body = {
'username': _email,
'password': _password,
};
var response = await http.post(
Uri.parse("http://mylink/login"),
headers: headers,
body: jsonEncode(body),
);
if (response.statusCode == 200) {
var value = jsonEncode(response.body);
return value;
}
return null;
}
here is I created logging logic:
final TextEditingController _loginController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
ElevatedButton(
onPressed: () async {
var username = _loginController.text;
var password = _passwordController.text;
var jwt = await ProviderService()
.getToken(password, username);
if (jwt != null) {
SharedPreferenceService().setToken(jwt);
Navigator.pushNamed(
context, '/mainPageAdmin');
} else {
displayDialog(context);
}
},
here is my shared pref. I can't understand how to put new token value in that string, after paaword and login was sent.
String tokens = 'dhjwhdwdwkjdhdkje';
Future<bool> getSharedPreferencesInstance() async {
_prefs = await SharedPreferences.getInstance().catchError((e) {
print("shared preferences error : $e");
return false;
});
return true;
}
Future setToken(String token) async {
await _prefs?.setString('token', token);
}
Future clearToken() async {
await _prefs?.clear();
}
Future<String> get token async => _prefs?.getString('token') ?? '';
Future<String> loginWithToken() async {
bool value = await getSharedPreferencesInstance();
if (value == true) {
setToken("Bearer $tokens");
// print(tokens);
}
return tokens;
}
Api Responce:
{
"$id": "1",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZ",
"user": {
"$id": "2"
}
}
Auth class I parsed:
Auth authFromJson(String str) => Auth.fromJson(json.decode(str));
String authToJson(Auth data) => json.encode(data.toJson());
class Auth {
Auth({
this.token,
this.user,
});
final String? token;
final User? user;
factory Auth.fromJson(Map<String, dynamic> json) => Auth(
token: json["token"],
user: User.fromJson(json["user"]),
);
Map<String, dynamic> toJson() => {
"token": token,
"user": user!.toJson(),
};
}
In your getToken function do this:
if (response.statusCode == 200) {
var value = jsonEncode(response.body) as Map<String, dynamic>;
await setToken(value['token']);
return value;
}

I'm getting errors for my controller listener in Flutter

I am building a password manager flutter application and I'm using Firestore database to store the data(passwords) entered by the users. I have created 4 different text fields on my Flutter application and on the firestore database, namely : title, email, userpassword and url.
I am getting some errors for my listeners.
void _titleControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final title = _titleController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
title: title,
);
}
void _emailControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final email = _emailController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
email: email,
);
}
void _userPasswordControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final userpassword = _userPasswordController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
userpassword: userpassword,
);
}
void _urlControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final url = _urlController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
url: url,
);
}
Errors: These 4 four errors are repeated for a total of 24 errors.
The named parameter 'url' is required, but there's no corresponding argument.
Try adding the required argument.
The named parameter 'email' is required, but there's no corresponding argument.
Try adding the required argument.
The named parameter 'userpassword' is required, but there's no corresponding argument.
Try adding the required argument.
The named parameter 'title' is required, but there's no corresponding argument.
Try adding the required argument.
update password() code(I'm not getting any errors here).
Future<void> updatePassword({
required String documentId,
required String title,
required String email,
required String userpassword,
required String url,
}) async {
try {
await passwords.doc(documentId).update({titleFieldName: title});
await passwords.doc(documentId).update({emailFieldName: email});
await passwords.doc(documentId).update({userpasswordFieldName: userpassword});
await passwords.doc(documentId).update({urlFieldName: url});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Pay attention that when you are calling:
await _passwordsService.updatePassword(
documentId: password.documentId,
url: url,
);
You are not passing all required parameters. You have various calls to this method and each time you are calling it with different arguments.
I.E.
void _userPasswordControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final userpassword = _userPasswordController.text;
await _passwordsService.updatePassword( //// <----
documentId: password.documentId,
userpassword: userpassword,
);
}
The method updatePassword has five required arguments:
updatePassword({
required String documentId, /// <-------
required String title, /// <-------
required String email, /// <-------
required String userpassword, /// <-------
required String url, /// <-------
})
so you must pass all of them.
An example call could be:
await _passwordsService.updatePassword(
documentId: password.documentId,
userpassword: userpassword,
title: YOUR_TITLE,
url: YOUR_URL,
email: YOUR_EMAIL
);
In updatePassword method you specified title, email, userpassword and url as required.
You can make them optional:
Future<void> updatePassword({
required String documentId,
String? title,
String? email,
String? userpassword,
String? url,
}) async {
try {
if (title != null) await passwords.doc(documentId).update({titleFieldName: title});
if (email != null) await passwords.doc(documentId).update({emailFieldName: email});
if (userpassword != null) await passwords.doc(documentId).update({userpasswordFieldName: userpassword});
if (url != null) await passwords.doc(documentId).update({urlFieldName: url});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
I was able to solve the errors by splitting the updatePassword() code into 4 different functions. 1 function for each text field.
Future<void> updatePasswordTitle({
required String documentId,
required String title,
}) async {
try {
await passwords.doc(documentId).update({titleFieldName: title});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Future<void> updatePasswordEmail({
required String documentId,
required String email,
}) async {
try {
await passwords.doc(documentId).update({emailFieldName: email});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Future<void> updatePasswordUserpassword({
required String documentId,
required String userpassword,
}) async {
try {
await passwords.doc(documentId).update({userpasswordFieldName: userpassword});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Future<void> updatePasswordUrl({
required String documentId,
required String url,
}) async {
try {
await passwords.doc(documentId).update({urlFieldName: url});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
After creating the above 4 updatePassword functions. I made changes to the controller listeners. So, that they call their own updatePassword function.
void _titleControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final title = _titleController.text;
await _passwordsService.updatePasswordTitle(
documentId: password.documentId,
title: title,
);
}
void _emailControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final email = _emailController.text;
await _passwordsService.updatePasswordEmail(
documentId: password.documentId,
email: email,
);
}
void _userPasswordControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final userpassword = _userPasswordController.text;
await _passwordsService.updatePasswordUserpassword(
documentId: password.documentId,
userpassword: userpassword,
);
}
void _urlControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final url = _urlController.text;
await _passwordsService.updatePasswordUrl(
documentId: password.documentId,
url: url,
);
}

Strange error using Flutter app + Deno + MongoDB backend

I want to write a simple registration function and this is my code:
auth_screen.dart:
Future<void> _submit() async {
if (!_formKey.currentState!.validate()) {
// Invalid!
return;
}
_formKey.currentState!.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] as String,
_authData['password'] as String,
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] as String,
_authData['password'] as String,
);
}
} on HttpException catch (error) {
var errorMessage = 'Authentication failed';
print("this is the auth data");
print(_authData);
if (error.toString().contains('EMAIL_EXISTS')) {
errorMessage = 'This email address is already in use.';
} else if (error.toString().contains('INVALID_EMAIL')) {
errorMessage = 'This is not a valid email address';
} else if (error.toString().contains('WEAK_PASSWORD')) {
errorMessage = 'This password is too weak.';
} else if (error.toString().contains('EMAIL_NOT_FOUND')) {
errorMessage = 'Could not find a user with that email.';
} else if (error.toString().contains('INVALID_PASSWORD')) {
errorMessage = 'Invalid password.';
}
_showErrorDialog(errorMessage);
} catch (error) {
var errorMessage = 'Could not authenticate you. Please try again later.' +
error.toString();
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
auth.dart:
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
// final url = Uri.http('http://localhost:8000/api/', 'urlSegment');
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
//'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(
Duration(
seconds: int.parse(
responseData['expiresIn'],
),
),
);
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate!.toIso8601String(),
},
);
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
This is the backend(Deno) part of the project:
auth_controller.ts:
async register(ctx: RouterContext) {
const { email, password } = await ctx.request.body().value;
let user = await User.findOne({ email });
if (user) {
ctx.response.status = 422;
ctx.response.body = { message: "Email is already exist" };
return;
}
const hashedPassword = hashSync(password);
user = new User({ email, password: hashedPassword });
await user.save();
ctx.response.status = 201;
ctx.response.body = {
id: user.id,
name: user.name,
email: user.email
};
}
And this is the user.ts class:
export default class User extends BaseModel {
public id: string = "";
public name: string = "";
public email: string = "";
public password: string = "";
constructor({ id = "", name = "", email = "", password = "" }) {
super();
this.id = id;
this.name = name;
this.email = email;
this.password = password;
}
static async findOne(params: object): Promise<User | null> {
const user = await userCollection.findOne(params);
if (!user) {
return null;
}
return new User(User.prepare(user));
}
async save() {
const _id = await userCollection.insertOne(this);
this.id = _id;
return this;
}
}
I get this error message when I want to test the application on Android emulator:
type 'Null' is not a subtype of type 'String'
When I try the backend server using Postman and send post request to http://0.0.0.0:8000/api/register address. I get correct response and it works, but I don't know why do I get Null response using the Flutter app?
I tried to print the variables in both front and backend side of the application and it seems they all are good and correct but I can not understand why do I get this error message?!
probably you got a null value in your map in this part since map return a null value when can't find a key, check if the Map value is not null
try {
if (_authMode == AuthMode.Login) {
// Log user in
await Provider.of<Auth>(context, listen: false).login(
_authData['email'] as String, // can return a null value
_authData['password'] as String, // can return a null value
);
} else {
// Sign user up
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'] as String, // can return a null value
_authData['password'] as String, // can return a null value
);
}
}
Seems you're getting a null as a response value instead of a String.
EDIT:
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Check email and password are not null. And getting the correct values.
Actually the problem was from these two lines of code:
_token = responseData['idToken'];
_userId = responseData['localId'];
Because it wasn't passing these data in response from the backend side.

How to get data from the CurrentUser on flutter Firebase Authentification

I have this Firebase Authentication Providers with who I can create an user, Sign In and Sign Out with the methods (only with email and password)
My problem I that in the UI I want to show data from the current User once the user has Sign In and I don't know how.
For example showing the email in a TextWidget or get the email as a variable for other stuff.
final firebaseAuthProvider = Provider<FirebaseAuth>((ref) {
return FirebaseAuth.instance;
});
class AuthenticationService {
final FirebaseAuth _firebaseAuth;
final Reader read;
AuthenticationService(this._firebaseAuth, this.read);
Stream<User?> get authStateChange => _firebaseAuth.authStateChanges();
Future<String> signIn({required String email, required String constrasena, required String nombreUsuario}) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: constrasena,
);
return "Login Successful";
} on FirebaseAuthException catch (e) {
return e.message ?? 'Error';
}
}
Future<String> signUp({required String email, required String constrasena, required String nombreUsuario}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: constrasena,
);
read(addPerson(Person(nombre_de_usuario: nombreUsuario, email: email, videosVistos: 0)));
return "Signup Successful";
} on FirebaseAuthException catch (e) {
print(e.message);
return e.message ?? 'Error';
}
}
Future<void> signout() async {
await _firebaseAuth.signOut();
}
}
final authServicesProvider = Provider<AuthenticationService>((ref) {
return AuthenticationService(ref.read(firebaseAuthProvider), ref.read);
});
final authStateProvider = StreamProvider<User?>((ref) {
return ref.watch(authServicesProvider).authStateChange;
});
Thanks You!
You can use FirebaseAuth.instance.currentUser.
Example:
Get the user on your initState.
_user = FirebaseAuth.instance.currentUser;
And on your build method:
Text(_user?.email ?? 'No email')

Using REST API to verify email and sign up user (Dart and Flutter)

I am trying to sign up user using REST API. I am so far able to signup user without verification. However, I need to verify the user's email by sending a confirmation email and then sign up the user after confirmation. How can I accomplish that?
Here's my current code:
class Auth with ChangeNotifier {
String _token;
DateTime _expiryDate;
String _userId;
Timer _authTimer;
String get token {
if (_expiryDate != null &&
_expiryDate.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
}
bool get isAuth {
return token != null;
}
String get userId{
return _userId;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url =
'`https://www.googleapis.com/identitytoolkit/v3/relyingparty`/$urlSegment?key={MyAPIKEY}';
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now()
.add(Duration(seconds: int.parse(responseData['expiresIn'])));
notifyListeners();
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'signupNewUser');
}
}