credo_flutter 0.0.1 copy "credo_flutter: ^0.0.1" to clipboard
credo_flutter: ^0.0.1 copied to clipboard

retracted

Official Credo checkout SDK for Flutter.

example/lib/main.dart

import 'dart:math';

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

void main() {
  CredoCheckout.configure(
    publicKey: 'pk_demo_xxx',
    environment: CredoEnvironment.demo,
    debug: true,
  );

  runApp(const CredoExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Credo Flutter Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _currentIndex = 0;

  final _pages = const [ProductPage(), UrlCheckoutPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: NavigationBar(
        selectedIndex: _currentIndex,
        onDestinationSelected: (index) => setState(() => _currentIndex = index),
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.shopping_bag_outlined),
            selectedIcon: Icon(Icons.shopping_bag),
            label: 'Product',
          ),
          NavigationDestination(
            icon: Icon(Icons.link_outlined),
            selectedIcon: Icon(Icons.link),
            label: 'URL Checkout',
          ),
        ],
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Product Page - Demonstrates CredoCheckout.pay()
// ─────────────────────────────────────────────────────────────────────────────

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

  @override
  State<ProductPage> createState() => _ProductPageState();
}

class _ProductPageState extends State<ProductPage> {
  bool _loading = false;

  Future<void> _buyProduct() async {
    setState(() => _loading = true);

    final result = await CredoCheckout.pay(
      context,
      PaymentInitConfig(
        amount: 250000, // ₦2,500.00 in kobo
        email: 'customer@example.com',
        currency: Currency.ngn,
        bearer: FeeBearer.customer,
        reference: _generateRef(),
      ),
    );

    if (!mounted) return;
    setState(() => _loading = false);

    _showResultSheet(result);
  }

