How the future and exception handling work together in dart? - flutter

I have a problem with exception handling, I build the product manager app in which I use firebase rest API to post the data to the server, And use the exception if by chance any error occur then redirect to the home screen. But if any error occurs then it will only show the loading spinner so what is the problem here and Also tell that how the exception and future work here?
If there is a problem in url then it will show the alert dialog and show error message and after that it will show loading spinner but according to the code after catchError it will return future then it means next then block content should run but that doesn't work so what is the behavior behind this?
The function which has post method
Future<void> addProduct(Product product) {
const url =
'';
return http
.post(
Uri.parse(url),
body: json.encode(
{
'title': product.title,
'description': product.description,
'price': product.price,
'imageUrl': product.imageUrl,
'isFavorite': product.isFavorite,
},
),
)
.then(
(response) {
final id = json.decode(response.body)['name'];
final newProduct = Product(
id: id,
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl,
);
_items.add(newProduct);
notifyListeners();
},
).catchError(
(error) {
print(error.toString());
throw error;
},
);
}
Code which is used in fronted
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog(
context: context,
builder: (ctx) {
return AlertDialog(
title: const Text('An Error Occured!!'),
content: const Text('Something went wrong'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Okay'),
)
],
);
});
}).then((_) {
setState(() {
_isLoding = false;
});
Navigator.of(context).pop();
});
}
}

the issue you mentioned is that the loading spinner is not being shown after the alert dialog is displayed. This is because the then block after catchError is not being executed. This is because the error is being re-thrown in the catchError block and not being caught by the catchError block in the front-end code. To fix this, you need to catch the error in the catchError block in the front-end code, for example by adding a try-catch statement around the call to addProduct.

Related

How to make HTTP GET request in flutter/dart

I am trying to make this GET request in my app but I am not sure how to go about it as I'm fairly new to flutter/dart.
I have successfully made a POST request to log in and now I am trying to make this GET request to display the messages in this message board in my app. That can come later as I am trying to complete the GET request first.
Preferably the GET request should be in a method which I can use in a button; each will be in messageBoard_Page.dart
This is the request URL that I am trying to reach.
and this is the Request Header
for reference this is the response that I am getting from my Login POST method
{
"RESPONSE":{
"login_request_result":{
"user_must_change_password":"0"
},
"BASEL_RESPONSE":{
"UserDate":"0",
"UserTime":"0",
"UserName":"Administrator",
"module_config_1":"0",
"module_config_2":"0",
"ErrEntity":{
"MessageID":"0",
"last_req_id":"50029",
"table_id":"0",
"key_id_list":"536871",
"operation_id":"0"
},
"is_csv":"0",
"VersionName":"DYMA # 6.1.24.0, ORG # 2017.3.22.15.0.41, GRC # 2017.3.22.15.0.55, LDC # 2017.3.22.15.1.8, DYMA_XML # 2017.3.22.15.0.30, NAS # 2017.3.22.15.1.22 - Config: 0 - Node: OPRISK_DATACOLLECTOR",
"ExpiryDate":"31/01/2030",
"count_key":"0",
"id_Us":"1",
"is_popup":"0",
"tot_messages":"0",
"my_messages":"0",
"product":"0"
},
"RESPONSE_HEADER":{
"SessionID":"VtVQIdERO-206868772kpwAXF0001",
"NomeRichiesta":"LOGIN_REQUEST",
"ltimeStart":"22262791",
"ltimeStop":"22262813",
"ldate_null":"19900101",
"product":"1",
"server_name":"OPRISK_DATACOLLECTOR",
"cell_context_id":"537945",
"operation_key":"1000000",
"operation_sub_num":"-1"
}
}
}
and this is my Login POST Method in login_Page.dart
void sendLogin() async {
var map = <String, dynamic>{
"UserName": _usernameController.text,
"Password": _passwordController.text,
};
var res = await http.post(
Uri.parse("http://192.168.1.8:8080/HongLeong/LOGIN_REQUEST.do"),
body: map,
);
final data = jsonDecode(res.body);
final String userSessionID = (data as Map)['RESPONSE']['RESPONSE_HEADER']['SessionID'];
print(res.statusCode);
print(res.body);
await WriteCache.setString(key: "cache", value: userSessionID);
if ((data as Map)['RESPONSE']['login_request_result'] == null) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Center(child: Text('Invalid Username/Password')),
actions: <Widget>[
Center(
child: TextButton(
onPressed: () {
_usernameController.clear();
_passwordController.clear();
Navigator.of(ctx).pop();
},
child: const Text('Ok'),
),
),
],
),
);
} else {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const DashboardPage()));
}
}
please ignore the messiness as Im trying to achieve the GET method as of now.
Any help is appreciated. Thank You.
ps. if the images are too small, I am not sure how else to show the request URL and header, sorry.
To make a get request its very much similar to the post you created. Just remove the body and change the request type
var res = await http.get(
Uri.parse("The url for getting the respose through get method here")
);
Rest everything stays the same.

