How do I print a value from an instance of 'User' in a flutter? - flutter

class User {
String token;
User({this.token});
}
class AuthService {
final String url = 'https://reqres.in/api/login';
final controller = StreamController<User>();
Future<User> signIn(String email, String password) async {
final response =
await post(url, body: {'email': email, 'password': password});
final data = jsonDecode(response.body);
final user = _userFromDatabaseUser(data);
// print(user.token);
controller.add(user);
return user;
}
//create user obj based on the database user
User _userFromDatabaseUser(Map user) {
return user != null ? User(token: user['token']) : null;
}
//user stream for provider
Stream<User> get user {
return controller.stream;
}
}
//in Sign in page
onPressed: () async {
if (_formKey.currentState.validate()) {
dynamic result = await _auth.signIn(email, password);
print(result); // Instance of 'User'
}
}
I am new to flutter and want to make an app that only authenticated users. I'm trying to read user token data from a stream. then check that token is not null if I got token then goto home page otherwise it will show error how do I print or store token value?

You can do is when you get the user after the sign In:
User result = await _auth.signIn(email, password);
Then to see the data you can do is
print(result.token);
which will give you the token, and then you can use the shared prefrences to store your token and access it.
Check out the docs for the it: https://pub.dev/packages/shared_preferences

You can override Object.toString method.
you can add this method in your User class to print the token instead of Instance of 'User'.
#override
String toString() {
// TODO: change the below return to your desired string
return "token: $token";
}

You can print using
print(userModel.toString());

Related

Can we set user displayName in firebase using password authentication through flutter? [duplicate]

I can save the email and the password with Firebase Authentication. I also save this information with Cloud Firestore. But how can I add and save the displayName after registering?
my code:
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
// create a new document for the user with the uid
await DatabaseService(uid: user.uid)
.updateUserData('User', user.email, 'test.de/test.png', user.uid);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
the register form button:
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth
.registerWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
error = 'Valid email, please';
loading = false;
});
}
}
}
You can use updateProfile method given in the FirebaseUser class to update the name and photo url.
updateProfile({String displayName, String photoURL}).
For email you can use the different method
updateEmail(String newEmail) which is a async method.
Or to save the username directly into the firestore, after successful login you can use 'set' method of the FirebaseFirestore to save email, password and the username.
Here's the code if you want to save the Username together with the email and password
final FirebaseAuth _auth = FirebaseAuth.instance;
//register with email & password & save username instantly
Future registerWithEmailAndPassword(String name, String password, String email) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
user.updateProfile(displayName: name); //added this line
return _user(user);
} catch(e) {
print(e.toString());
return null;
}
}
late User userFirebase;
Future<UserCredential> userCredential =await //Your code signin or signup
await userCredential.then((UserCredential value) {
userFirebase = value.user!;
});
await userFirebase.updateDisplayName(event.name);
You can use updateDisplayName() and updatePhotoURL() methods on a User object to add the displayName/profile image to Firebase user.
final userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//After creating a user in Firebase, we then are able to change name/pictue
await userCredential.user?.updateDisplayName(name);
await userCredential.user?.updatePhotoURL(imageUrl);
As of october 2021, updateProfile() is deprecated, and you should use updateDisplayName() and updatePhotoURL() instead.

Need to get state data from Authentication Cubit inside another Cubit. In essence, I need to read the state

Note: I've seen similar questions all over Stackoverflow, but none of them exactly answer this.
Context:
I have an authentication cubit that has a variety of user states:
/// User exists, includes user's access and refresh tokens.
class User extends AuthenticationState {
final Tokens? tokens;
final bool justRegistered;
final bool tokensAvailable;
User({
required this.tokens,
this.justRegistered = false,
this.tokensAvailable = true,
});
#override
List<Object?> get props => [tokens, justRegistered, tokensAvailable];
}
/// No authenticated user exists.
class NoUser extends AuthenticationState {}
/// User is currently being registered or signed in.
class UserLoading extends AuthenticationState {}
Problem:
I have a Posts Cubit that needs to manage API calls and pass in the current user's access token to them in order to work. However, this access token is only stored inside the Authentication Cubit's state (in the User state, inside the tokens variable).
Is there a (good practice) way to get this token from the Authentication Cubit's User state inside the Post Cubit so I can use it to send API requests that require tokens for authentication to return posts?
Thanks!
You can create a class something like API Provider and authenticateService, pass and use in your Cubit to call API :
For example:
Future<Response<dynamic>> _callAndRetryDelete(
String url, {
int validStatus,
int retries,
}) async =>
retry(
() async {
final Map<String, String> authHeaders = await _authenticationService.getAuthHeaders;
if (authHeaders == null) {
throw ApiError('Could not get authorization', endpoint: url, method: HTTPMethod.Delete);
}
_client.options = _options(success: validStatus, authHeaders: authHeaders);
try {
return await _client.delete(url);
} on DioError catch (error) {
final String message = _error(error);
throw ApiError(message, endpoint: url, method: HTTPMethod.Delete);
}
},
maxAttempts: retries,
);
AuthenticaionService.class
Future<void> _doLogin(Map<String, dynamic> params) async {
final Response<Map<String, dynamic>> response =
await _handler.post(_loginEndpoint, body: params,
validStatus: 200);
final Map<String, String> res =
response?.data?.map((String key, dynamic value) => MapEntry<String, String>(key, value.toString()));
final Authentication authentication = Authentication.parse(res);
await _parseAndStore(authentication);
return authentication;}
AuthCubit:
Future<void> signIn() async => cubitAction(
action: () async {
emit(AuthenticationLoading());
await _authenticationService.signIn(payload);
emit(AuthenticationDone);
}
);

show display name after signUp

