How to get user credentials from firebase userdataMap - flutter

I have used firebase auth for login and registration. In that I created a map in relatime database to store users credential.
Like This
Future validateForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.createUserWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
Map userDataMap = {
"name": _namecontroller.text.trim(),
"email": _emailcontroller.text.trim(),
"phone": _phonecontroller.text.trim(),
};
usersRef.child(firebaseUser.uid).set(userDataMap);
displayToast("Succesfully Registered!", context);
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
} else {
displayToast("User was unable to create", context);
}
}
}
}
displayToast(String msg, BuildContext context) {
Fluttertoast.showToast(msg: msg);
}
Now please help me how to add extra information to this map from another page and also how to access these details from database to app

Related

How to get user credential while moving to welcome screen in flutter

I have created simple home screen for login and register,
Here I have taken readymade code from a channel, and now I need to change little bit..
code is simple, so no more details to explain
just I want to pass Usercredential to my welcome screen...
here is my code
class MainPage extends StatelessWidget {
const MainPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context,snapshot){
if(snapshot.hasData)
{
print(snapshot.data);
return WelcomePage(usercredential:
//how to get usercredential,
);
}
else
{
return AuthPage();
}
},
),
);
}
}
here is my login page's login code
Future signin() async {
UserCredential? usercredential;
try {
usercredential=await FirebaseAuth.instance.signInWithEmailAndPassword(
email: txtemailcontroller.text, password: txtpasswordcontroller.text);
} on FirebaseAuthException catch (e) {
print("Error is =" + e.toString());
}
}
and register page's register code
Future signup() async {
UserCredential? usercredential;
try {
if (txtconfirmpasswordcontroller.text.trim() ==
txtpasswordcontroller.text.trim()) {
usercredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: txtemailcontroller.text,
password: txtpasswordcontroller.text);
} else {
print("passwrod does not match");
}
} on FirebaseAuthException catch (e) {
print('Error while register' + e.toString());
}
if (usercredential != null) {
String userid = usercredential.user!.uid;
UserModel newuser = UserModel(
email: txtemailcontroller.text,
userid: userid,
fullname:
txtfirstnamecontroller.text + ' ' + txtlastnamecontroller.text,
profilepicture: '');
}
}
so far I know, user credential generated while createuserwithemailandpassword and signinwithemailandpassword method, but how to get it here....where I need...
Add this In your Welcome page:
User? currentUser=FirebaseAuth.instance.currentUser;
Then you can call it any where and get user details like email & id & display name.
for example:
currentUser.email
or
currentUser.uid

Flutter Riverpod Firebase currentUser Provider not updated