  void _showResultSheet(CheckoutResult result) {
    showModalBottomSheet(
      context: context,
      builder: (context) => ResultSheet(result: result),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Shop'), centerTitle: true),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Product Image
            Container(
              height: 280,
              decoration: BoxDecoration(
                color: Colors.grey.shade100,
                borderRadius: BorderRadius.circular(16),
              ),
              child: const Center(
                child: Icon(Icons.headphones, size: 120, color: Colors.indigo),
              ),
            ),
            const SizedBox(height: 24),

            // Product Info
            const Text(
              'Wireless Headphones',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Text(
              'Premium sound quality with active noise cancellation',
              style: TextStyle(fontSize: 16, color: Colors.grey.shade600),
            ),
            const SizedBox(height: 16),
            const Text(
              '₦2,500.00',
              style: TextStyle(
                fontSize: 28,
                fontWeight: FontWeight.bold,
                color: Colors.indigo,
              ),
            ),
            const SizedBox(height: 32),

            // Buy Button
            FilledButton(
              onPressed: _loading ? null : _buyProduct,
              style: FilledButton.styleFrom(
                padding: const EdgeInsets.symmetric(vertical: 16),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
              child: _loading
                  ? const SizedBox(
                      width: 24,
                      height: 24,
                      child: CircularProgressIndicator(
                        strokeWidth: 2,
                        color: Colors.white,
                      ),
                    )
                  : const Text('Buy Now', style: TextStyle(fontSize: 16)),
            ),
            const SizedBox(height: 16),

            // Info text
            Text(
              'Uses CredoCheckout.pay() to initialize and open checkout',
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 12, color: Colors.grey.shade500),
            ),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// URL Checkout Page - Demonstrates CredoCheckout.open()
// ─────────────────────────────────────────────────────────────────────────────

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

  @override
  State<UrlCheckoutPage> createState() => _UrlCheckoutPageState();
}

class _UrlCheckoutPageState extends State<UrlCheckoutPage> {
  final _controller = TextEditingController();
  bool _loading = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Future<void> _openCheckout() async {
    final url = _controller.text.trim();
    if (url.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Please enter a checkout URL')),
      );
      return;
    }

    setState(() => _loading = true);

    final result = await CredoCheckout.open(context, checkoutUrl: url);

    if (!mounted) return;
    setState(() => _loading = false);

    _showResultSheet(result);
  }

  void _showResultSheet(CheckoutResult result) {
    showModalBottomSheet(
      context: context,
      builder: (context) => ResultSheet(result: result),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('URL Checkout'), centerTitle: true),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Header
            Container(
              padding: const EdgeInsets.all(20),
              decoration: BoxDecoration(
                color: Colors.indigo.shade50,
                borderRadius: BorderRadius.circular(16),
              ),
              child: Column(
                children: [
                  Icon(Icons.link, size: 48, color: Colors.indigo.shade400),
                  const SizedBox(height: 12),
                  const Text(
                    'Open with Checkout URL',
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    'Paste a checkout URL from your backend to open the payment page directly.',
                    textAlign: TextAlign.center,
                    style: TextStyle(color: Colors.grey.shade600),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 24),

            // URL Input
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                labelText: 'Checkout URL',
                hintText: 'https://pay.credodemo.com/v4/...',
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
                prefixIcon: const Icon(Icons.link),
              ),
              keyboardType: TextInputType.url,
              textInputAction: TextInputAction.done,
              onSubmitted: (_) => _openCheckout(),
            ),
            const SizedBox(height: 24),

            // Open Button
            FilledButton(
              onPressed: _loading ? null : _openCheckout,
              style: FilledButton.styleFrom(
                padding: const EdgeInsets.symmetric(vertical: 16),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
              child: _loading
                  ? const SizedBox(
                      width: 24,
                      height: 24,
                      child: CircularProgressIndicator(
                        strokeWidth: 2,
                        color: Colors.white,
                      ),
                    )
                  : const Text('Open Checkout', style: TextStyle(fontSize: 16)),
            ),
            const SizedBox(height: 16),

            // Info text
            Text(
              'Uses CredoCheckout.open() — no SDK configuration required',
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 12, color: Colors.grey.shade500),
            ),
          ],
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Result Sheet - Shows checkout result
// ─────────────────────────────────────────────────────────────────────────────

class ResultSheet extends StatelessWidget {
  final CheckoutResult result;

  const ResultSheet({super.key, required this.result});

  @override
  Widget build(BuildContext context) {
    final (icon, color, title) = switch (result.status) {
      CheckoutStatus.success => (
        Icons.check_circle,
        Colors.green,
        'Payment Successful',
      ),
      CheckoutStatus.failed => (Icons.error, Colors.red, 'Payment Failed'),
      CheckoutStatus.cancelled => (Icons.cancel, Colors.orange, 'Cancelled'),
      CheckoutStatus.unknown => (Icons.help, Colors.grey, 'Unknown Status'),
    };

    return Padding(
      padding: const EdgeInsets.all(24),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 64, color: color),
          const SizedBox(height: 16),
          Text(
            title,
            style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          if (result.transaction != null) ...[
            const SizedBox(height: 16),
            _InfoRow(
              label: 'Amount',
              value:
                  '${result.transaction!.currency ?? ''} ${result.transaction!.amount ?? '-'}',
            ),
            _InfoRow(
              label: 'Transaction Reference',
              value: result.transaction?.transRef ?? '-',
            ),
            if (result.transaction!.message != null)
              _InfoRow(label: 'Message', value: result.transaction!.message!),
          ],
          if (result.hasFieldErrors) ...[
            const SizedBox(height: 16),
            ...result.fieldErrors!.entries.map(
              (e) => _InfoRow(label: e.key, value: e.value),
            ),
          ],
          const SizedBox(height: 24),
          SizedBox(
            width: double.infinity,
            child: FilledButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Done'),
            ),
          ),
        ],
      ),
    );
  }
}

class _InfoRow extends StatelessWidget {
  final String label;
  final String value;

  const _InfoRow({required this.label, required this.value});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: TextStyle(color: Colors.grey.shade600)),
          Flexible(
            child: Text(
              value,
              textAlign: TextAlign.end,
              style: const TextStyle(fontWeight: FontWeight.w500),
            ),
          ),
        ],
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Utilities
// ─────────────────────────────────────────────────────────────────────────────

String _generateRef({int length = 20}) {
  const chars =
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  final random = Random.secure();
  return List.generate(
    length,
    (_) => chars[random.nextInt(chars.length)],
  ).join();
}
0
likes
0
points
63
downloads

Publisher

unverified uploader

Weekly Downloads

Official Credo checkout SDK for Flutter.

Homepage
Repository (GitHub)
View/report issues

Topics

#payments #checkout #flutter #fintech #sdk

License

unknown (license)

Dependencies

flutter, http, webview_flutter

More

Packages that depend on credo_flutter