Flutter firebase user problem trying to link to a model - firebase

the error I'm getting:
A value of type 'UserA?' can't be returned from the method
'_userFromFirebaseUser' because it has a return type of 'User'
I'm following along this tutorial: Flutter & Firebase App Tutorial #6 - Custom User Model
At about 5:35 into the video he talks about returning the Firebase user object and linking it to the model. Now the video is about 2 years old, so Firebase has moved on a bit. FirebaseUser is now just called User, but I think in my changes I've made a mistake. Here is my code:
class AuthService{
final FirebaseAuth _auth = FirebaseAuth.instance;
//create user object based on firebaseuser
User _userFromFirebaseUser(User? user) {
return user != null ? UserA(uid: user.uid) : null;
}
This is my model:
class UserA {
final String uid;
UserA({ required this.uid });
}
Since FirebaseUser is now just called User I've changed the model to be UserA since I was getting confused.
Any suggestion on what I'm doing wrong?

You're mixing up the two types of users in your code.
The video has two types: FirebaseUser and User, which you have mapped to Users and UserA respectively.
With your types, the function should be:
UserA? _userFromFirebaseUser(User? user) {
return user != null ? UserA(uid: user.uid) : null;
}
Aside from the type change, the ? is needed in Dart nowadays to indicate that you may return either a UserA object or null.

Related

Cannot get the currentUser's displayName with FirebaseAuth

I have made a sign-in page, and a sign-up page with Firebase Authentication in Flutter and Dart.
After the sign up, I'm trying to retrieve the current user's displayName, however, when I try retrieving it, I seem to get not the current one, but the one that I signed up with before this one.
However, when I for example hot-restart the app, I get the current user's details just fine.
I try to retrieve the current user's displayName property with this code:
static String? getUsername() {
return FirebaseAuth.instance.currentUser?.displayName!;
}
The way I call this, is I initialize a variable to store the username which I get from the method, on a different dart file, different from the signUp page I got. I also call this method in the initState() method.
This is how I sign-up the user and set the displayName:
static void signUpUser(String username, String emailAddress, String password) async {
try {
final credential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
password: password,
);
// Here I set the displayName property
await credential.user!.updateDisplayName(username);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {}
else if (e.code == 'email-already-in-use') {}
} catch (e) {}
}
I tried to use the user.reload(), and FirebaseAuth.userChanges() functions, but these did not seem to fix my problem.
Maybe I'm trying to retrieve the displayName property wrong, what am I missing? I'm quite new to developing my own apps and working with Firebase.
The Future that updateDisplayName returns completes when the call has been made to the underlying Firebase SDK. It does not automatically update the user profile in your application at that point though. That will only happen automatically once every hour (when the SDK refreshes the ID token on which that profile is based), or when the user signs out and in again.
To force a refresh of the profile from your application code outside of those automatic conditions, you can call reload() on the user object.

Update user data in provider if user document has changed on firestore

I would like to update user data in provider if user document has changed on firestore.
Actually, I use provider to store current user data in a variable called _currentUser. This variable is helpful to display user data on several screens.
class UserService extends ChangeNotifier {
final CollectionReference usersCollection =
FirebaseFirestore.instance.collection('users');
late User _currentUser;
User get currentUser => _currentUser;
Future<User> getUser(String uid) async {
var userData = await usersCollection.doc(uid).get();
User user = User.fromMap(userData.data()!);
_currentUser = user;
print("nb lives : ${_currentUser.nbLives}");
notifyListeners();
return user;
}
}
Current User data can change over time and the problem of my current solution is that if user document has changed, _currentUser variable is not updated and the old data is displayed on app screens. I want to find a way to listen to this document and update _currentUser variable if user data has changed.
A solution i found is to use Streams to fetch user data but I don't like it because it runs on a specific screen and not in background.
Does anyone have ever face a similar issue ? Thank you for your help !
class UserService extends ChangeNotifier {
final CollectionReference usersCollection =
FirebaseFirestore.instance.collection('users');
late User _currentUser;
User get currentUser => _currentUser;
void init(String uid) async {
// call init after login or on splash page (only once) and the value
// of _currentUser should always be updated.
// whenever you need _currentUser, just call the getter currentUser.
usersCollection.doc(uid).snapshots().listen((event) {
_currentUser = User.fromMap(event.data()!);
notifyListeners();
});
}
}
You can do this in many ways
When you update the _currentUser in firestore, update the same in the provider variable with notifylistner and wrap your widget that uses the _currentUser in Consumer, so the changes get updated always.
In you root widget use StreamBuilder with stream: ....snapshots() and on change update the _currentUser
This depends on your use-case and want things to react on changes to _currentUser.

