smart_pay 0.1.2 copy "smart_pay: ^0.1.2" to clipboard
smart_pay: ^0.1.2 copied to clipboard

Unified Flutter payments toolkit supporting Stripe Payment Sheets and Payment Links with automatic URL generation, manual handling, and provider-driven configuration.

example/lib/main.dart

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:smart_pay/smart_pay.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Load environment variables
  await dotenv.load(fileName: ".env");

  // Get API keys from environment
  final String publishableKey = dotenv.env['STRIPE_PUBLISHABLE_KEY'] ?? '';
  final String secretKey = dotenv.env['STRIPE_SECRET_KEY'] ?? '';

  if (publishableKey.isEmpty || secretKey.isEmpty) {
    throw Exception(
      'Please set STRIPE_PUBLISHABLE_KEY and STRIPE_SECRET_KEY in your .env file',
    );
  }

  // Configure Smart Pay with payment methods
  SmartPay.configure(
    SmartPayConfig(
      providers: [
        // Stripe provider with custom name
        StripeProvider(
          publishableKey: publishableKey,
          secretKey: secretKey,
          displayName: 'Credit Card',
        ),

        // Another Stripe provider for web payments
        StripeProvider(
          publishableKey: publishableKey,
          secretKey: secretKey,
          displayName: 'Pay Online',
          mode: PaymentMode.url, // Force web payment
          urlConfig: StripeURLConfig(
            successUrl: 'https://example.com/success',
            cancelUrl: 'https://example.com/cancel',
            allowPromotionCodes: true,
            urlHandlingMode: UrlHandlingMode.manual,
          ),
        ),
      ],
    ),
  );

  runApp(const SmartPayExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Smart Pay Example',
      theme: ThemeData(colorSchemeSeed: Colors.blue, useMaterial3: true),
      home: const CheckoutScreen(),
    );
  }
}

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

  @override
  State<CheckoutScreen> createState() => _CheckoutScreenState();
}

class _CheckoutScreenState extends State<CheckoutScreen> {
  bool _isLoading = false;

  @override
  Widget build(BuildContext context) {
    // Get platform info for display
    final platformInfo = PlatformDetector.getPlatformDefaults();

    return Scaffold(
      appBar: AppBar(
        title: const Text('Smart Pay Checkout'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Platform info card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Platform: ${platformInfo['platform']}',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Default Mode: ${platformInfo['defaultMode']}',
                      style: Theme.of(context).textTheme.bodyMedium,
                    ),
                    Text(
                      'SDK Support: ${platformInfo['supportsSdk'] ? 'Yes' : 'No'}',
                      style: Theme.of(context).textTheme.bodyMedium,
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 24),

            // Payment methods section
            Text(
              'Choose Payment Method',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            const SizedBox(height: 16),

            // Smart Pay Methods widget
            SmartPayMethods(
              store: SmartPay.store,
              onMethodSelected: (provider) {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text('Selected: ${provider.displayName}'),
                    duration: const Duration(seconds: 2),
                  ),
                );
              },
            ),

            const SizedBox(height: 32),

            // Order summary
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Order Summary',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    const Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [Text('Smart Pay Demo Item'), Text('\$19.99')],
                    ),
                    const Divider(),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text(
                          'Total',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        Text(
                          '\$19.99',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 24),

            // Pay button
            FilledButton(
              onPressed: _isLoading ? null : _processPayment,
              style: FilledButton.styleFrom(
                minimumSize: const Size(double.infinity, 50),
              ),
              child: _isLoading
                  ? const SizedBox(
                      height: 20,
                      width: 20,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Text('Pay \$19.99', style: TextStyle(fontSize: 16)),
            ),

            const SizedBox(height: 16),

            // Help text
            Text(
              'This is a demo app. No real charges will be made.',
              textAlign: TextAlign.center,
              style: Theme.of(
                context,
              ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _processPayment() async {
    setState(() {
      _isLoading = true;
    });

    try {
      final result = await SmartPay.checkout(
        const PayRequest(
          amountMinorUnits: 1999, // $19.99
          currency: 'USD',
          description: 'Smart Pay Demo Purchase',
          flowMode: PaymentFlowMode.testing,
        ),
      );

      // Log the result for debugging
      log('Payment result: ${result.toString()}');

      // Handle payment URL if present (for URL-based payments)
      if (result.success && result.paymentUrl != null) {
        _showPaymentUrlDialog(result.paymentUrl!);
      } else {
        // Show result dialog
        _showResultDialog(result);
      }
    } catch (e) {
      log('Payment error: $e');
      _showResultDialog(
        PaymentResult.failure(
          providerId: 'unknown',
          message: 'Payment failed: $e',
        ),
      );
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  void _showResultDialog(PaymentResult result) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Icon(
          result.success ? Icons.check_circle : Icons.error,
          color: result.success ? Colors.green : Colors.red,
          size: 48,
        ),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              result.success ? 'Payment Successful!' : 'Payment Failed',
              style: Theme.of(context).textTheme.titleMedium,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            Text(
              result.message ?? 'No additional information',
              textAlign: TextAlign.center,
            ),
            if (result.transactionId != null) ...[
              const SizedBox(height: 8),
              Text(
                'Transaction ID: ${result.transactionId}',
                style: Theme.of(context).textTheme.bodySmall,
                textAlign: TextAlign.center,
              ),
            ],
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('OK'),
          ),
        ],
      ),
    );
  }

  void _showPaymentUrlDialog(String paymentUrl) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Payment URL Generated'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text('A payment URL was generated for manual handling:'),
            const SizedBox(height: 12),
            Container(
              padding: const EdgeInsets.all(8),
              decoration: BoxDecoration(
                color: Colors.grey[100],
                borderRadius: BorderRadius.circular(4),
              ),
              child: SelectableText(
                paymentUrl,
                style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
              ),
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('Close'),
          ),
          FilledButton(
            onPressed: () {
              Navigator.of(context).pop();
              // Here you would implement your URL handling logic
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('Implement custom URL handling here!'),
                ),
              );
            },
            child: const Text('Handle URL'),
          ),
        ],
      ),
    );
  }
}
1
likes
160
points
281
downloads

Publisher

verified publishermwaqas.mobvers.com

Weekly Downloads

Unified Flutter payments toolkit supporting Stripe Payment Sheets and Payment Links with automatic URL generation, manual handling, and provider-driven configuration.

Repository (GitHub)
View/report issues
Contributing

Topics

#payments #stripe #flutter #payment-processing #payment-gateway

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter, flutter_stripe, http, url_launcher

More

Packages that depend on smart_pay