Sign in with Facebook Flutter, how can I change my code? - facebook

How can I change my code below so I can login with Facebook? The second method is just normal login, but I want apply the same app login logic to the Facebook login.
// facebook login
bool isLoggedIn = false;
void onLoginStatusChanged(bool isLoggedIn) {
setState(() {
this.isLoggedIn = isLoggedIn;
});
}
void initiateFacebookLogin() async {
var facebookLogin = FacebookLogin();
var facebookLoginResult = await facebookLogin.logIn(['email']);
switch (facebookLoginResult.status) {
case FacebookLoginStatus.error:
print("Error");
onLoginStatusChanged(false);
break;
case FacebookLoginStatus.cancelledByUser:
print("CancelledByUser");
onLoginStatusChanged(false);
break;
case FacebookLoginStatus.loggedIn:
print("LoggedIn");
onLoginStatusChanged(true);
break;
}
}
// application login
void login() async {
if (loginFormKey.currentState.validate()) {
loginFormKey.currentState.save();
repository.login(user).then((value) {
//print(value.apiToken);
if (value != null && value.apiToken != null) {
scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(S.current.welcome + value.name),
));
Navigator.of(scaffoldKey.currentContext)
.pushReplacementNamed('/Pages', arguments: 2);
} else {
scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(S.current.wrong_email_or_password),
));
}
});
}
}

Related

Appodeal Consent Manager won't show

