unified_payment 1.0.0+1 copy "unified_payment: ^1.0.0+1" to clipboard
unified_payment: ^1.0.0+1 copied to clipboard

A Flutter package that provides a unified API for multiple payment providers (Stripe, PayPal, RazorPay, Paystack, Flutterwave) using a WebView-first approach.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:unified_payment/unified_payment.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Unified Payment Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const PaymentDemoPage(),
    );
  }
}

class PaymentDemoPage extends StatefulWidget {
  const PaymentDemoPage({super.key});

  @override
  State<PaymentDemoPage> createState() => _PaymentDemoPageState();
}

class _PaymentDemoPageState extends State<PaymentDemoPage> {
  final PaymentService _paymentService = PaymentService();
  PaymentProvider _selectedProvider = PaymentProvider.stripe;
  PaymentEnvironment _selectedEnvironment = PaymentEnvironment.sandbox;
  String _backendUrl = 'https://your-backend.com';
  String _apiKey = 'your-api-key';

  final TextEditingController _amountController =
      TextEditingController(text: '10.00');
  final TextEditingController _currencyController =
      TextEditingController(text: 'USD');
  final TextEditingController _descriptionController =
      TextEditingController(text: 'Test Payment');
  final TextEditingController _orderIdController = TextEditingController(
      text: 'order_${DateTime.now().millisecondsSinceEpoch}');
  final TextEditingController _emailController =
      TextEditingController(text: 'test@example.com');
  final TextEditingController _nameController =
      TextEditingController(text: 'Test User');

  String _lastResult = 'No payment attempted yet';
  bool _isLoading = false;

  @override
  void dispose() {
    _amountController.dispose();
    _currencyController.dispose();
    _descriptionController.dispose();
    _orderIdController.dispose();
    _emailController.dispose();
    _nameController.dispose();
    super.dispose();
  }

  Future<void> _initializePaymentService() async {
    try {
      setState(() => _isLoading = true);

      final config = PaymentConfig(
        provider: _selectedProvider,
        apiKey: _apiKey,
        environment: _selectedEnvironment,
        backendUrl: _backendUrl,
      );

      await _paymentService.init(config);

      setState(() {
        _lastResult = 'Payment service initialized successfully';
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _lastResult = 'Failed to initialize: $e';
        _isLoading = false;
      });
    }
  }

