standard_checkout_plugin 1.0.1
standard_checkout_plugin: ^1.0.1 copied to clipboard
Flutter plugin for integrating standard checkout payment gateway in Android, iOS, and Web applications.
example/lib/main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:checkout_plugin/checkout_plugin.dart';
import 'package:checkout_plugin/model/pay_request.dart';
import 'package:checkout_plugin/model/pay_result.dart';
import 'package:http/http.dart' as http;
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Checkout Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const CheckoutActivity(),
);
}
}
class CheckoutActivity extends StatefulWidget {
const CheckoutActivity({super.key});
@override
State<CheckoutActivity> createState() => _CheckoutActivityState();
}
class _CheckoutActivityState extends State<CheckoutActivity> {
final TextEditingController _descriptionController = TextEditingController();
final TextEditingController _amountController = TextEditingController();
final _formKey = GlobalKey<FormState>();
late PayRequest _payRequest;
bool _isProcessing = false;
String _ipAddress = 'Fetching IP...';
@override
void initState() {
super.initState();
_initializePayRequest();
_getRealIPAddress();
}
void _initializePayRequest() {
_payRequest = PayRequest(
memberId: '14691',
toType: 'TWPayz',
memberKey: 'KsidL3VNx4rNaxPG9eYBNXNVmxlbZXvn',
amount: '',
currency: 'GBP',
merchantTransactionId: '',
hostUrl: 'https://sandbox.twpayz.com/transaction/Checkout',
// hostUrl: 'https://www.google.com'
);
_payRequest.orderDescription = 'Testing Transaction';
_payRequest.country = 'IN';
_payRequest.city = 'Mumbai';
_payRequest.state = 'MH';
_payRequest.postCode = '400064';
_payRequest.street = 'Malad';
_payRequest.telnocc = '91';
_payRequest.phone = '8668459089';
_payRequest.email = 'riya.patel@gmail.com';
_payRequest.paymentBrand = ''; // Added - matches Android
_payRequest.paymentMode = ''; // Added - matches Android
_payRequest.terminalId = ''; // Added - matches Android
_payRequest.ipAddress = '';
_payRequest.device = 'flutter';
}
// Method to get IP address
static Future<String?> getIPForTransaction() async {
try {
final response = await http.get(Uri.parse('https://api.ipify.org?format=json'));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final ip = data['ip'] as String?;
return ip;
}
return null;
} catch (e) {
debugPrint('Failed to get IP: $e');
return null;
}
}
// Method to fetch and set IP in the UI
Future<void> _getRealIPAddress() async {
final ip = await getIPForTransaction();
if (mounted) {
setState(() {
_ipAddress = ip ?? 'Not available';
_payRequest.ipAddress = ip ?? '';
});
}
}
void _startPayment() async {
// Check if IP is empty FIRST - before anything else
if (_payRequest.ipAddress == null || _payRequest.ipAddress!.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('❌ IP Address is empty. Please check your internet connection.'),
backgroundColor: Colors.red,
duration: Duration(seconds: 3),
),
);
return;
}
// Then validate the form
if (_formKey.currentState!.validate()) {
setState(() => _isProcessing = true);
_payRequest.merchantTransactionId = _descriptionController.text;
_payRequest.amount = double.parse(_amountController.text).toStringAsFixed(2);
try {
await FlutterPaymentCheckout.initPayment(
context: context,
payRequest: _payRequest,
onSuccess: (PayResult result) {
if (mounted) {
setState(() => _isProcessing = false);
// ✅ Just reset the form and navigate if needed
_resetForm();
}
},
onFailure: (PayResult result) {
if (mounted) {
setState(() => _isProcessing = false);
// ✅ Just reset the form
_resetForm();
}
},
);
} catch (e) {
if (mounted) {
setState(() => _isProcessing = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: ${e.toString()}'))
);
}
}
}
}
// ✅ Add this helper method to reset form
void _resetForm() {
_descriptionController.clear();
_amountController.clear();
_formKey.currentState?.reset();
// Optionally show a brief success/failure message
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Payment completed. Check the result in the dialog.'),
duration: Duration(seconds: 2),
),
);
}
String? _validateDescription(String? value) {
if (value == null || value.isEmpty) return 'Order description is required';
if (value.length < 3) return 'Description must be at least 3 characters';
return null;
}
String? _validateAmount(String? value) {
if (value == null || value.isEmpty) return 'Amount is required';
final amount = double.tryParse(value);
if (amount == null || amount <= 0) return 'Please enter a valid amount';
if (amount > 999999.99) return 'Amount is too high';
return null;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Checkout Demo'),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(
labelText: 'Order Description',
hintText: 'Enter order description',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.description),
),
validator: _validateDescription,
),
const SizedBox(height: 16),
TextFormField(
controller: _amountController,
decoration: const InputDecoration(
labelText: 'Amount',
hintText: 'Enter amount',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.currency_pound),
suffixText: 'GBP',
),
keyboardType: const TextInputType.numberWithOptions(decimal: true),
validator: _validateAmount,
),
const SizedBox(height: 24),
Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Payment Details:', style: TextStyle(fontWeight: FontWeight.bold)),
const Divider(),
_buildInfoRow('Member ID:', _payRequest.memberId ?? ''),
_buildInfoRow('Currency:', _payRequest.currency ?? ''),
_buildInfoRow('IP Address:', _ipAddress),
],
),
),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: _isProcessing ? null : _startPayment,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: _isProcessing
? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Text('Pay Now', style: TextStyle(fontSize: 18)),
),
],
),
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
SizedBox(width: 100, child: Text(label)),
Expanded(child: Text(value)),
],
),
);
}
@override
void dispose() {
_descriptionController.dispose();
_amountController.dispose();
super.dispose();
}
}