payu_bharatkosh_encryption_wrapper 1.0.0-alpha.1 copy "payu_bharatkosh_encryption_wrapper: ^1.0.0-alpha.1" to clipboard
payu_bharatkosh_encryption_wrapper: ^1.0.0-alpha.1 copied to clipboard

Flutter wrapper for BharatKosh encryption SDK that internally uses PayU CheckoutPro native SDKs for Android and iOS.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'BharatKosh Encryption Wrapper Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF00A86B),
          brightness: Brightness.light,
        ),
        useMaterial3: true,
        fontFamily: 'SF Pro Display',
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF00A86B),
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const PaymentPage(),
    );
  }
}

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

  @override
  State<PaymentPage> createState() => _PaymentPageState();
}

class _PaymentPageState extends State<PaymentPage> {
  // Default sample values from iOS sample app
  static const String _defaultEncryptedPayload = 
      "lxtLlNkazs3eF7p5ZvO2jpEuBB9T3UzD50t1S2xyQuY5FyGpmRXY0MEMfWEv2u7bfEhcWTQy9Cd4u7UowNanz60xenaIZAZoL0AsSKdWIK3WgE0yjvIzeWDJvJaOmhzF4/Jtu9OgMwU2Wn6ut+o0bvomrwv+Shpiz8DuuLK04aOk/kObh/0s0hWmVSMEs/PS0YtbxaMBQ56I0Gn2GGCd55NW+9bG4xmq3M1uFEmpvhavSn4vT/+GTc2iSilyQIRjz8Rzop8P3mdIP5Lh8CuIu0YstBe6VAMlQnCmg/Dn0chnLg7emLH+vithrlj3gnWTUh46CxP2k06r2lsx2T+A2ZBr3iDltAAs9sPxWpdU1/U=";
  
  static const String _defaultDigitalSignature = 
      "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";
  
  static const String _defaultMerchantId = "g9jmjm";

  final _encryptedPayloadController = TextEditingController(text: _defaultEncryptedPayload);
  final _digitalSignatureController = TextEditingController(text: _defaultDigitalSignature);
  final _merchantIdController = TextEditingController(text: _defaultMerchantId);
  
  bool _isProduction = false;
  bool _isLoading = false;
  String? _responseText;
  BharatkoshResultType? _resultType;

  final BharatkoshWrapper _wrapper = BharatkoshWrapper();

  @override
  void dispose() {
    _encryptedPayloadController.dispose();
    _digitalSignatureController.dispose();
    _merchantIdController.dispose();
    super.dispose();
  }

  Future<void> _startPaymentWithCallback() async {
    if (!_validateInputs()) return;

    setState(() {
      _isLoading = true;
      _responseText = null;
      _resultType = null;
    });

    _wrapper.startPayment(
      encRequestParameter: _encryptedPayloadController.text.trim(),
      reqDigitalSignature: _digitalSignatureController.text.trim(),
      merchIdVal: _merchantIdController.text.trim(),
      isProduction: _isProduction,
      callback: _PaymentCallback(
        onResult: (type, response) {
          if (mounted) {
            setState(() {
              _isLoading = false;
              _resultType = type;
              _responseText = response;
            });
            _showResultDialog(type, response);
          }
        },
      ),
    );
  }

  Future<void> _startPaymentAsync() async {
    if (!_validateInputs()) return;

    setState(() {
      _isLoading = true;
      _responseText = null;
      _resultType = null;
    });

    try {
      final result = await _wrapper.startPaymentAsync(
        encRequestParameter: _encryptedPayloadController.text.trim(),
        reqDigitalSignature: _digitalSignatureController.text.trim(),
        merchIdVal: _merchantIdController.text.trim(),
        isProduction: _isProduction,
      );

      if (mounted) {
        setState(() {
          _isLoading = false;
          _resultType = result.type;
          _responseText = result.encryptedResponse;
        });
        _showResultDialog(result.type, result.encryptedResponse);
      }
    } catch (e) {
      if (mounted) {
        setState(() {
          _isLoading = false;
          _resultType = BharatkoshResultType.error;
          _responseText = e.toString();
        });
        _showResultDialog(BharatkoshResultType.error, e.toString());
      }
    }
  }

  bool _validateInputs() {
    if (_encryptedPayloadController.text.trim().isEmpty) {
      _showSnackBar('Please enter encrypted payload');
      return false;
    }
    if (_digitalSignatureController.text.trim().isEmpty) {
      _showSnackBar('Please enter digital signature');
      return false;
    }
    if (_merchantIdController.text.trim().isEmpty) {
      _showSnackBar('Please enter merchant ID');
      return false;
    }
    return true;
  }