The getter 'uid' was called on null in flutter

I'm implementing firebase authentication in flutter application but while trying to get user uid , it is crashing and show noSuchMethodError uid is null , if anyone could help , it is deeply appreciated
That's how i init my variables
class _UserRegistrationState extends State<UserRegistration> {
FirebaseAuth auth;
DocumentReference reference;
Reference storage;
PickedFile imageUri;
final ImagePicker _imagePicker = new ImagePicker();
#override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
// the uid is where the logcat is pointing too and it is null
reference = FirebaseFirestore.instance.collection('users').doc(auth.currentUser.uid);
storage = firebase_storage.FirebaseStorage.instance.ref('avatar').child(auth.currentUser.uid);
}
When you sign in to Firebase Authentication, the SDK automatically persists the user's credentials in local storage. When you restart the app, the SDK tries to restore the user's authentication state from the stored credentials. This requires that it calls the servers to get a new ID token, and for example to check if the account was deleted/disabled in the meantime.
Depending on the platform where you run your code, the calls to the server may have completed before your auth.currentUser runs, or not. To safely respond to the user state, always use an auth state listener as shown in the FlutterFire documentation on responding to auth state changes:
#override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
FirebaseAuth.instance.authStateChanges().listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
reference = FirebaseFirestore.instance.collection('users').doc(auth.currentUser.uid);
storage = firebase_storage.FirebaseStorage.instance.ref('avatar').child(auth.currentUser.uid);
}
});
}
currentUser → User?
Returns the current User if they are currently signed-in, or null if not.
So most likely thing is that you are not logged in and therefore passing null to reference

Custom user model to firebase authentication

I have an AuthService class that has the following code
UserData _userDetFromFirebaseUser(User user) {
if (user != null) {
return UserData(uid: user.uid);
} else {
return null;
}
}
Stream<UserData> get userData {
return _firebaseAuth.authStateChanges().map(_userDetFromFirebaseUser);
}
And I used StreamProvider from the flutter provider package
Widget build(BuildContext context) {
return StreamProvider<UserData>.value(
value: AuthService().userData,
child: MaterialApp(
home: HomeController(),
),
);
}
It is all working well but the problem is that I want to add custom variables to the UserData model and get it through the provider and I don't know how to to do it. can You please help me?
the usermodel goes like this
class UserData {
final String uid;
String name;
String phoneNumber;
UserData({this.uid});
}
also: I tried calling Provider.of method and adding the fields in the app but then the app restarts the state is lost I want to save that state( the field variables in the model)I am new to Provider and state management so Please elaborate the answer.
That is one of my next tasks. From my understanding so far, you create a root level folder in FireStore called /users and add for each user a document with the UID of the user as the document id.
Unfortunately I am still fighting other Firestore challenges before I can tell, whether this is already sufficient to get all the fields of that user document together with the returned User element upon login.

Cannot login using flutter, redux and firebase-auth as described in FlutterByExample

I have created an action as follows:
class EmailLogIn {
EmailLogIn({this.email, this.password});
String email;
String password;
}
a reducer as follows:
FirebaseUser _emailLogIn(FirebaseUser user, action) {
return action.user;
}
after following the flutter by example tutorial.
The middleware is executed but I get an error in the reducer. action.user getter is not recognised.
Please assist.
Also note: A similar question exists at Flutter, Redux and Firebase Auth Invalid argument(s) error and I was following the tutorial at Flutter by example: LogIn Redux Cycle contd
Yes, it correct because the class EmailLogIn doesn't contain user attribute but it contains email and password when you do action.user getter is not recognized because user doesn't exist in the class, if you take a look at FlutterByExample code the LogInSuccessful contains final FirebaseUser user; not email and password!

Resources