end2endpay_flutter_sdk 1.0.0 copy "end2endpay_flutter_sdk: ^1.0.0" to clipboard
end2endpay_flutter_sdk: ^1.0.0 copied to clipboard

A Flutter SDK for End2EndPay payment integration with secure WebView support.

example/lib/main.dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:end2endpay_flutter_sdk/end2endpay_flutter_sdk.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'End2EndPay Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final _formKey = GlobalKey<FormState>();
  final _amountController = TextEditingController(text: '100.00');
  final _currencyController = TextEditingController(text: 'USD');
  final _emailController = TextEditingController(text: 'customer@example.com');
  final _apiKeyController = TextEditingController(text: 'KEY-E2E-17207416075629c1e9lveY8RKUv6CMnnsGQVVXgPLY5Fq');
  final _accessTokenController = TextEditingController(text: 'E2E_AK_17207416075668nQr6Y4CMEvAK13cqGJiktgpIdkqvUOKKtL74BnADk9LoYg1');

  @override
  void dispose() {
    _amountController.dispose();
    _currencyController.dispose();
    _emailController.dispose();
    _apiKeyController.dispose();
    _accessTokenController.dispose();
    super.dispose();
  }

  void _makePayment() {
    if (_formKey.currentState!.validate()) {
      Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => PaymentScreen(
            apiKey: _apiKeyController.text,
            accessToken: _accessTokenController.text,
            amount: double.parse(_amountController.text),
            currency: _currencyController.text,
            email: _emailController.text,
          ),
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('End2EndPay Demo'),
        elevation: 2,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              const SizedBox(height: 20),
              const Icon(
                Icons.payment,
                size: 80,
                color: Colors.blue,
              ),
              const SizedBox(height: 20),
              const Text(
                'Payment Configuration',
                style: TextStyle(
                  fontSize: 24,
                  fontWeight: FontWeight.bold,
                ),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 30),
              TextFormField(
                controller: _apiKeyController,
                decoration: const InputDecoration(
                  labelText: 'API Key',
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.key),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter API key';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: _accessTokenController,
                decoration: const InputDecoration(
                  labelText: 'Access Token',
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.lock),
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter access token';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: _amountController,
                decoration: const InputDecoration(
                  labelText: 'Amount',
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.attach_money),
                ),
                keyboardType: const TextInputType.numberWithOptions(decimal: true),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter amount';
                  }
                  final amount = double.tryParse(value);
                  if (amount == null || amount <= 0) {
                    return 'Please enter valid amount';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: _currencyController,
                decoration: const InputDecoration(
                  labelText: 'Currency',
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.currency_exchange),
                  hintText: 'USD, EUR, GBP',
                ),
                maxLength: 3,
                textCapitalization: TextCapitalization.characters,
                validator: (value) {
                  if (value == null || value.length != 3) {
                    return 'Please enter 3-letter currency code';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 16),
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(
                  labelText: 'Payer Email',
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.email),
                ),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter email';
                  }
                  if (!RegExp(r'^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')
                      .hasMatch(value)) {
                    return 'Please enter valid email';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 30),
              ElevatedButton(
                onPressed: _makePayment,
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(vertical: 16),
                  textStyle: const TextStyle(fontSize: 18),
                ),
                child: const Text('Proceed to Payment'),
              ),
              const SizedBox(height: 20),
              const Card(
                child: Padding(
                  padding: EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Note:',
                        style: TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 16,
                        ),
                      ),
                      SizedBox(height: 8),
                      Text(
                        '• Replace API Key and Access Token with your actual credentials\n'
                            '• All fields are required\n'
                            '• Amount must be greater than 0\n'
                            '• Currency must be a valid 3-letter code',
                        style: TextStyle(fontSize: 14),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class PaymentScreen extends StatelessWidget {
  final String apiKey;
  final String accessToken;
  final double amount;
  final String currency;
  final String email;

  const PaymentScreen({
    Key? key,
    required this.apiKey,
    required this.accessToken,
    required this.amount,
    required this.currency,
    required this.email,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Complete Payment'),
        leading: IconButton(
          icon: const Icon(Icons.close),
          onPressed: () => Navigator.pop(context),
        ),
      ),
      body: End2EndPayWebView(
        apiKey: apiKey,
        accessToken: accessToken,
        amount: amount,
        currency: currency,
        reference: 'ORDER-${DateTime.now().millisecondsSinceEpoch}',
        payerEmail: email,
        onSuccess: (response) {
          debugPrint('✅ Payment Success: $response');

          // Try to parse the response
          String displayMessage = response;
          try {
            final data = jsonDecode(response);
            displayMessage = 'Transaction ID: ${data['transactionId'] ?? 'N/A'}\n'
                'Status: ${data['status'] ?? 'Success'}';
          } catch (e) {
            // If parsing fails, use the raw response
          }

          // Navigate to success screen
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(
              builder: (context) => SuccessScreen(
                message: displayMessage,
                amount: amount,
                currency: currency,
              ),
            ),
          );
        },
        onError: (error) {
          debugPrint('❌ Payment Error: $error');

          // Show error dialog
          showDialog(
            context: context,
            barrierDismissible: false,
            builder: (ctx) => AlertDialog(
              title: const Row(
                children: [
                  Icon(Icons.error, color: Colors.red),
                  SizedBox(width: 8),
                  Text('Payment Failed'),
                ],
              ),
              content: Text(error),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.pop(ctx);
                    Navigator.pop(context);
                  },
                  child: const Text('Close'),
                ),
                ElevatedButton(
                  onPressed: () {
                    Navigator.pop(ctx);
                    // The WebView will remain and can retry
                  },
                  child: const Text('Retry'),
                ),
              ],
            ),
          );
        },
        onCancel: (message) {
          debugPrint('⚠️ Payment Cancelled: $message');

          Navigator.pop(context);
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: const Text('Payment was cancelled'),
              action: SnackBarAction(
                label: 'Retry',
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => PaymentScreen(
                        apiKey: apiKey,
                        accessToken: accessToken,
                        amount: amount,
                        currency: currency,
                        email: email,
                      ),
                    ),
                  );
                },
              ),
            ),
          );
        },
      ),
    );
  }
}

class SuccessScreen extends StatelessWidget {
  final String message;
  final double amount;
  final String currency;

  const SuccessScreen({
    Key? key,
    required this.message,
    required this.amount,
    required this.currency,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Payment Complete'),
        automaticallyImplyLeading: false,
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Icon(
                Icons.check_circle,
                color: Colors.green,
                size: 100,
              ),
              const SizedBox(height: 24),
              const Text(
                'Payment Successful!',
                style: TextStyle(
                  fontSize: 28,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 16),
              Text(
                '$currency ${amount.toStringAsFixed(2)}',
                style: const TextStyle(
                  fontSize: 36,
                  fontWeight: FontWeight.bold,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 24),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Transaction Details',
                        style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 12),
                      Text(
                        message,
                        style: const TextStyle(fontSize: 14),
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 32),
              ElevatedButton.icon(
                onPressed: () {
                  Navigator.popUntil(context, (route) => route.isFirst);
                },
                icon: const Icon(Icons.home),
                label: const Text('Back to Home'),
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 32,
                    vertical: 16,
                  ),
                  textStyle: const TextStyle(fontSize: 18),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
2
likes
0
points
48
downloads

Publisher

verified publisherend2endpay.com

Weekly Downloads

A Flutter SDK for End2EndPay payment integration with secure WebView support.

Homepage

License

unknown (license)

Dependencies

flutter, webview_flutter, webview_flutter_android, webview_flutter_wkwebview

More

Packages that depend on end2endpay_flutter_sdk