  Future<void> _makePayment() async {
    if (!_paymentService.isInitialized) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
            content: Text('Please initialize payment service first')),
      );
      return;
    }

    try {
      setState(() => _isLoading = true);

      final request = PaymentRequest(
        amount: double.parse(_amountController.text),
        currency: _currencyController.text,
        description: _descriptionController.text,
        orderId: _orderIdController.text,
        customerEmail: _emailController.text,
        customerName: _nameController.text,
      );

      await _paymentService.pay(
        context: context,
        request: request,
        onSuccess: (PaymentResponse response) {
          setState(() {
            _lastResult = 'Payment Successful!\n'
                'Transaction ID: ${response.transactionId}\n'
                'Order ID: ${response.orderId}\n'
                'Message: ${response.message}';
            _isLoading = false;
          });
          _showPaymentDialog(
              'Payment Successful', response.message, Colors.green);
        },
        onFailure: (PaymentResponse response) {
          setState(() {
            _lastResult = 'Payment Failed!\n'
                'Status: ${response.status.name}\n'
                'Message: ${response.message}\n'
                'Error Code: ${response.errorCode ?? 'N/A'}';
            _isLoading = false;
          });
          _showPaymentDialog('Payment Failed', response.message, Colors.red);
        },
      );
    } catch (e) {
      setState(() {
        _lastResult = 'Error: $e';
        _isLoading = false;
      });
      _showPaymentDialog('Error', e.toString(), Colors.red);
    }
  }

  void _showPaymentDialog(String title, String message, Color color) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Row(
          children: [
            Icon(
              title.contains('Success') ? Icons.check_circle : Icons.error,
              color: color,
            ),
            const SizedBox(width: 8),
            Text(title),
          ],
        ),
        content: Text(message),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('OK'),
          ),
        ],
      ),
    );
  }

  Widget _buildProviderConfig() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Payment Provider Configuration',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 16),
            DropdownButtonFormField<PaymentProvider>(
              value: _selectedProvider,
              decoration: const InputDecoration(
                labelText: 'Payment Provider',
                border: OutlineInputBorder(),
              ),
              items: PaymentProvider.values.map((provider) {
                return DropdownMenuItem(
                  value: provider,
                  child: Text(provider.name.toUpperCase()),
                );
              }).toList(),
              onChanged: (value) {
                if (value != null) {
                  setState(() => _selectedProvider = value);
                  _updateApiKeyPlaceholder();
                }
              },
            ),
            const SizedBox(height: 12),
            DropdownButtonFormField<PaymentEnvironment>(
              value: _selectedEnvironment,
              decoration: const InputDecoration(
                labelText: 'Environment',
                border: OutlineInputBorder(),
              ),
              items: PaymentEnvironment.values.map((env) {
                return DropdownMenuItem(
                  value: env,
                  child: Text(env.name.toUpperCase()),
                );
              }).toList(),
              onChanged: (value) {
                if (value != null) {
                  setState(() => _selectedEnvironment = value);
                }
              },
            ),
            const SizedBox(height: 12),
            TextFormField(
              initialValue: _backendUrl,
              decoration: const InputDecoration(
                labelText: 'Backend URL',
                border: OutlineInputBorder(),
                hintText: 'https://your-backend.com',
              ),
              onChanged: (value) => _backendUrl = value,
            ),
            const SizedBox(height: 12),
            TextFormField(
              initialValue: _apiKey,
              decoration: InputDecoration(
                labelText: 'API Key (Public Key)',
                border: const OutlineInputBorder(),
                hintText: _getApiKeyHint(),
              ),
              onChanged: (value) => _apiKey = value,
              obscureText: true,
            ),
            const SizedBox(height: 16),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton.icon(
                onPressed: _isLoading ? null : _initializePaymentService,
                icon: _isLoading
                    ? const SizedBox(
                        width: 16,
                        height: 16,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const Icon(Icons.settings),
                label: Text(_isLoading
                    ? 'Initializing...'
                    : 'Initialize Payment Service'),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildPaymentForm() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Payment Details',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  flex: 2,
                  child: TextFormField(
                    controller: _amountController,
                    decoration: const InputDecoration(
                      labelText: 'Amount',
                      border: OutlineInputBorder(),
                    ),
                    keyboardType:
                        const TextInputType.numberWithOptions(decimal: true),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: TextFormField(
                    controller: _currencyController,
                    decoration: const InputDecoration(
                      labelText: 'Currency',
                      border: OutlineInputBorder(),
                    ),
                    textCapitalization: TextCapitalization.characters,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),
            TextFormField(
              controller: _descriptionController,
              decoration: const InputDecoration(
                labelText: 'Description',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            TextFormField(
              controller: _orderIdController,
              decoration: const InputDecoration(
                labelText: 'Order ID',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            TextFormField(
              controller: _emailController,
              decoration: const InputDecoration(
                labelText: 'Customer Email',
                border: OutlineInputBorder(),
              ),
              keyboardType: TextInputType.emailAddress,
            ),
            const SizedBox(height: 12),
            TextFormField(
              controller: _nameController,
              decoration: const InputDecoration(
                labelText: 'Customer Name',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 16),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton.icon(
                onPressed: _isLoading || !_paymentService.isInitialized
                    ? null
                    : _makePayment,
                icon: _isLoading
                    ? const SizedBox(
                        width: 16,
                        height: 16,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const Icon(Icons.payment),
                label: Text(_isLoading ? 'Processing...' : 'Make Payment'),
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.green,
                  foregroundColor: Colors.white,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildResultSection() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Last Result',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 8),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.grey[100],
                borderRadius: BorderRadius.circular(8),
                border: Border.all(color: Colors.grey[300]!),
              ),
              child: Text(
                _lastResult,
                style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                      fontFamily: 'monospace',
                    ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _updateApiKeyPlaceholder() {
    // Update API key placeholder based on selected provider
    switch (_selectedProvider) {
      case PaymentProvider.stripe:
        _apiKey = 'pk_test_...';
        break;
      case PaymentProvider.paypal:
        _apiKey = 'your-paypal-client-id';
        break;
      case PaymentProvider.razorpay:
        _apiKey = 'rzp_test_...';
        break;
      case PaymentProvider.paystack:
        _apiKey = 'pk_test_...';
        break;
      case PaymentProvider.flutterwave:
        _apiKey = 'FLWPUBK_TEST-...';
        break;
    }
  }

  String _getApiKeyHint() {
    switch (_selectedProvider) {
      case PaymentProvider.stripe:
        return 'pk_test_... (Stripe Publishable Key)';
      case PaymentProvider.paypal:
        return 'PayPal Client ID';
      case PaymentProvider.razorpay:
        return 'rzp_test_... (RazorPay Key ID)';
      case PaymentProvider.paystack:
        return 'pk_test_... (Paystack Public Key)';
      case PaymentProvider.flutterwave:
        return 'FLWPUBK_TEST-... (Flutterwave Public Key)';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Unified Payment Demo'),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            _buildProviderConfig(),
            const SizedBox(height: 16),
            _buildPaymentForm(),
            const SizedBox(height: 16),
            _buildResultSection(),
          ],
        ),
      ),
    );
  }
}
2
likes
160
points
30
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package that provides a unified API for multiple payment providers (Stripe, PayPal, RazorPay, Paystack, Flutterwave) using a WebView-first approach.

Repository (GitHub)
View/report issues

Topics

#payment #stripe #webview #paypal #flutter

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

equatable, flutter, http, webview_flutter

More

Packages that depend on unified_payment