Hi guys,
how to convert this flutter version to B4x?
PayPal with Flutter
First, we will create a Transaction screen in which we will add our simple example UI and Navigation to pay the payment
Now we will create the services screen in which we will call the Paypal APIs, for now, will use this domain https://api.sandbox.paypal.com because we are testing If you want to make a real transaction then replace it with https://api.paypal.com.
Now it's time to make a payment screen in which we will send the order and payment detail to Paypal.
how to convert this flutter version to B4x?
PayPal with Flutter
First, we will create a Transaction screen in which we will add our simple example UI and Navigation to pay the payment
B4X:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:paypal/Payment.dart';
class Transaction extends StatefulWidget {
@override
_TransactionState createState() => _TransactionState();
}
class _TransactionState extends State<Transaction> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
backgroundColor: Colors.white,
key: _scaffoldKey,
appBar: new AppBar(
centerTitle: true,
backgroundColor: Colors.white,
title: Text(
'Paypal Payment',
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
body: Container(
width: MediaQuery.of(context).size.width,
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
children: [
Text(
"Items in your Cart",
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w600),
),
ListTile(
title: Text(
"Product: iPhone 7",
style: TextStyle(
fontSize: 14, fontWeight: FontWeight.w600),
),
subtitle: Text(
"Quantity: 1",
style: TextStyle(
fontSize: 14, fontWeight: FontWeight.w600),
),
trailing: Text(
"\$200",
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w600),
),
)
],
),
RaisedButton(
color: Colors.red,
onPressed: () {
// make PayPal payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => Payment(
onFinish: (number) async {
// payment done
final snackBar = SnackBar(
content: Text("Payment done Successfully"),
duration: Duration(seconds: 5),
action: SnackBarAction(
label: 'Close',
onPressed: () {
// Some code to undo the change.
},
),
);
_scaffoldKey.currentState
.showSnackBar(snackBar);
print('order id: ' + number);
print('ddasdas');
},
),
),
);
},
child: Text(
'Pay with Paypal',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
],
),
)),
));
}
}
Now we will create the services screen in which we will call the Paypal APIs, for now, will use this domain https://api.sandbox.paypal.com because we are testing If you want to make a real transaction then replace it with https://api.paypal.com.
B4X:
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert' as convert;
import 'package:http_auth/http_auth.dart';
class Services {
String domain = "https://api.sandbox.paypal.com"; // for sandbox mode
// String domain = "https://api.paypal.com"; // for production mode
// change clientId and secret with your own, provided by paypal
String clientId = 'AUedUnHVJFup2E2r-JEBQmUMqOv_isN6i1JRr5AumAAVHx53-AVKYtjMjxZ-pzKjoOE94LBQdc1i';
String secret = 'EFPD5SIVIui95gdZCWsPlxYZiX8XDtuYLEs4b5gjoLa3vGmSdC8qgrKP8aEpsadJ_YAuNPB7zZwD';
// for getting the access token from Paypal
Future<String> getAccessToken() async {
try {
var client = BasicAuthClient(clientId, secret);
var response = await client.post('$domain/v1/oauth2/token?grant_type=client_credentials');
if (response.statusCode == 200) {
final body = convert.jsonDecode(response.body);
return body["access_token"];
}
return null;
} catch (e) {
rethrow;
}
}
// for creating the payment request with Paypal
Future<Map<String, String>> createPaypalPayment(
transactions, accessToken) async {
try {
var response = await http.post("$domain/v1/payments/payment",
body: convert.jsonEncode(transactions),
headers: {
"content-type": "application/json",
'Authorization': 'Bearer ' + accessToken
});
final body = convert.jsonDecode(response.body);
if (response.statusCode == 201) {
if (body["links"] != null && body["links"].length > 0) {
List links = body["links"];
String executeUrl = "";
String approvalUrl = "";
final item = links.firstWhere((o) => o["rel"] == "approval_url",
orElse: () => null);
if (item != null) {
approvalUrl = item["href"];
}
final item1 = links.firstWhere((o) => o["rel"] == "execute",
orElse: () => null);
if (item1 != null) {
executeUrl = item1["href"];
}
return {"executeUrl": executeUrl, "approvalUrl": approvalUrl};
}
return null;
} else {
throw Exception(body["message"]);
}
} catch (e) {
rethrow;
}
}
// for executing the payment transaction
Future<String> executePayment(url, payerId, accessToken) async {
try {
var response = await http.post(url,
body: convert.jsonEncode({"payer_id": payerId}),
headers: {
"content-type": "application/json",
'Authorization': 'Bearer ' + accessToken
});
final body = convert.jsonDecode(response.body);
if (response.statusCode == 200) {
return body["id"];
}
return null;
} catch (e) {
rethrow;
}
}
}
Now it's time to make a payment screen in which we will send the order and payment detail to Paypal.
B4X:
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:paypal/Services.dart';
import 'package:webview_flutter/webview_flutter.dart';
class Payment extends StatefulWidget {
final Function onFinish;
Payment({this.onFinish});
@override
State<StatefulWidget> createState() {
return PaymentState();
}
}
class PaymentState extends State<Payment> {
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String checkoutUrl;
String executeUrl;
String accessToken;
Services services = Services();
// you can change default currency according to your need
Map<dynamic,dynamic> defaultCurrency = {"symbol": "USD ", "decimalDigits": 2, "symbolBeforeTheNumber": true, "currency": "USD"};
bool isEnableShipping = false;
bool isEnableAddress = false;
String returnURL = 'return.example.com';
String cancelURL= 'cancel.example.com';
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () async {
try {
accessToken = await services.getAccessToken();
final transactions = getOrderParams();
final res =
await services.createPaypalPayment(transactions, accessToken);
if (res != null) {
setState(() {
checkoutUrl = res["approvalUrl"];
executeUrl = res["executeUrl"];
});
}
} catch (e) {
print('exception: '+e.toString());
final snackBar = SnackBar(
content: Text(e.toString()),
duration: Duration(seconds: 10),
action: SnackBarAction(
label: 'Close',
onPressed: () {
// Some code to undo the change.
},
),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
}
});
}
// item name, price and quantity
String itemName = 'iPhone 7';
String itemPrice = '200';
int quantity = 1;
Map<String, dynamic> getOrderParams() {
List items = [
{
"name": itemName,
"quantity": quantity,
"price": itemPrice,
"currency": defaultCurrency["currency"]
}
];
// checkout invoice details
String totalAmount = '200';
String subTotalAmount = '200';
String shippingCost = '0';
int shippingDiscountCost = 0;
String userFirstName = 'Arsalan';
String userLastName = 'Umar';
String addressCity = 'Islamabad';
String addressStreet = "i-10";
String addressZipCode = '44000';
String addressCountry = 'Pakistan';
String addressState = 'Islamabad';
String addressPhoneNumber = '+923200811288';
Map<String, dynamic> temp = {
"intent": "sale",
"payer": {"payment_method": "paypal"},
"transactions": [
{
"amount": {
"total": totalAmount,
"currency": defaultCurrency["currency"],
"details": {
"subtotal": subTotalAmount,
"shipping": shippingCost,
"shipping_discount":
((-1.0) * shippingDiscountCost).toString()
}
},
"description": "The payment transaction description.",
"payment_options": {
"allowed_payment_method": "INSTANT_FUNDING_SOURCE"
},
"item_list": {
"items": items,
if (isEnableShipping &&
isEnableAddress)
"shipping_address": {
"recipient_name": userFirstName +
" " +
userLastName,
"line1": addressStreet,
"line2": "",
"city": addressCity,
"country_code": addressCountry,
"postal_code": addressZipCode,
"phone": addressPhoneNumber,
"state": addressState
},
}
}
],
"note_to_payer": "Contact us for any questions on your order.",
"redirect_urls": {
"return_url": returnURL,
"cancel_url": cancelURL
}
};
return temp;
}
@override
Widget build(BuildContext context) {
print(checkoutUrl);
if (checkoutUrl != null) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).backgroundColor,
leading: GestureDetector(
child: Icon(Icons.arrow_back_ios),
onTap: () => Navigator.pop(context),
),
),
body: WebView(
initialUrl: checkoutUrl,
javascriptMode: JavascriptMode.unrestricted,
navigationDelegate: (NavigationRequest request) {
if (request.url.contains(returnURL)) {
final uri = Uri.parse(request.url);
final payerID = uri.queryParameters['PayerID'];
if (payerID != null) {
services
.executePayment(executeUrl, payerID, accessToken)
.then((id) {
widget.onFinish(id);
Navigator.of(context).pop();
});
} else {
Navigator.of(context).pop();
}
Navigator.of(context).pop();
}
if (request.url.contains(cancelURL)) {
Navigator.of(context).pop();
}
return NavigationDecision.navigate;
},
),
);
} else {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.of(context).pop();
}),
backgroundColor: Colors.black12,
elevation: 0.0,
),
body: Center(child: Container(child: CircularProgressIndicator())),
);
}
}
}