Flutter
Flutter is a UI Framework developed and supported by Google to create user interface (UI) applications for multiple platforms with a single code base. Currently, Flutter supports the development of applications on multiple platforms such as IOS, Android, Web, MacOS, Windows and Linux.
Flutter uses the Dart programming language to write. Dart is an Open Source language developed by Google, Dart is a programming language designed and optimized for UI creation and many of its strengths are used in Flutter. For example: Null Safety, helps to find and fix bugs more easily. This capability allows developers to reduce time and focus the rest of their time on the most important parts of their application development.
Connect to Payment Support Using Flutter
You can use Flutter to connect to Lailao Payment Support. First of all, we need to create a Flutter project. This project will create an e-Commerce system, especially the product details page that will display images, details, prices, categories, etc. There is also a provision to send an order to create a QR Payment at a commercial bank and can use the commercial banking app (BCEL One) to scan for payment. After that, the system will receive a callback from the bank detailing the payment and we will display a message confirming the payment. All Source Code is available at this link Github (opens in a new tab)
If you want to read more details about Lailao Payment Support, you can see here Introduction
Start Flutter Project
Create a Flutter App to create an environment to learn how to use Lailao Payment Support with Flutter. More details on creating a Flutter project can be found at Flutter User Guide (opens in a new tab) and is the best way to start creating a new single-page application in Flutter.
flutter create lailaopayment_app
cd lailaopayment_app
flutter run
Line 1 This command will create a Flutter project named lailaopayment_app
Line 2 is moved to the lailaopayment_app folder
Line 3 commands to run the Debug system first
Next we will install Libray which will be used to create App more easily.
flutter pub add http
flutter pub add socket_io_client
flutter pub add url_launcher
flutter pub add company_info
The command above is to add various libraries to the project, each of which has the following meaning:
Library | Details |
---|---|
http | http is our flutter link to the server to send requests to the server and receive response data back to the frontend and an important part of communicating with RESTful APIs. |
socket_io_client | socket.io is used for connecting to WebSocket and Socket.IO server. It is a client used for creating real-time applications by which data can be sent between the client and the server without reloading the page or sending new requests. |
url_launcher | url_launcher is a library used in Flutter to open URLs from within our app with external apps |
company_info | company_info is a library that includes logos of apps or companies in Laos |
Next start to write the code by starting from:
main.dart
import 'package:carshop/screens/home_screen.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomeScreen(),
);
}
}
home_screen.dart
import 'package:carshop/screens/payment_screens.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
List product = [
{
"brand": "APPLE",
"name": "iPhone-15 pro max ",
"price": 100,
"image":
"https://www.pngmart.com/files/15/Apple-iPhone-12-Transparent-Images-PNG.png"
},
{
"brand": "APPLE",
"name": "iPhone-14 pro max",
"price": 200,
"image":
"https://www.pngmart.com/files/15/Apple-iPhone-12-Transparent-Images-PNG.png"
},
{
"brand": "APPLE",
"name": " iPhone-11 pro max ",
"price": 300,
"image":
"https://www.pngmart.com/files/15/Apple-iPhone-12-Transparent-Images-PNG.png"
},
{
"brand": "APPLE",
"name": "iPhone-13 pro max",
"price": 400,
"image":
"https://www.pngmart.com/files/15/Apple-iPhone-12-Transparent-Images-PNG.png"
},
{
"brand": "APPLE",
"name": "iPhone-12 pro max",
"price": 500,
"image":
"https://www.pngmart.com/files/15/Apple-iPhone-12-Transparent-Images-PNG.png"
},
{
"brand": "APPLE",
"name": "iPhone-12",
"price": 600,
"image":
"https://www.pngmart.com/files/15/Apple-iPhone-12-Transparent-Images-PNG.png"
}
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("ລາຍການລົດສີ້ນຄ້າ"),
),
body: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView.builder(
itemCount: product.length,
shrinkWrap: true,
itemBuilder: ((context, index) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => PaymentScreen(
dataProduct: product[index],
)),
),
);
},
child: Padding(
padding: const EdgeInsets.only(top: 7),
child: Container(
width: MediaQuery.of(context).size.width,
height: 70,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadiusDirectional.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.shade100,
spreadRadius: 0.1,
offset: const Offset(
0,
0.5,
),
),
]),
child: ListTile(
dense: true,
leading: Image(
image: NetworkImage("${product[index]['image']}"),
),
title: Row(
children: [
const Icon(Icons.smartphone),
const SizedBox(width: 10),
Text(product[index]['brand'] ?? ""),
],
),
subtitle: Row(
children: [
const Icon(Icons.vibration),
const SizedBox(width: 10),
Text(product[index]['name'] ?? ""),
],
),
trailing: Text("${product[index]['price']} KIP"),
)),
),
);
}),
),
),
);
}
}
payment_screens.dart
// ignore_for_file: must_be_immutable, prefer_typing_uninitialized_variables
import 'dart:convert';
import 'package:carshop/screens/payment_success.dart';
import 'package:company_info/company_info.dart';
import 'package:company_info/logo_enum.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:qr_flutter/qr_flutter.dart';
import 'package:socket_io_client/socket_io_client.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
class PaymentScreen extends StatefulWidget {
var dataProduct;
PaymentScreen({super.key, this.dataProduct});
@override
State<PaymentScreen> createState() => _PaymentScreenState();
}
class _PaymentScreenState extends State<PaymentScreen> {
IO.Socket? socket;
var qrIB;
static const String keyDev =
"\$2b\$10\$fwHDiyPBpPf9YLwcLWfNV.O6427H0C8zEzV0Opo6p.uqtwAUYX6GG";
// "\$2b\$10\$q8fTfBbezQ3t6Mq1fjcZ1u4oWcMprn0.ENGzZUTyOKhp75tfVGog2";
static const String urlSocket =
"https://payment-Support.lailaolab.com/?key=$keyDev";
static const String endPoint =
"https://payment-Support.lailaolab.com/v1/api/payment";
Future<void> generateIBQr() async {
var bodyData = {
"amount": widget.dataProduct['price'],
"description": "Take test from Lailaolab",
};
var response = await http.post(Uri.parse("$endPoint/generate-ib-qr"),
headers: <String, String>{
'Content-Type': 'application/json',
"secretKey": keyDev
},
body: jsonEncode(bodyData));
if (response.statusCode == 200) {
var responsePayment = jsonDecode(response.body);
setState(() {
qrIB = responsePayment['qrCode'];
});
}
}
Future<void> generateBcelQr() async {
var bodyData = {
"amount": widget.dataProduct['price'],
"description": "Take test from Lailaolab",
};
var response = await http.post(Uri.parse("$endPoint/generate-bcel-qr"),
headers: <String, String>{
'Content-Type': 'application/json',
"secretKey": keyDev
},
body: jsonEncode(bodyData));
print(response.body);
if (response.statusCode == 200) {
var responsePayment = jsonDecode(response.body);
await launchUrl(
Uri.parse(responsePayment['link']),
mode: LaunchMode.externalApplication,
);
}
}
Future<void> generateJDBQr() async {
var bodyData = {
"amount": widget.dataProduct['price'],
"description": "Take test from Lailaolab",
};
var response = await http.post(Uri.parse("$endPoint/generate-jdb-qr"),
headers: <String, String>{
'Content-Type': 'application/json',
"secretKey": keyDev
},
body: jsonEncode(bodyData));
if (response.statusCode == 200) {
var responsePayment = jsonDecode(response.body);
await launchUrl(
Uri.parse(responsePayment['appLink']),
mode: LaunchMode.externalApplication,
);
}
}
@override
void initState() {
super.initState();
_socketConnect();
}
_socketConnect() async {
socket =
IO.io(urlSocket, OptionBuilder().setTransports(['websocket']).build());
socket!.onConnect((_) {
print('connected');
});
socket!.on("join::$keyDev", (data) async {
print("===>>>${data}");
if (data != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => PaymentSuccess(
dataResponse: data,
)),
),
);
socket!.clearListeners();
}
});
}
@override
Widget build(BuildContext context) {
print(widget.dataProduct);
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("ເລືອກທະນາຄານ"),
),
body: SingleChildScrollView(
child: Column(
children: [
BankWidget(
company: const companyInfo(
logoType: LogoType.bcel,
showName: true,
width: 30,
height: 30,
nameStyle: TextStyle(color: Colors.white),
),
onTap: () => generateBcelQr(),
),
BankWidget(
company: const companyInfo(
logoType: LogoType.jdb,
showName: true,
width: 30,
height: 30,
nameStyle: TextStyle(color: Colors.white),
),
onTap: () => generateJDBQr(),
),
BankWidget(
company: const companyInfo(
logoType: LogoType.ib,
showName: true,
width: 30,
height: 30,
nameStyle: TextStyle(color: Colors.white),
),
onTap: () => generateIBQr(),
),
const SizedBox(height: 20),
qrIB != null
? QrImage(
data: '$qrIB',
version: QrVersions.auto,
size: 200.0,
)
: const SizedBox.shrink()
],
),
),
);
}
}
class BankWidget extends StatelessWidget {
Function() onTap;
Widget company;
BankWidget({Key? key, required this.onTap, required this.company})
: super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5),
child: Container(
width: double.infinity,
height: 60,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(color: Colors.grey, offset: Offset(0, 0.5))
],
color: Colors.blue,
borderRadius: BorderRadius.circular(40),
),
child: Center(
child: company,
),
),
),
);
}
}
payment_success.dart
// ignore_for_file: must_be_immutable, prefer_typing_uninitialized_variables
import 'package:flutter/material.dart';
class PaymentSuccess extends StatefulWidget {
var dataResponse;
PaymentSuccess({super.key, this.dataResponse});
@override
State<PaymentSuccess> createState() => _PaymentSuccessState();
}
class _PaymentSuccessState extends State<PaymentSuccess> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("ສຳເລັດ"),
),
body: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
height: 400,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.shade400,
offset: const Offset(0, 0.5),
)
]),
child: Column(
children: [
const SizedBox(height: 10),
const Image(
width: 120,
height: 120,
image: AssetImage("assets/images/success.png"),
),
const SizedBox(height: 20),
const Text(
"ຊຳລະເງີນສຳເລັດ",
style: TextStyle(color: Colors.black),
),
const SizedBox(height: 30),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
const Text("ຈຳນວນເງີນ"),
const Spacer(),
Text(
"${widget.dataResponse['amount'] ?? ""} KIP",
style: const TextStyle(fontSize: 10),
),
],
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
const Text("ຊື່"),
const Spacer(),
Text(
"${widget.dataResponse['name'] ?? ""}",
style: const TextStyle(fontSize: 10),
),
],
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
const Text("uuid:"),
const Spacer(),
Text(
"${widget.dataResponse['uuid'] ?? ""}",
style: const TextStyle(fontSize: 10),
),
],
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
const Text("ວິນທີ່"),
const Spacer(),
Text(
"${widget.dataResponse['txtime'] ?? ""}",
style: const TextStyle(fontSize: 10),
),
],
),
),
],
),
),
));
}
}