'PresentPaymentSheetParameters' is deprecated and shouldn't be used. Parameters are now inherited from initPaymentSheet

I am integrating Stripe Payment Gateway into my e-commerce application. I am new to stripe payment gateway, I am facing a depreciation error which is as
'parameters' is deprecated and shouldn't be used. Params are now inherited from initPaymentSheet so this 'parameters' can be removed.
The current stripe plugin I am using is flutter_stripe: ^3.3.0. Just want to know how to fix this depreciation issue. Attaching the error screenshot also
CODE IS AS :
displayPaymentSheet(OrderProvider orderProvider) async {
try {
await Stripe.instance
.presentPaymentSheet(
parameters: PresentPaymentSheetParameters(
clientSecret: paymentIntentData!['client_secret'],
confirmPayment: true,
))
.then((newValue) {
print('payment intent ${paymentIntentData!['id']}');
print('payment intent ${paymentIntentData!['client_secret']}');
print('payment intent ${paymentIntentData!['amount']}');
print('payment intent $paymentIntentData');
//orderPlaceApi(paymentIntentData!['id'].toString());
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: const Text("Paid successfully")));
orderProvider.success = true;
Navigator.pop(context);
setState(() {
paymentIntentData = null;
});
}).onError((error, stackTrace) {
print('Exception/DISPLAYPAYMENTSHEET==> $error $stackTrace');
});
} on StripeException catch (e) {
print('Exception/DISPLAYPAYMENTSHEET==> $e');
showDialog(
context: context,
builder: (_) => AlertDialog(
content: Text("Cancelled "),
));
} catch (e) {
print('$e');
}
}
Try using initPaymentSheet.
await Stripe.instance
.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: "",
),
)

Flutter web Stripe Error: WebUnsupportedError: initPaymentSheet is not supported for Web

I am trying to implement Stripe inside my application, but I do get this error.
The error I get is Error: WebUnsupportedError:
initPaymentSheet is not supported for Web i don't know how to make it work on the web.
WidgetsFlutterBinding.ensureInitialized();
Get.put(MenuController());
Get.put(NavigationController());
await initialization;
Stripe.publishableKey =
'pk_test_5555851KuZKPKYrgcm5L1......';
Stripe.merchantIdentifier = 'merchant.flutter.stripe.test';
Stripe.urlScheme = 'flutterstripe';
await Stripe.instance.applySettings();
runApp((MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ApplicationState(),
builder: (context, _) => MyApp(),
)
],
// child: MyApp(),
)));
}
Future<void> makePayment(String amount, String currency) async {
try {
paymentIntentData = await createPaymentIntent(amount, currency);
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData!['client_secret'],
applePay: true,
googlePay: true,
merchantCountryCode: 'US',
merchantDisplayName: 'KasaiMart'));
displayPaymentSheet();
} on StripeException catch (e) {
print('Exeption ${e.toString()}');
}
}
displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet();
paymentIntentData = null;
Get.defaultDialog(
title: 'Select project to contribute to',
middleText: 'Paid Sucessfully');
} catch (e) {
print('Exeption ${e.toString()}');
}
}
createPaymentIntent(String amount, String currency) async {
try {
Map<String, dynamic> body = {
'amount': calculateAmount(amount),
'currency': currency,
'payment_method_types[]': 'card'
};
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
body: body,
headers: {
'Authorization':
'pk_test_51K......',
'Content-Type': 'application/x-www-form-urlencoded'
});
return jsonDecode(response.body.toString());
} catch (e) {
print('Exeption ${e.toString()}');
}
}
I am struggling to display the initPaymentSheet?
In which method am I doing something wrong? is it possible to fix this issue or is it from package itself?
Stripe for Web is still highly experimental. From the README on Github: Notice right now it is highly experimental and only a subset of features is implemented.
You can also check in the stripe_web plugin repository that the initPaymentSheet is still not implemented. It throws a WebUnsupportedError right away. Also, check the other unsupported methods in the same place.
initPaymentSheet doesn't work on the web. Stripe's React Native SDK is exclusive to iOS/Android.
If you want to present something similar to the Payment Sheet via the web, you might consider using the Payment Element instead: https://stripe.com/docs/payments/payment-element

