Apple Sign in Flutter Firestore overwrites displayname - flutter

I managed to get apple sign in working and create a userdoc on my firestore collection ('Users). However when I log out and sign in again with apple it overwrites the name "" ... Because it only logs the name the first time you log in with apple. How do I stop the name field to be overwritten everytime the same person signs out and in again?
case AuthorizationStatus.authorized:
try {
final res = await FirebaseAuth.instance.signInWithCredential(credential);
if (fixDisplayNameFromApple != null && res.user!.displayName == null) {
await res.user!.updateDisplayName(fixDisplayNameFromApple);
res.user!.reload();
}
FirebaseFirestore.instance.collection('Users').doc(res.user!.uid).set({
'name' : fixDisplayNameFromApple,
'email': res.user!.email,
'uid': res.user!.uid,
'image': 'https://merakiapp.be/wp-content/uploads/2022/06/appleUser.png',
}, SetOptions(merge: true));
return res.user;
} catch (e) {
print("error");
}
break;
I tried to check if the doc already exists so it doesn't create (overwrites) the original doc. But then it doesn't create a doc on firestore:
case AuthorizationStatus.authorized:
try {
final res = await FirebaseAuth.instance.signInWithCredential(credential);
if (fixDisplayNameFromApple != null && res.user!.displayName == null) {
await res.user!.updateDisplayName(fixDisplayNameFromApple);
res.user!.reload();
}
await FirebaseFirestore.instance
.collection("Users")
.doc(res.user!.uid)
.get()
.then((doc) {
if(doc.exists) {
return res.user;
} else {
FirebaseFirestore.instance.collection('Users').doc(res.user!.uid).set({
'name' : fixDisplayNameFromApple,
'email': res.user!.email,
'uid': res.user!.uid,
'image': 'https://merakiapp.be/wp-content/uploads/2022/06/appleUser.png',
}, SetOptions(merge: true));
return res.user;
}
});
} catch (e) {
print("error");
}
break;

Related

Flutter Firebase web authentication setup issue

Description:
Trying to setup firebase authentication for web. Please guide how to implement and the steps needed for it. Or if there is some tutorial that explain it well. Need to way to implement authencication for web version only. Any help would be appreciated alot.
Here is I tried but not working for auth and getx. Thank you.
Future<void> checkLoginAndRediect() async {
Authentication authentication = Authentication();
final UserController userController = Get.find(tag: 'userController');
await authentication.autoLogin();
if (userController.previouslyLoggedIn) {
Get.offAll(
const Home(),
);
} else {
Get.offAll(
const SignupPage(),
);
}
Future<bool> init() async {
if (userID.isNotEmpty) {
userController.userID = userID;
var document = await FirebaseFirestore.instance
.collection('users')
.doc(userID)
.get();
if (document.exists) {
//updaiting user data locally from firebase
userController.setUser(
userID,
document.data()!['name'],
document.data()!['phone'],
document.data()!['email'],
document.data()!['username'],
document.data()!['profilePictureLink'] ??
"https://firebasestorage.googleapis.com/v0/b/matab-a53a8.appspot.com/o/DefaultProfile.png?alt=media&token=716eca5e-b939-4dfa-8e8e-72b0efc75f7f", //there is always a default profile picture but for those user which are reqistered earlier it will replace their as soon as they sign in, with default dummy pic
);
//fetching user's addresss from firebase
addressDatabaseService
.getAddress(userID)
.then((value) {})
.catchError((error) {
return false;
});
//fetching bank details here
var bankDetails =
FirebaseFirestore.instance.collection('bankDetails').doc("1").get();
bankDetails.then((value) {
transactionController.setBankDetails(
value.data()!['bankName'],
value.data()!['accountNumber'],
value.data()!['accountTitle'],
value.data()!['bankBranch']);
orderController.userID = userID;
}).catchError((error) {
debugPrint(error.toString());
});
//fetching user optional details from firebase if already exists there
optionalProfileDetailsController.getProfileDetails(
userID); //this will fetch and store user optional details in controller, controller calls database service itself to fetch data from database
userController.previouslyLoggedIn =
true; //updating user already exists flag to true
}
return true;
} else {
return false;
}
}
Future<void> autoLogin() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool userStatus = prefs.containsKey('uid');
if (userStatus) {
String? uid = prefs.getString('uid');
userID = uid!;
userController.userID = userID;
await init();
userController.previouslyLoggedIn = true;
} else {
userController.previouslyLoggedIn =
false; //if this is false then in main.dart=>checkLoginAndRediect we will check for this and redirect user to signup page
debugPrint("not connected");
}
}
login(String identifier, String password) async {
String errorMessage;
final auth = FirebaseAuth.instance;
try {
final UserCredential userCredential = await auth
.signInWithEmailAndPassword(email: identifier, password: password);
final User? user = userCredential.user;
if (user != null) {
if (!user.emailVerified) {
Get.snackbar(" Email not Verified ", "Please verify your email.",
colorText: whiteColor,
backgroundColor: Colors.red,
duration: const Duration(seconds: 5),
snackPosition: SnackPosition.BOTTOM);
return;
} else {
userID = user.uid;
userController.userID = userID;
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('uid', userCredential.user!.uid);
await init();
Get.offAll(() => const Home());
}
}
} on FirebaseAuthException catch (error) {
switch (error.code) {
case "user-not-found":
errorMessage = "Incorrect Email or Password".tr;
break;
case "wrong-password":
errorMessage = "Incorrect Password".tr;
break;
case "invalid-email":
errorMessage = "Email is not valid.".tr;
break;
default:
errorMessage = "Something Went Wrong,";
}
Get.snackbar(errorMessage, "Please Try Again".tr,
snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red);
}
}
signUp(String name, String phone, int usercnic, String email, String password,
String confirmPassword) async {
//below is a default image link, it will be replaced by user's profile picture when he/she sign up for the first time later on he can updateq his/her profile picture
String profilePictureLink =
"https://firebasestorage.googleapis.com/v0/b/matab-a53a8.appspot.com/o/DefaultProfile.png?alt=media&token=716eca5e-b939-4dfa-8e8e-72b0efc75f7f";
final auth = FirebaseAuth.instance;
String errorMessage;
if (confirmPassword != password) {
generateError("Incorrect Confirm password".tr, "Please try again".tr);
return;
}
try {
final UserCredential signUPResponse =
await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
User? user = signUPResponse.user;
if (user != null) {
userDBService.addUser(
user.uid, name, phone, email, usercnic, profilePictureLink);
userController.setUser(
user.uid, name, phone, email, usercnic, profilePictureLink);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('uid', user.uid);
await user.sendEmailVerification();
Get.snackbar(
"Email Verification",
"Please verify your email",
snackPosition: SnackPosition.BOTTOM,
);
var bankDetails =
FirebaseFirestore.instance.collection('bankDetails').doc("1").get();
bankDetails.then((value) {
transactionController.setBankDetails(
value.data()!['bankName'],
value.data()!['accountNumber'],
value.data()!['accountTitle'],
value.data()!['bankBranch']);
}).catchError((error) {
throw (error);
});
}
Get.offAll(() => const LoginPage());
} on FirebaseAuthException catch (error) {
switch (error.code) {
case "user-not-found":
errorMessage = "Incorrect Email or Password";
break;
case "wrong-password":
errorMessage = "Incorrect Password";
break;
case "email-already-in-use":
errorMessage = "Email already in use";
break;
case "invalid-email":
errorMessage = "Email is not valid.";
break;
case "weak-password":
errorMessage = "Password should be at least 6 characters ";
break;
default:
errorMessage = error.code;
}
// Get.snackbar(errorMessage.tr, "Please Try Again.".tr,
// snackPosition: SnackPosition.BOTTOM);
generateError(errorMessage.tr, "Please Try Again.".tr);
}
}
You need to start by adding the lib
flutter pub add firebase_auth
then you need to make sure you installed firebase core and it's working from your app to firebase,
flutter pub add firebase_core
to init your firebase app, start by setting the options
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: ,
appId: ,
messagingSenderId: ,
projectId: ,
authDomain: ,
storageBucket: ,
measurementId: ,
);
and the initialization of your app
switch (defaultTargetPlatform) {
case TargetPlatform.windows:
_app = await desktop.Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
break;
default:
_app = await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform);
}
await Firebase.initializeApp();
and todo simple log in try
try {
final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
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);
}
for more info please follow:
https://pub.dev/packages/fireflutter