  void _showSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  void _showResultDialog(BharatkoshResultType type, String response) {
    final color = _getResultColor(type);
    final icon = _getResultIcon(type);
    final title = _getResultTitle(type);

    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Row(
          children: [
            Icon(icon, color: color),
            const SizedBox(width: 8),
            Text(title, style: TextStyle(color: color)),
          ],
        ),
        content: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text(
                'Encrypted Response:',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 8),
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.circular(8),
                ),
                child: SelectableText(
                  response,
                  style: const TextStyle(
                    fontFamily: 'monospace',
                    fontSize: 12,
                  ),
                ),
              ),
            ],
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('OK'),
          ),
        ],
      ),
    );
  }

  Color _getResultColor(BharatkoshResultType type) {
    switch (type) {
      case BharatkoshResultType.success:
        return Colors.green;
      case BharatkoshResultType.failure:
        return Colors.red;
      case BharatkoshResultType.cancel:
        return Colors.orange;
      case BharatkoshResultType.error:
        return Colors.red.shade800;
    }
  }

  IconData _getResultIcon(BharatkoshResultType type) {
    switch (type) {
      case BharatkoshResultType.success:
        return Icons.check_circle;
      case BharatkoshResultType.failure:
        return Icons.cancel;
      case BharatkoshResultType.cancel:
        return Icons.highlight_off;
      case BharatkoshResultType.error:
        return Icons.error;
    }
  }

  String _getResultTitle(BharatkoshResultType type) {
    switch (type) {
      case BharatkoshResultType.success:
        return 'Payment Success';
      case BharatkoshResultType.failure:
        return 'Payment Failed';
      case BharatkoshResultType.cancel:
        return 'Payment Cancelled';
      case BharatkoshResultType.error:
        return 'Error';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BharatKosh Payment'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Header Card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  children: [
                    Icon(
                      Icons.payment,
                      size: 48,
                      color: Theme.of(context).colorScheme.primary,
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'BharatKosh Encryption Wrapper',
                      style: Theme.of(context).textTheme.titleLarge,
                    ),
                    const SizedBox(height: 4),
                    Text(
                      'Enter the encrypted payload from BharatKosh to start payment',
                      style: Theme.of(context).textTheme.bodySmall,
                      textAlign: TextAlign.center,
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),

            // Input Fields
            TextField(
              controller: _encryptedPayloadController,
              decoration: const InputDecoration(
                labelText: 'Encrypted Payload',
                hintText: 'Enter encrypted request parameter',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.lock),
              ),
              maxLines: 3,
            ),
            const SizedBox(height: 16),

            TextField(
              controller: _digitalSignatureController,
              decoration: const InputDecoration(
                labelText: 'Digital Signature',
                hintText: 'Enter request digital signature',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.verified_user),
              ),
              maxLines: 2,
            ),
            const SizedBox(height: 16),

            TextField(
              controller: _merchantIdController,
              decoration: const InputDecoration(
                labelText: 'Merchant ID',
                hintText: 'Enter merchant ID value',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.business),
              ),
            ),
            const SizedBox(height: 16),

            // Environment Toggle
            Card(
              child: SwitchListTile(
                title: const Text('Production Environment'),
                subtitle: Text(
                  _isProduction
                      ? 'Using production servers'
                      : 'Using UAT/test servers',
                ),
                secondary: Icon(
                  _isProduction ? Icons.cloud : Icons.cloud_outlined,
                  color: _isProduction ? Colors.green : Colors.orange,
                ),
                value: _isProduction,
                onChanged: (value) {
                  setState(() {
                    _isProduction = value;
                  });
                },
              ),
            ),
            const SizedBox(height: 24),

            // Payment Buttons
            Row(
              children: [
                Expanded(
                  child: FilledButton.icon(
                    onPressed: _isLoading ? null : _startPaymentWithCallback,
                    icon: _isLoading
                        ? const SizedBox(
                            width: 20,
                            height: 20,
                            child: CircularProgressIndicator(strokeWidth: 2),
                          )
                        : const Icon(Icons.payment),
                    label: const Text('Pay (Callback)'),
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: FilledButton.tonal(
                    onPressed: _isLoading ? null : _startPaymentAsync,
                    child: const Text('Pay (Async)'),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 24),

            // Result Display
            if (_resultType != null && _responseText != null)
              Card(
                color: _getResultColor(_resultType!).withOpacity(0.1),
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          Icon(
                            _getResultIcon(_resultType!),
                            color: _getResultColor(_resultType!),
                          ),
                          const SizedBox(width: 8),
                          Text(
                            _getResultTitle(_resultType!),
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              color: _getResultColor(_resultType!),
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 12),
                      const Text(
                        'Encrypted Response:',
                        style: TextStyle(fontWeight: FontWeight.w500),
                      ),
                      const SizedBox(height: 8),
                      Container(
                        padding: const EdgeInsets.all(12),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: SelectableText(
                          _responseText!,
                          style: const TextStyle(
                            fontFamily: 'monospace',
                            fontSize: 11,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

/// Callback implementation for payment results.
class _PaymentCallback implements BharatkoshWrapperCallback {
  final void Function(BharatkoshResultType type, String response) onResult;

  _PaymentCallback({required this.onResult});

  @override
  void onSuccess(String encryptedResponse) {
    onResult(BharatkoshResultType.success, encryptedResponse);
  }

  @override
  void onFailure(String encryptedResponse) {
    onResult(BharatkoshResultType.failure, encryptedResponse);
  }

  @override
  void onCancel(String encryptedResponse) {
    onResult(BharatkoshResultType.cancel, encryptedResponse);
  }

  @override
  void onError(String encryptedResponse) {
    onResult(BharatkoshResultType.error, encryptedResponse);
  }
}
0
likes
145
points
0
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter wrapper for BharatKosh encryption SDK that internally uses PayU CheckoutPro native SDKs for Android and iOS.

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on payu_bharatkosh_encryption_wrapper

Packages that implement payu_bharatkosh_encryption_wrapper