Future<void> checkConsent() async {
ConsentManager.requestConsentInfoUpdate(Constants.kAppodealKey);
ConsentManager.setConsentInfoUpdateListener(
(onConsentInfoUpdated, consent) {
print('PRINT: onConsentInfoUpdated $consent');
}, (onFailedToUpdateConsentInfo, error) {
print('PRINT: onFailedToUpdateConsentInfo $error');
});
var consentStatus = await ConsentManager.getConsentStatus();
print('PRINT: consentStatus $consentStatus');
if (consentStatus.toString() == 'Status.UNKNOWN') {
var shouldShow = await ConsentManager.shouldShowConsentDialog();
print('PRINT: shouldShow $shouldShow');
if (shouldShow.toString() == 'ShouldShow.TRUE') {
ConsentManager.loadConsentForm();
var isLoaded = await ConsentManager.consentFormIsLoaded();
print('PRINT: isLoaded $isLoaded');
if (isLoaded == true) {
ConsentManager.showAsDialogConsentForm();
ConsentManager.showAsActivityConsentForm();
ConsentManager.setConsentFormListener((onConsentFormLoaded) {
print('PRINT: onConsentFormLoaded');
}, (onConsentFormError, error) {
print('PRINT: onConsentFormError $error');
}, (onConsentFormOpened) {
print('PRINT: onConsentFormOpened');
}, (onConsentFormClosed, consent) {
print('PRINT: onConsentFormClosed $consent');
});
}
}
}
}
Constants.kAppodealKey is what I got in the Application key from here: https://app.appodeal.com/apps
But this is what I got:
I/flutter ( 9497): PRINT: consentStatus Status.UNKNOWN
I/flutter ( 9497): PRINT: shouldShow ShouldShow.UNKNOWN
In the documentation ShouldShow.UKNOWN means this: https://wiki.appodeal.com/en/android/get-started/data-protection/gdpr-and-ccpa
UNKNOWN The value is undefined(the requestConsentInfoUpdate method was not called).
But I have called it on the first line of my method. May I know why it is having a problem?
Important update 2022 07 18
less than 10 days after I posted this answer, a new Flutter Appodeal plugin (3.0.0) was made available which is claimed to make the handling of consent much easier.
Old answer
I was able to reproduce your issue with your code, my verified app key and those prints on the first attempt after app installation:
I/flutter (21755): PRINT: consentStatus Status.UNKNOWN
I/flutter (21755): PRINT: shouldShow ShouldShow.UNKNOWN
I/flutter (21755): PRINT: onConsentInfoUpdated {"createdAt":1655890242,"zone":"NONE","acceptedVendors":[],"iab":{"IABConsent_SubjectToGDPR":"0"},"updatedAt":1655890242,"status":"UNKNOWN"}
The main problem here is that you cannot rely on the end of the execution of a method call to consider its work completed. Even with await.
You have to either rely on retry and wait loops which I don't recommend as it can be intensive and it can fail easily.
Or you can rely on the listeners.
What I did, is a mix of both because listeners are not always available.
I would love to get some feedback on this proposal as I am not certain I interpreted correctly the AppoDeal documentation.
I call AdManager.init(); once the app is loaded. This may also work if called earlier.
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:stack_appodeal_flutter/stack_appodeal_flutter.dart';
import 'dart:io' show Platform;
class AdManager {
static var consent = false;
static Status consentStatus = Status.UNKNOWN;
static int requestConsentInfoUpdateRetries = 20;
static int requestLoadConsentFormRetries = 20;
static int adType = Appodeal.INTERSTITIAL;
static String get appKey =>
Platform.isAndroid ?
"your android app key"
:
"your ios app key"
;
//app ids found here: https://app.appodeal.com/apps
static initializeAfterConsent() {
Appodeal.initialize(
appKey,
[
adType,
],
boolConsent: consent,
).whenComplete(() {
Appodeal.isLoaded(adType).then((bool isLoaded) {
if (!isLoaded) {
Appodeal.cache(adType).whenComplete(() {
debugPrint("Note: appodeal ad has been loaded");
});
}
else {
debugPrint("Note: appodeal ad was loaded");
}
});
});
}
static init(bool testing) async {
try {
await handleATT();
await Appodeal.setTesting(true);
await Appodeal.setLogLevel(Appodeal.LogLevelVerbose);
await Appodeal.disableNetwork("admob");
await Appodeal.setAutoCache(adType, true);
await Appodeal.setAutoCache(Appodeal.REWARDED_VIDEO, false);
await Appodeal.setAutoCache(Appodeal.BANNER, false);
await Appodeal.setAutoCache(Appodeal.MREC, false);
await Appodeal.setChildDirectedTreatment(false);
await Appodeal.setUseSafeArea(true);
await Appodeal.muteVideosIfCallsMuted(true);
await doTheConsentStuff();
}
catch (e, st) {
debugPrint("Error initializing ads: ${e.toString()} ${st.toString()}");
}
}
static Future<String> showInterstitialAd(
{Function doWhenComplete, int retries = 10}) async {
try {
Map<String, Function> callsForAd = {
"not initialized": () async {
return await Appodeal.isInitialized(adType);
},
"not loaded": () async {
return await Appodeal.isLoaded(adType);
},
"cannot show": () async {
return await Appodeal.canShow(adType);
},
"not shown": () async {
return await Appodeal.show(adType);
},
};
for (int i = 0; i < callsForAd.length; i++) {
if (!await callsForAd.values.toList()[i]()) {
String res = callsForAd.keys.toList()[i];
switch (res) {
case "not initialized":
await initializeAfterConsent();
break;
case "not loaded":
await Appodeal.cache(adType);
break;
case "cannot show":
case "not shown":
if (retries > 0) {
await Future.delayed(Duration(milliseconds: 100));
}
break;
default:
return (res);
break;
}
if (retries > 0) {
debugPrint(
"Warning from ads: " + res + "; with retries: $retries");
return (await showInterstitialAd(
doWhenComplete: doWhenComplete, retries: retries - 1));
}
return (res);
}
else {
if (doWhenComplete != null) {
doWhenComplete();
}
}
}
return (null);
}
catch (e, st) {
return ("${e.toString()} ${st.toString()}");
}
}
static retryMaybeConsentInfoUpdate() {
if (requestConsentInfoUpdateRetries > 0) {
Future.delayed(Duration(milliseconds: 2000)).whenComplete(() {
requestConsentInfoUpdateRetries--;
ConsentManager.requestConsentInfoUpdate(appKey);
});
}
else {
debugPrint(
"Error: exhausted all retries on retryMaybeConsentInfoUpdate, aborting consent handling");
initializeAfterConsent();
}
}
static retryMaybeLoadConsentForm() {
if (requestLoadConsentFormRetries > 0) {
Future.delayed(Duration(milliseconds: 2000)).whenComplete(() {
requestLoadConsentFormRetries--;
ConsentManager.loadConsentForm();
});
}
else {
debugPrint(
"Error: exhausted all retries on requestLoadConsentFormRetries, aborting consent handling");
initializeAfterConsent();
}
}
static doTheConsentStuff() async {
try {
ConsentManager.setConsentInfoUpdateListener(
(onConsentInfoUpdated, consent) {
debugPrint(
"Note: Appodeal consent onConsentInfoUpdated: $onConsentInfoUpdated : $consent");
if (onConsentInfoUpdated == "onConsentInfoUpdated") {
try {
Map<String, dynamic> result = jsonDecode(consent);
switch (result["status"]) {
case "UNKNOWN":
debugPrint("Note: got a consent info status of unknown");
updateConsentStatus().whenComplete(() {
getShouldShow().then((shouldShow) {
switch (shouldShow) {
case ShouldShow.TRUE:
ConsentManager.setConsentFormListener(
(onConsentFormLoaded) {
debugPrint(
"Note: consent form loaded: $onConsentFormLoaded");
if (Platform.isIOS) {
ConsentManager.showAsActivityConsentForm();
}
else {
ConsentManager.showAsDialogConsentForm();
}
},
(onConsentFormError, error) {
debugPrint(
"Error: consent form error: $onConsentFormError: $error");
if (error == "Nothing to load") {
updateConsentStatus().whenComplete(() {
initializeAfterConsent();
});
}
else {
retryMaybeLoadConsentForm();
}
},
(onConsentFormOpened) {
debugPrint(
"Note: consent form opened: $onConsentFormOpened");
},
(onConsentFormClosed, consent) {
debugPrint(
"Note: consent form closed: $onConsentFormClosed: $consent");
updateConsentStatus().whenComplete(() {
initializeAfterConsent();
});
}
);
ConsentManager.loadConsentForm();
break;
case ShouldShow.FALSE:
debugPrint("Note: no need to show consent form");
updateConsentStatus().whenComplete(() {
initializeAfterConsent();
});
break;
case ShouldShow.UNKNOWN:
retryMaybeConsentInfoUpdate();
break;
default:
debugPrint(
"Error: undefined consent shouldShow value, aborting consent handling");
initializeAfterConsent();
break;
}
});
});
break;
case "PARTLY_PERSONALIZED":
debugPrint(
"Note: got a consent info status of PARTLY_PERSONALIZED");
updateConsentStatus().whenComplete(() {
initializeAfterConsent();
});
break;
case "PERSONALIZED":
debugPrint(
"Note: got a consent info status of PERSONALIZED");
updateConsentStatus().whenComplete(() {
initializeAfterConsent();
});
break;
case "NON_PERSONALIZED":
debugPrint(
"Note: got a consent info status of NON_PERSONALIZED");
updateConsentStatus().whenComplete(() {
initializeAfterConsent();
});
break;
default:
debugPrint("Error: got an unknown consent info status");
retryMaybeConsentInfoUpdate();
break;
}
}
catch (e, st) {
debugPrint("Error reading onConsentInfoUpdated data");
retryMaybeConsentInfoUpdate();
}
}
},
(onFailedToUpdateConsentInfo, error) {
debugPrint(
"Note: Appodeal consent onFailedToUpdateConsentInfo: $onFailedToUpdateConsentInfo : $error with $requestConsentInfoUpdateRetries retries");
retryMaybeConsentInfoUpdate();
});
await ConsentManager.requestConsentInfoUpdate(appKey);
}
catch (e, st) {
debugPrint("Error: consent form general error: ${e.toString()} ${st
.toString()}");
}
}
static Future<void> updateConsentStatus() async {
consentStatus = await ConsentManager.getConsentStatus();
switch (consentStatus) {
case Status.UNKNOWN:
debugPrint("Warning: consent status is unknown");
consent = false;
break;
case Status.NON_PERSONALIZED:
case Status.PARTLY_PERSONALIZED:
consent = false;
break;
case Status.PERSONALIZED:
debugPrint("Note: consent status is known");
consent = true;
break;
default:
consent = false;
debugPrint("Warning: undefined consent status");
break;
}
}
static Future<ShouldShow> getShouldShow([int retries = 20]) async {
var shouldShow = await ConsentManager.shouldShowConsentDialog();
if (shouldShow == ShouldShow.UNKNOWN) {
if (retries > 0) {
await Future.delayed(Duration(milliseconds: 500));
return (getShouldShow(retries - 1));
}
}
return (shouldShow);
}
static Future<void> handleATT({int retries = 20}) async {
if (Platform.isIOS) {
Permission appTrackingTransparencyPermission = Permission
.appTrackingTransparency;
PermissionStatus aTTPermissionStatus = await appTrackingTransparencyPermission
.status;
if (aTTPermissionStatus == null ||
aTTPermissionStatus == PermissionStatus.denied) {
debugPrint("ATT is null or denied, requesting with retries: $retries");
aTTPermissionStatus = await appTrackingTransparencyPermission.request();
if (aTTPermissionStatus == null ||
aTTPermissionStatus == PermissionStatus.denied) {
if (retries > 0) {
await Future.delayed(Duration(milliseconds: 500));
await handleATT(retries: retries - 1);
}
else {
debugPrint(
"Warning: ATT permission request retries exhausted, aborting");
}
}
return;
}
debugPrint(
"ATT is either granted, permanently denied, limited or restricted, thus, not requesting");
}
}
}
With this code, I get this edited consent form:
Then, the following is shown when I request to display an ad:
So, to me, apart from the deprecation warnings, everything seems to work fine.
Edit 2022 06 23:
Running on iOS, I realized that the shouldShow answer is enough to know whether to show the consent form or not. Thus, the consent form is only displayed when my VPN is set to Europe or California.
Also for iOS, I added ATT handling.
I have made some other general improvements.
I do not work for Appodeal and I am not a legal expert. I just provide this code based on my personal understanding which may not lead to the right way to handle those ads and consent questions.