StreamSubscription not cancel properly

I am following this guide to build my App. Then, I add a document listener to the "users" collection. Now the problem is even if I log out of the first account and log in to the second account, the stream is still reading the previous document if I manually change the document using the console.
Account _userInfo = Account(email: '', name: '', typeName: '', fcmToken: '', isDisable: false);
Account get userInfo => _userInfo;
StreamSubscription<DocumentSnapshot>? userListener;
Future<void> init() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseAuth.instance.userChanges().listen((user) async {
if (user != null) {
print('User != null');
_loginState = ApplicationLoginState.loggedIn;
await setFcmToken();
listenToMyself();
} else {
print('User null');
userListener?.cancel();
_loginState = ApplicationLoginState.loggedOut;
}
notifyListeners();
});
void listenToMyself() {
print('Listening to: ${FirebaseAuth.instance.currentUser!.uid}');
userListener = usersCollection.doc(FirebaseAuth.instance.currentUser!.uid).snapshots().listen(
(event) {
print("current data: ${FirebaseAuth.instance.currentUser!.uid} ${event.data()}");
_userInfo = Account.fromJson(event.data() as Map<String, dynamic>);
notifyListeners();
},
onError: (error) => print("Listen failed: $error"),
);
}
Future<void> setFcmToken() async {
String? token = await FirebaseMessaging.instance.getToken();
_token = token;
await FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid).set({'fcmToken': token}, SetOptions(merge: true));
}