I'm beginner in Flutter, Riverpod for the state management and firebase for the authentication.
I'm looking to retrieve the logged user's email to pass to my postgres database and retrieve all the user information. In a first time, I just try to display the nickname of the current user. I am facing a problem when I log out of the app to log back in. The auth providers are not updated so I get informations from the very first connected user. For example currentUserEmailProvider still get the first connected user email. Any help is welcome, I'm really stuck.
My auth_repository.dart:
class AuthRepository {
const AuthRepository(this._auth);
final FirebaseAuth _auth;
Stream<User?> get authStateChange => _auth.idTokenChanges();
Stream<User?>get authUserChange => _auth.userChanges();
String? get currentUserEmail => _auth.currentUser?.email;
Future<User?> signInWithEmailAndPassword(
String email, String password) async {
_auth.currentUser?.reload();
try {
final result = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
return result.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
throw const ErrorHandler(message: 'User not found');
} else if (e.code == 'wrong-password') {
throw const ErrorHandler(message : 'Wrong password');
} else {
throw const ErrorHandler(message: 'An error occurred. Please try again later');
}
}
}
Future<AppUser?> registerWithEmailAndPassword(String email, String password, String nickname, String role, String firstname, String lastname) async {
// Sans ces deux lignes la création d'un nouveau compte entraîne un login automatique sur ce compte
FirebaseApp app = await Firebase.initializeApp(
name: 'Secondary', options: Firebase.app().options);
try {
AppUser? appUser = await UserRepository(email).saveUser(email, nickname, role, firstname, lastname);
if(appUser != null) {
try {
UserCredential result =
await FirebaseAuth.instanceFor(app: app).createUserWithEmailAndPassword(email: email, password: password);
User? user = result.user;
if(user == null) {
throw Exception("user from firebase not found");
}
return appUser;
} on FirebaseException catch(e) {
await UserRepository(email).deleteUser(email);
print(ErrorHandler(message: e.code.toString()));
}
} else {
throw Exception("user from postgres database not found");
}
} on PostgreSQLException catch(e) {
print(ErrorHandler(message: e.code.toString()));
}
return null;
}
Future<void> signOut() async {
await _auth.signOut();
}
}
My user_repository.dart:
class UserRepository {
final String email;
PostgreSQLConnection? connection;
UserRepository(this.email){
connection = (connection == null || connection!.isClosed == true
? PostgreSQLConnection(
'10.0.2.2', 5432, DatabaseAccess.databaseName,
queryTimeoutInSeconds: 3600,
timeoutInSeconds: 3600,
username: DatabaseAccess.databaseUser,
password: DatabaseAccess.databasePassword) : connection);
}
}
Future<AppUser?> getCurrentUser(String? currentEmail) async {
print(currentEmail);
try {
await connection!.open();
final result = await connection!.mappedResultsQuery(
'select * from public.user where email = #emailValue',
substitutionValues: {
'emailValue': currentEmail,
},
allowReuse: true,
timeoutInSeconds: 30,
);
final userFromDataBase = result[0]['user']!;
return AppUser(
email: userFromDataBase['email'],
nickname: userFromDataBase['nickname'],
role: userFromDataBase['role'],
firstname: userFromDataBase['firstname'],
lastname: userFromDataBase['lastname'],
);
} on PostgreSQLException catch(e) {
print(ErrorHandler(message: e.toString()));
return null;
}
}
}
My providers.dart:
final authRepositoryProvider = Provider<AuthRepository>((ref) {
return AuthRepository(FirebaseAuth.instance);
});
final authStateProvider = StreamProvider<User?>((ref) {
return ref.read(authRepositoryProvider).authStateChange;
});
final currentUserEmailProvider = Provider<String?>((ref) {
return AuthRepository(FirebaseAuth.instance).currentUserEmail;
});
final userRepositoryProvider = Provider.autoDispose<UserRepository>((ref) {
return UserRepository(ref.read(currentUserEmailProvider)!);
});
final futureCurrentUserProvider = Provider<Future<AppUser?>>((ref) {
return ref.read(userRepositoryProvider).getCurrentUser(ref.read(currentUserEmailProvider));
});
final currentUserProvider = FutureProvider.autoDispose<AppUser?>((ref) => ref.read(userRepositoryProvider).getCurrentUser(ref.read(currentUserEmailProvider)));
My home_screen.dart:
class HomeScreen extends HookConsumerWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final currentUser = ref.watch(currentUserProvider);
return Scaffold(
body: currentUser.when(
data: (user) => _buildBody(context, user, ref),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => _errorBody(context, ref),
)
);
}
Widget _buildBody(BuildContext context, AppUser? user, WidgetRef ref) {
if(user == null) {
return _errorBody(context, ref);
} else {
return Center(child: Text(
'Welcome ${user.getNickname}',
style: const TextStyle(fontSize: 20),
));
}
}
Widget _errorBody(BuildContext context, WidgetRef ref) {
return const Center(child: Text(
"Error: No user found",
style: TextStyle(fontSize: 20, color: Colors.red),
));
}
}
Try changing
final currentUserProvider = FutureProvider.autoDispose<AppUser?>((ref) => ref.read(userRepositoryProvider).getCurrentUser(ref.read(currentUserEmailProvider)));
to
final currentUserProvider = FutureProvider.autoDispose<AppUser?>((ref) => ref.read(userRepositoryProvider).getCurrentUser(ref.watch(currentUserEmailProvider)));
and changing
final currentUserEmailProvider = Provider<String?>((ref) {
return AuthRepository(FirebaseAuth.instance).currentUserEmail;
});
to
final currentUserEmailProvider = Provider<String?>((ref) {
return ref.read(authRepositoryProvider).currentUserEmail;
});
Ok I resolved my problem with this following. To be simplier I removed the singleton in my user_repository.dart. The problem was from my providers and I found a way to use the authUserChanges() method :
providers.dart :
final futureCurrentUserProvider = Provider<Future<AppUser?>>((ref) {
return UserRepository().getCurrentUser(ref.watch(emailChangeProvider));
});
final currentUserProvider = FutureProvider.autoDispose<AppUser?>((ref) => UserRepository().getCurrentUser(ref.watch(emailChangeProvider)));
final authChangeProvider = StreamProvider<User?>((ref) {
return ref.read(authRepositoryProvider).authUserChange;
});
final emailChangeProvider = Provider<String?>((ref) {
return ref.watch(authChangeProvider).value?.email;
});

Flutter Connection State Management