MIgrating to bloc >= 7.2.0 with multiple enevts and shared preferences

I am working on a login page that was created with the pre >=7.2.0 bloc version and I am having issues migrating this AuthBloc because it has multiple events and shared preferences within.
class AuthBloc extends Bloc<AuthEvent, AuthStates> {
AuthBloc() : super(Initialization());
Stream<AuthStates> mapEventToState(AuthEvent event) async* {
yield WaitingAuth();
switch (event.runtimeType) {
case InitEvent:
SharedPreferences prefs = await SharedPreferences.getInstance();
bool login = prefs.getBool('login');
if (login == null || !login) {
prefs.clear();
yield Initialization();
break;
} else {
String token = prefs.getString('token');
String tokenJWT = prefs.getString('tokenJWT');
if (token == null ||
tokenJWT == null ||
token.isEmpty ||
tokenJWT.isEmpty) {
yield Initialization();
} else {
setToken(token);
setJWTToken(tokenJWT);
final response = await Api.getAccount();
if (response is Account) {
final sensorResponse = await Api.getDevices();
if (sensorResponse is List<Sensor>) {
yield SuccessAuth(account: response, sensors: sensorResponse);
} else {
yield SuccessAuth(account: response, sensors: []);
}
} else {
yield Initialization();
}
}
}break;
default:
SentryCapture.error(
loggerName: 'AuthBloc',
environment: 'switch',
message: 'unhandled event($event)');
}
}
}
How do I go about it?
With flutter bloc >= 7.2.0 you have to use the new on< Event> API and replace your yield with emit. Here is a small example.
MyBloc() : super (MyInitialState()) {
on<MyEvent1>((event, emit) => emit(MyState1()));
on<MyEvent2>((event, emit) => emit(MyState2()));
}
For your case do the following.
AuthBloc() : super(Initialization()) {
on<AuthEvent>((event, emit) {
emit(WaitingAuth());
// Your logic
}
}

Flutter Facebook login responds with Http status error [500]

I have added Facebook login to my flutter project and its logging in successfully but the problem is, The user is not able to enter the home screen of the application and stays back on the login screen. It is responding as Http status error [500].
Below is the code for Facebook login/authentication:
void doFacebookSignIn() async{
print("FaceBook Clicked");
try {
final result =
await FacebookAuth.i.login(permissions: ['email']);
if (result.status == LoginStatus.success) {
final userData = await FacebookAuth.i.getUserData();
print(userData);
hitFacebookApi(result.accessToken.token);
await FacebookAuth.i.logOut();
if (result.status == LoginStatus.cancelled) {
ToastUtils.showCustomToast(context, "cancelled", Colors.white , MyColors.primaryColor);
}
if (result.status == LoginStatus.failed) {
ToastUtils.showCustomToast(context, result.message, Colors.white , MyColors.primaryColor);
}
}
} catch (error) {
print(error);
}
}
Code for entering from Login to Home screen:
void hitFacebookApi(String token) {
CommonApis().logInWithFB(
{"token": "$token"}, CommonUtils.getLanguage(context) == "english")
.then((value) async{
if (value is Map) {
String fullToken = "Bearer ${value['token']}";
ApiUtils.headerWithToken.update("Authorization",(value)=> fullToken);
await userData.save(fullToken, "client");
await userService.getProfile();
Navigator.pushAndRemoveUntil(context,PageTransition(type: PageTransitionType.fade, child: ClientMain()), (Route<dynamic> route) => false);
} else {
ToastUtils.showCustomToast(
context, value, Colors.white, MyColors.primaryColor);
print("the cause "+value);
}
});
}
Code for API method:
Future<dynamic> logInWithFB(dynamic data ,bool isEnglish) async{
try{
final response= await Dio().post("${ApiUtils.BaseApiUrl}/auth/social/facebook",data: data,options: Options(headers: ApiUtils.headerForRegister ));
if(response.statusCode==200){
return {
"token" : response.data['token']
};
}
else{
return isEnglish?response.data['error']['en']:response.data['error']['ar'];
}
}on DioError catch(e) {
if(e.response !=null) {
return e.message;
}
}
}

Login is successful even if it is invalid user

I simply want to accept username and password while login and check in the database if user is valid or not but the problem is for any username and password it shows "login successful". Whatever values I give it shows login successful but it should show "user doesnt exist." Please help me.
db_service.dart
Future<RegisterUser> getLogin(String user, String password) async {
await DB.init();
var res = await DB.rawQuery("userDetails WHERE emailId = '$user' and password = '$password'");
if (res.length > 0) {
return RegisterUser.fromMap(res.first);
}
return null;
}
UserLogin.dart (Code for the login button)
bool validateAndSave() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
void _submit(){
final form = _formKey.currentState;
var res;
if (validateAndSave()) {
setState(() {
res=dbService.getLogin(_email, _password).then((value) {
if(res!=0){
FormHelper.showMessage(
context,
"Login",
"Login Successfull",
"Ok",
() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => People_List(),
),
);
},
);}
else {
FormHelper.showMessage(
context,
"Login",
"Login not Successfull",
"Ok", () {}
);
}
});
});
}
}
It seems you are using the Future function in the wrong way.
res= await dbService.getLogin(_email, _password);
if(res != 0){
} else {
}
Or
dbService.getLogin(_email, _password).then((value) {
if(value != 0){
}else {
}
}, onError(e){});