How can i store the url of the image instead of path of the image in firestore flutter

I want to store the URL of the image like this -
this is how i want to store url of the image in firestore
This is my current condition -
Currently it's showing the path of the image not the url
onPressed: () async {
if (imageFile == null) {
print("error");
} else {
try {
final ref = storage
.ref()
.child('user_profile_images')
.child(name + '.jpg');
ref.putFile(imageFile!);
url = await ref.getDownloadURL();
if (url != null) {
print(url);
}
} catch (e) {
print(e);
}
dynamic user = await auth.createUserWithEmailAndPassword(
email: email, password: password);
await FirebaseFirestore.instance
.collection('users')
.doc(name)
.set({
'email': email,
'name': name,
'profileurl': imageFile?.path,
'userid': auth.currentUser?.uid
}).then((value) {
try {
if (user != null) {
Navigator.pushNamed(context, '/dashboard');
}
} catch (e) {
print(e);
}
});
}
}),
I have a feeling the multiple try/catch blocks are getting in your way. In addition, it is never a good idea to mix then and await in a single block of code.
Combining those, try the following:
try {
final ref = storage
.ref()
.child('user_profile_images')
.child(name + '.jpg');
ref.putFile(imageFile!);
url = await ref.getDownloadURL();
if (url != null) {
print(url);
}
dynamic user = await auth.createUserWithEmailAndPassword(
email: email, password: password);
dynamic value = await FirebaseFirestore.instance
.collection('users')
.doc(name)
.set({
'email': email,
'name': name,
'profileurl': url // 👈
'userid': auth.currentUser?.uid
});
if (user != null) {
Navigator.pushNamed(context, '/dashboard');
}
} catch (e) {
print(e);
}
'profileurl': imageFile?.path, => 'profileurl': url?.toString(),

Flutter Stripe paymentsheet is opening webpage (hooks.stripe.com) while processing payments