Hello I am doing my fist App in Flutter and i am just setting up the authentication with FireBase, and a mistake its happenning. Im trying to manage the state and navigate between Home and Login with the streambuilder, and its working fine but only if i do a hot restart on Android Studio after registering a new user. After the hot reload it works fine, i am able to login with any of the existing users and it navigates to the home screen, and when i log out goes back to login screen, but if i create new user than just stops working, the screens do not alterate anymore when i log in with any of the old users...
here its my main
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primaryColor: cPrimary),
home: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.active){
if(snapshot.hasData){
return Home_Screen();
} else if (snapshot.hasError){
return Center(child: Text('${snapshot.error}'),);
}
} else if (snapshot.connectionState == ConnectionState.waiting){
return Center(child: CircularProgressIndicator(color: cPrimary,));
}
return LoginScreen();
}
)
);
}
}
Here is my login and register functions
//Sign Up
Future <void> signUp({
required String email,
required String password,
required String username,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty && username.isNotEmpty){
UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//add user to database
await _firestore.collection('users').doc(userCredential.user!.uid).set({
'username' : username,
'email' : email,
'uid' : userCredential.user!.uid,
});
}
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
}
//Log In
Future <void> logIn({
required String email,
required String password,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty ){
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);}
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
}
and here its how i am calling the functions on my screens
ElevatedButton(
onPressed: () async {
setState(() {
_isLoading = true;
});
await AuthService().logIn(
email: _emailController.text,
password: _passwordController.text,);
setState(() {
setState(() {
_isLoading = false;
});
});
},
ElevatedButton(
onPressed: () async {
setState(() {
_isLoading = true;
});
await AuthService().signUp(
email: _emailController.text,
password: _passwordController.text,
username: _usernameController.text,
);
setState(() {
_isLoading = false;
});
After creating the user account, ensure you log in as well.
//Sign Up
Future <void> signUp({
required String email,
required String password,
required String username,
}) async {
try {
if(email.isNotEmpty && password.isNotEmpty && username.isNotEmpty){
UserCredential userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//add user to database
await _firestore.collection('users').doc(userCredential.user!.uid).set({
'username' : username,
'email' : email,
'uid' : userCredential.user!.uid,
});
}
// add this
await logIn(email: email, password: password);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
}

Flutter bloc registration trouble

I have bloc, which listen to changes of currentUser state from firebase.
AuthBloc({#required AuthService authService})
: assert(authService != null),
_authService = authService,
super(AuthInitial()) {
_userSubscription = _authService.currentUser
.listen((user) => add(AuthenticationUserChanged(user)));
}
Then add event and the event call this function
Stream<AuthState> _mapAuthenticationUserChangedToState(
AuthenticationUserChanged event) async* {
if (event.user != null) {
// TO GET CUSTOM USER FROM FIRESTORE because of expiration, etc.
var user = await _authService.getUser(event.user.uid);
if (user.expiration == "") {
yield NotAuthorized(user);
} else {
var isAfter =
DateTime.now().toUtc().isAfter(DateTime.fromMillisecondsSinceEpoch(
user.expiration.millisecondsSinceEpoch,
isUtc: false,
).toUtc());
if (isAfter) {
yield NotAuthorized(user);
} else {
yield Authenticated(event.user);
}
}
} else {
yield Unautheticated();
}
But in my RegisterCubit I have signUpSubmitted method, which creates Firebase user and immediately after this is called my AuthBloc, which make sense.
But in my Bloc i need my custom Firestore user, which i have to create after FirebaseUser creation(because I need UID and email).
And this is the problem.
Future<void> signUpFormSubmitted() async {
if (!state.status.isValidated) return;
emit(state.copyWith(status: FormzStatus.submissionInProgress));
try {
await _authService
.registerUser(state.email.value, state.password.value)
.then((value) async {
// THIS IS CALLED AFTER BLOC
// I NEED TO CALL IT AFTER _registerUser() but in front of BLOC
var user =
ApplicationUser(uid: value.user.uid, email: value.user.email);
await _authService.addUserToDocument(user);
});
emit(state.copyWith(status: FormzStatus.submissionSuccess));
} on Exception {
print(Exception);
emit(state.copyWith(status: FormzStatus.submissionFailure));
}
}
My AuthService methods
Future<UserCredential> registerUser(email, password) =>
_auth.createUserWithEmailAndPassword(email: email, password: password);
Future<void> addUserToDocument(ApplicationUser user) {
return _db.collection('users').doc(user.uid).set({
'uid': user.uid,
'firstname': '',
'lastname': '',
'age': '',
'expiration': '',
'email': user.email
});
}

Flutter, firebase. I want to show my registration form data other than the email and password and connect to a unique uid

Register Screen On Pressed method given, I believe there is a problem with calling Firebase user = result.user
onPressed: () async {
if(_formKey.currentState.validate()){
setState(() => loading = true);
dynamic result = await _auth.registerWithEmailAndPassword(email, password);
FirebaseUser user = result.user;
await DatabaseService(uid: user.uid).newUserInfo(
_nameC.text,
_cityC.text,
_contactnoC.toString()
);
if(result == null) {
setState(() {
error = 'Please supply a valid email';
loading = false;
});
}}},
// Database backend
class DatabaseService {
final String uid;
DatabaseService ({this.uid});
final CollectionReference userdata2 = Firestore.instance.collection('UserData');
Future newUserInfo(String name, String city, String contactno) async {
return await userdata2.document(uid).setData({
'name' : name,
'city' : city,
'contactno' : contactno
});
}}
// authentication backend
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
DatabaseService(uid: user.uid);
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
} }
// user.dart
class User {
final String uid;
User({this.uid});
}