telebirr_inapp_sdk 0.1.0 copy "telebirr_inapp_sdk: ^0.1.0" to clipboard
telebirr_inapp_sdk: ^0.1.0 copied to clipboard

A Flutter plugin for integrating Telebirr payment SDK in Flutter applications.

example/lib/main.dart

// ignore_for_file: prefer_typing_uninitialized_variables

import 'dart:async';
import 'dart:io' show Platform;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:telebirr_inapp_sdk/telebirr_inapp_sdk.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Platform.isIOS ? 'Telebirr SDK iOS Demo' : 'Telebirr SDK Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const PaymentScreen(),
    );
  }
}

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

  @override
  State<PaymentScreen> createState() => _PaymentScreenState();
}

class _PaymentScreenState extends State<PaymentScreen> {
  final TextEditingController _amountController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  bool _isProcessing = false;
  String _errorMessage = '';
  String receiveCode = "";

  // Configuration constants
  static const String appId = "YOUR_APP_ID";
  static const String shortCode = "YOUR_SHORT_CODE";

  /// Disposes the resources used by this state, including the
  /// amount text controller, and calls the superclass dispose
  /// method. This should be called when the state is removed
  /// from the widget tree to free up resources.

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

  // Validate amount
  String? _validateAmount(String? value) {
    if (value == null || value.isEmpty) {
      return 'Amount is required';
    }

    try {
      double amount = double.parse(value);
      if (amount <= 0) {
        return 'Amount must be greater than 0';
      }
      if (amount > 100000) {
        // Example maximum amount
        return 'Amount cannot exceed 100,000';
      }
    } catch (e) {
      return 'Please enter a valid number';
    }

    // Check for decimal places
    if (value.contains('.')) {
      int decimalPlaces = value.split('.')[1].length;
      if (decimalPlaces > 2) {
        return 'Maximum 2 decimal places allowed';
      }
    }

    return null;
  }

  Future<void> _startPayment() async {
    if (!_formKey.currentState!.validate()) {
      return;
    }
    try {
      double amount = double.parse(_amountController.text);
      if (amount <= 0) {
        setState(() {
          _errorMessage = 'Amount must be greater than 0';
        });
        return;
      }

      setState(() {
        _isProcessing = true;
        _errorMessage = '';
      });

      // First get the receiveCode from your API
      final receiveCodeResult = await _getReceiveCode(
        amount: _amountController.text,
        title: "Telebirr Payment",
      );
      if (receiveCodeResult != null &&
          receiveCodeResult['createOrderResult']['result']
                  .toString()
                  .toLowerCase() ==
              'success') {
        setState(() {
          receiveCode = receiveCodeResult['createOrderResult']['biz_content']
              ['receiveCode'];
        });

        // Initialize the SDK and start payment
        final sdk = TelebirrInappSdk(
          appId: appId,
          shortCode: shortCode,
          receiveCode: receiveCode,
        );

        final result = await sdk.startPayment();
        debugPrint("Payment result: $result");

        // Always set processing to false when we get a response
        setState(() {
          _isProcessing = false;
        });

        if (!mounted) return;

        // Show appropriate message based on status
        bool isSuccess = (result.isNotEmpty && result["status"] == true);
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text(
              isSuccess
                  ? "Payment completed successfully!"
                  : "Payment failed due to: ${result['message']}",
              style: TextStyle(color: Colors.white)),
          backgroundColor: isSuccess ? Colors.green : Colors.red,
        ));
      } else {
        setState(() {
          _isProcessing = false;
          _errorMessage =
              receiveCodeResult?['message'] ?? 'Failed to get receive code';
        });
      }
    } catch (e) {
      setState(() {
        _isProcessing = false;
        _errorMessage = "An error occurred: ${e.toString()}";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
            Platform.isIOS ? 'Telebirr SDK iOS Demo' : 'Telebirr SDK Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Form(
          key: _formKey,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Image.asset(
                "images/telebirr.png",
                height: 200,
                width: 200,
              ),
              const SizedBox(height: 30),
              TextFormField(
                controller: _amountController,
                keyboardType:
                    const TextInputType.numberWithOptions(decimal: true),
                decoration: InputDecoration(
                  labelText: 'Amount (ETB)',
                  hintText: 'Enter amount',
                  prefixIcon: const Icon(Icons.monetization_on),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                  errorMaxLines: 2,
                ),
                validator: _validateAmount,
                enabled: !_isProcessing,
                // Format input to allow only numbers and one decimal point
                inputFormatters: [
                  FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}')),
                ],
              ),
              const SizedBox(height: 8),
              if (_errorMessage.isNotEmpty)
                Container(
                  padding: const EdgeInsets.all(8),
                  decoration: BoxDecoration(
                    color: Colors.red.shade50,
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: Text(
                    _errorMessage,
                    style: TextStyle(color: Colors.red.shade700),
                  ),
                ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: _startPayment,
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.black,
                  foregroundColor: Colors.white,
                  padding: const EdgeInsets.symmetric(vertical: 16),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
                child: _isProcessing
                    ? const SpinKitThreeBounce(
                        color: Colors.white,
                        size: 24,
                      )
                    : const Text(
                        'Pay with Telebirr',
                        style: TextStyle(fontSize: 16),
                      ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  // Example implementation of getting receive code from your API
  Future<dynamic> _getReceiveCode(
      {required String amount, required String title}) async {
    setState(() {
      _isProcessing = true;
    });

    var url = "YOUR_BACKEND_API_URL";
    Map data = {
      "amount": amount,
      "title": title,
    };
    var body = json.encode(data);
    try {
      http.Response response = await http
          .post(
        Uri.parse(url),
        headers: <String, String>{
          "Content-Type": "application/json",
          "Accept": "application/json"
        },
        body: body,
      )
          .timeout(
        const Duration(seconds: 15),
        onTimeout: () {
          setState(() {
            _isProcessing = false;
          });
          throw TimeoutException("The connection has timed out!");
        },
      );

      setState(() {
        _isProcessing = false;
      });

      return json.decode(response.body);
    } catch (e) {
      setState(() {
        _isProcessing = false;
      });
      return null;
    }
  }
}
5
likes
160
points
62
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for integrating Telebirr payment SDK in Flutter applications.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_spinkit, http, package_info_plus

More

Packages that depend on telebirr_inapp_sdk

Packages that implement telebirr_inapp_sdk