How to put an if statement in another one in flutter?

I am trying to put an if statement inside another like this :
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then((res) {
if (res != null) {
if (userType.text == 'Student') {
Navigator.pushReplacementNamed(context, '/StudentsPage');
} else if (userType.text == 'Teacher') {
Navigator.pushReplacementNamed(context, '/TeacherPage');
} else if (userType.text == 'Admin') {
Navigator.pushReplacementNamed(context, '/AdminPage');
}
} else {
LoginScreen();
}
});
}
But It gives me this error that there is a text that was called on null, so if anyone has an idea.
I'm using FireBase database.. and I am retrieving the data using this:
void getUserData() async {
try {
firestoreInstance .collection('Users') .document(usernameController.text) .get() .then((value) {
setState(() {
email = (value.data)['email'];
password = (value.data)['password'];
gender = (value.data)['gender'];
username = (value.data)['username'];
userType = (value.data)['userType'];
}); });
print('$userType');
}
catch (e) {
print(e.toString);
} }
The issue is that userType is a String object and therefore has no text getter method. Remove the .text and it seems that your code would work fine.
if (res != null) {
if (userType == 'Student') {
Navigator.pushReplacementNamed(context, '/StudentsPage');
} else if (userType == 'Teacher') {
Navigator.pushReplacementNamed(context, '/TeacherPage');
} else if (userType == 'Admin') {
Navigator.pushReplacementNamed(context, '/AdminPage');
}
}