I have a flutter firebase createUserWithEmailAndPassword function with the displayName update.
display name prints normally at the moment of fb user creation.
After signup MainPage loads with the users email and displayName. But displayName returns null value error. If I delete displayName from the MainPage - all works fine.
If I reload app, it works fine.
When I login, it works fine.
It can't pass the displayName at the moment of signup only.
Where I am wrong?
class AuthServiceProvider extends ChangeNotifier {
final auth.FirebaseAuth _firebaseAuth = auth.FirebaseAuth.instance;
final googleSingIn = GoogleSignIn();
UserModel? _userFromFirebase(auth.User? user) {
if (user == null) {
return null;
}
return UserModel(
user.displayName,
user.uid,
user.email,
);
}
Stream<UserModel?>? get user {
return _firebaseAuth.authStateChanges().map(_userFromFirebase);
}
Future<UserModel?> createUserWithEmailAndPassword(
String name,
String email,
String password,
) async {
try {
final userCred = await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
auth.User? firebaseUser = _firebaseAuth.currentUser;
if (firebaseUser != null) {
await firebaseUser.updateDisplayName(name);
await firebaseUser.reload();
firebaseUser = _firebaseAuth.currentUser;
}
print('FIREBASE USER IS $firebaseUser');
return _userFromFirebase(firebaseUser);
} catch (e) {
print(e.toString());
return null;
}
}
}
If your class were to extend either StatelessWidget or StatefulWidget, then all you'd have to do is to pass the data (displayName) between the screens.
This is not an answer but a suggestion:
You should try changing the ChangeNotifier to a StatefulWidget
and pass the data between screens...
You could also setup an
Authentication class that will hold all these Future methods so that
these calls can be reusable in your code. With this method, all you have to do is to call the specific function and give its required parameters.
As usually the solution is very simple if you think a little bit.
As all this is through the firebase auth, at the main page loading I just grab the firebase user with its display name that is saved in FB both for GoogleSignIn and createUserWithEmailAndPassword (required at registration)
import 'package:firebase_auth/firebase_auth.dart' as auth;
final auth.FirebaseAuth _firebaseAuth = auth.FirebaseAuth.instance;
final String firebaseUser =
_firebaseAuth.currentUser!.displayName ?? 'Unknown user';

Firebase documentation for flutter does not work for deleting user

The following documentation on deleting a user does not work:
try {
await FirebaseAuth.instance.currentUser.delete();
} catch on FirebaseAuthException (e) {
if (e.code == 'requires-recent-login') {
print('The user must reauthenticate before this operation can be executed.');
}
}
"delete()" is not a function recognized by Flutter. "FirebaseAuthException" is also not recognized by Flutter.
How do I delete a user? Where do I find this information?
Using flutter, if you want to delete firebase accounts together with the associated firestore user collection document, the following method works fine. (documents in user collection named by the firebase uid).
Database Class
class DatabaseService {
final String uid;
DatabaseService({this.uid});
final CollectionReference userCollection =
Firestore.instance.collection('users');
Future deleteuser() {
return userCollection.document(uid).delete();
}
}
Use Firebase version 0.15.0 or above otherwise, Firebase reauthenticateWithCredential() method throw an error like { noSuchMethod: was called on null }.
Authentication Class
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future deleteUser(String email, String password) async {
try {
FirebaseUser user = await _auth.currentUser();
AuthCredential credentials =
EmailAuthProvider.getCredential(email: email, password: password);
print(user);
AuthResult result = await user.reauthenticateWithCredential(credentials);
await DatabaseService(uid: result.user.uid)
.deleteuser(); // called from database class
await result.user.delete();
return true;
} catch (e) {
print(e.toString());
return null;
}
}
}
Then use the following code inside the clickable event of a flutter widget tree to achieve the goal:
onTap: () async {
await AuthService().deleteUser(email, password);
}

How do I return to the user stream in flutter

I'm having an issue return a Stream to a StreamBuilder widget in a flutter. I'm trying to access a custom class that is stored token.
class User {
String token;
User({this.token});
}
===============================
class AuthService {
String url = 'https://reqres.in/api/login';
String token = '';
// {
// "email": "eve.holt#reqres.in",
// "password": "cityslicka"
// }
Map data;
Future signIn(String email, String password) async {
final response =
await post(url, body: {'email': email, 'password': password});
data = jsonDecode(response.body);
print(data['token']);
token = data['token'];
_userFromDatabaseUser(data);
return data;
}
//create user obj based on the database user
User _userFromDatabaseUser(Map user) {
return user != null ? User(token: user['token']) : null;
}
//user stream for provider
Stream<User> get user {
return .................. ;
}
You could use a stream controller:
class AuthService {
final String url = 'https://reqres.in/api/login';
final controller = StreamController<User>();
Future<User> signIn(String email, String password) async {
final response = await post(url, body: {'email': email, 'password': password});
final data = jsonDecode(response.body);
final user = _userFromDatabaseUser(data);
controller.add(user);
return user;
}
//create user obj based on the database user
User _userFromDatabaseUser(Map user) {
return user != null ? User(token: user['token']) : null;
}
//user stream for provider
Stream<User> get user {
return controller.stream;
}
Please note that this approach is a simplistic example that has some flaws, you should read up on it in the documentation.
If you use this for the purpose you describe, you may want to look into the bloc pattern and it's implementation as flutter-bloc. It might seem easier to do the user in this way by hand, but once you reach the point where you have multiple of those streams, you may want a more structured approach.
You can use
Stream<User> get user async*{
yield .................. ;
}
you can use yield keyword when you want to return stream object.
2nd way you can use a stream controller. You can add value in controller and
listen wherever you want to listen in your app there is no need to return stream