I am developing a flutter application which uses stripe for payments. I am using https://pub.dev/packages/flutter_stripe for this.
Everything is working fine but whenever I initiate payments I always get a webpage middleware (Screenshots attached). What am I doing wrong?
Here is my implementation in Flutter
Future<void> makePayment(String planName, String type) async {
Fluttertoast.showToast(msg: "initiating Payments, Please wait.");
ApiProvider provider = ApiProvider();
final tokenResponse = await provider
.getPaymentToken(PlanPayment(planName: planName, type: type));
if (tokenResponse != null) {`
var _service = locator<NavigationService>();
String secret = tokenResponse.clientSecret;
// make a get call from this url
Map<String, dynamic> paymentIntentData = Map();
await payment.Stripe.instance.initPaymentSheet(
paymentSheetParameters: payment.SetupPaymentSheetParameters(
merchantCountryCode: 'IN',
testEnv: true,
paymentIntentClientSecret: secret,
googlePay: true,
));
try {
// await Stripe.instance.handleCardAction(secret);
await payment.Stripe.instance.presentPaymentSheet().then((value) {});
await payment.Stripe.instance
.confirmPaymentSheetPayment()
.then((value) async {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': true});
});
} catch (e) {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': false});
print("Stripe error" + e.toString());
}
await provider
.confirmPayment(tokenResponse.transactionId)
.then((value) async {
await _service
.pushReplacementNamed(paymentStatus, args: {"isSuccess": value});
});
}
}
`
Maybe you have a webhook put in your account?
1)Provide valid Secret key
2)Provide valid Publisable key
3)Update flutterstripe pacakge
4)provide valid currency code to create stripe account country
ex :- stripe account create india to inr etc..
5)Right Way to implemet
- Main.dart to main method run app to implemet
ex :--
Stripe.publishableKey = "your publishable key ";
- create controller / method
code:-
Map<String, dynamic>? paymentIntentData;
Future<void> makePayment({amount}) async {
try {
paymentIntentData =
await createPaymentIntent(amount: amount, currency: 'INR');
if (paymentIntentData != null) {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// applePay: true,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'INR'),
merchantDisplayName: "PGA",
customerId: paymentIntentData!['customer'],
paymentIntentClientSecret: paymentIntentData!['client_secret'],
customerEphemeralKeySecret: paymentIntentData!['ephemeralkey'],
));
}
displayPaymentSheet();
} catch (err) {
logger.e(err);
}
}
void displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet();
Get.snackbar("PaymentInfo", "Payment Successfully");
} on Exception catch (e) {
if (e is StripeException) {
logger.e(e, "Error From Stripe");
} else {
logger.e(e, "Unforeseen error");
}
} catch (e) {
logger.e("exeption === $e");
}
}
var id = "";
createPaymentIntent({amount, currency}) async {
try {
Map<String, dynamic> body = {
'amount': calculateAmount(amount: amount),
'currency': currency,
'payment_method_types[]': 'card'
};
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
headers: {
'Authorization':
'Bearer YourSecretKey',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body,
);
if (response.statusCode == 200) {
var decode = jsonDecode(response.body);
logger.e(decode);
id = decode['id'];
return decode;
}
} catch (e) {
logger.e(e, "error charging user");
}
}
calculateAmount({amount}) {
logger.e(amount.round());
final a = (int.parse(amount.toString())) * 100;
logger.e(a.toString());
update();
return a.toString();
}
6) How to Access Stripe payment :-
ex :- any button click
ontap : (){
makePayment(
amount: "200")
}

error : display a red line under this statement _userFromFirebaseUser(userCredential.user);

hi every one I'm trying making my app with flutter . it is contains a sign up page so I write the code and I'm retrieving an information from the firebase after I upload it .
the below code is the sign up code
UserModel? _userFromFirebaseUser(User userCredential) {
return userCredential != null
? UserModel(
id: userCredential.uid,
bannerImageUrl: '',
name: '',
email: '',
profileImageUrl: '')
: null;
}
Stream<UserModel?> get userCredential {
return auth
.authStateChanges()
.map((userCredential) => _userFromFirebaseUser(userCredential!));
}
Future SignUp(email, password) async {
var formdata = formstate.currentState;
if (formdata!.validate()) {
print("valid");
formdata.save();
try {
UserCredential userCredential =
(await auth.createUserWithEmailAndPassword(
email: myemail!, password: mypassword!));
FirebaseFirestore.instance
.collection('Users')
.doc(userCredential.user!.uid)
.set({'name': email, 'email': email});
_userFromFirebaseUser(userCredential.user);
return userCredential;
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
Navigator.of(context).pop();
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
Navigator.of(context).pop();
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
} else {}
}
and the red line appears on this line _userFromFirebaseUser(userCredential.user); as it is appears in the picture . please help me
userCredential.user is User? not User
change the method parameter
UserModel? _userFromFirebaseUser(User? userCredential) {
return ....
}