This expression has a type of 'void' so its value can't be used flutter dart

i hope this image help
as well this one
when i try to use provider to call async function from another file I get the error.
i dont know that it's a problem in the methode where i call it or in the file that i created the function. at the end i will say thank you because stack overflow says add more details.
the code from pictures
void _saveForm() async {
var isValid = _form.currentState?.validate() as bool;
if (!isValid) {
return;
}
_form.currentState?.save();
print(_editedProduct);
if (_editedProduct.id == '') {
print('done');
// ignore: await_only_futures
await Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct); // this is where i get the error.
} else {
Provider.of<Products>(context, listen: false)
.updateProduct(_editedProduct.id, _editedProduct);
}
Navigator.of(context).pop();
}
Future<void> addProduct(Product product) async {
var httpsUri = Uri(
scheme: 'scheme',
host: 'host',
path: 'path',
);
final uri = Uri.parse(
'host');
try {
var res = await http.post(uri,
body: json.encode({
'title': product.title,
'description': product.description,
'price': product.price,
'isFav': product.isFavorite,
'imageUrl': product.imageUrl
}));
final newProduct = Product(
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl,
id: DateTime.now().toString(),
);
_items.add(newProduct);
notifyListeners();
} catch (e) {
print(e);
}
// _items.insert(0, newProduct); // at the start of the list
}
Future<void> addProduct(Product product) async {...} means the function doesn't return anything but Provider needs a value so it throws an error.

Flutter Firebase Auth throws NoSuchMethodError: The getter 'data' was called on null

During the email app signup process using firebaseAuth.createUserWithEmailAndPassword, when I try to do an upload or save to prefs in the .then part it throws this error:
NoSuchMethodError: The getter 'data' was called on null.
So I can work around this by Navigating to a new screen and postponing processing of the user's TextFormField input till there, but it's messy and bugs me.
Doing anything big in the .then seems problematic but I don't really know what's causing the problem, or what in fact the best way is to solve this kind of issue for future clarity. Education appreciated!
void registerToFb() {
firebaseAuth
.createUserWithEmailAndPassword(
email: emailController.text, password: passwordController.text)
.then((result) async {
Person user = new Person();
user.email = emailController.text;
user.firstName = firstNameController.text;
user.surname = surnameController.text;
user.postcode = postcodeController.text;
user.password = passwordController.text;
user.city = cityController.text ?? "Edinburgh";
user.firebaseId = result.user.uid;
Map<String, dynamic> firebaseUpload = user.toMap();
print("Attempting to reduce upload");
firebaseUpload.removeWhere((key, value) => value == null);
user.country = "GB";
String path = "${user.country}/${user.city}/People";
print("Attempting record upload");
DocumentReference autoId =
await myFirestore.collection(path).add(firebaseUpload);
user.personId = autoId.id;
user.saveToPrefs(prefs);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => MyHomePage()));
}).catchError((err) {
print("Login thrown an error...\n${err.toString()}");
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Error 10"),
content: Text("${err.toString()}"),
actions: [
ElevatedButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
});
A suggestion from me is to completely remove the .then() callback, since you have it stated as async. A better approach would be to make the whole function async, so you can do all your async code directly inside that.
Make the function async
void registerToFb() async { ...
Change the .then() callback to a simple await and store the result in your result variable.
var result = await firebaseAuth.createUserWithEmailAndPassword(email: emailController.text, password: passwordController.text);
I would highly suggest surrounding this statement with a try/catch block, to avoid unhandled errors:
try {
var result = await firebaseAuth.createUserWithEmailAndPassword(
email: emailController.text,
password: passowrdController.text
);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('password too weak.');
} else if (e.code == 'email-already-in-use') {
print('email already exists');
}
} catch (e) {
print(e);
}
You might get this error because you marked the .then() call as async, since it then executes asynchronously and the data might not be "there" yet, but I am not sure about this one.