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

PlatformAndroid

Flutter implementation of Billpocket for Android

example/lib/main.dart

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_billpocket/billpocket.dart';
import 'package:flutter_billpocket/installment.dart';
import 'package:flutter_billpocket/reader.dart';
import 'package:permission_handler/permission_handler.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Billpocket.config(
      isProduction: true,
      token: '{YOUR_TOKEN}');
  runApp(const MyAppPage());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: MyApp());
  }
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _statusSDK = false;
  bool _statusBluetooth = false;
  bool _statusConnection = false;
  List<Reader> _readers = [];
  StreamSubscription<Map<dynamic, dynamic>>? _subscription;
  TextEditingController amountController = TextEditingController();

  List<String> log = [];

  @override
  void initState() {
    super.initState();
    getStatusSDK();
    getStatusBluetoothPermission();
    listenTransactionStream();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Billpocket'),
        actions: [
          IconButton(
            onPressed: () async {
              final log = await Billpocket.getLogs();
              if( context.mounted ){
                _showLogs( context, log );
              }
            }, 
            icon: const Text( 'Logs' )
          )
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
        child: SingleChildScrollView(
          physics: const BouncingScrollPhysics(),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Estados',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              const SizedBox(
                height: 20,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Status(
                    title: 'SDK',
                    isActive: _statusSDK,
                  ),
                  Status(
                    title: 'Bluetooth',
                    isActive: _statusBluetooth,
                  ),
                  Status(
                    title: 'Terminal \nConnection',
                    isActive: _statusConnection,
                  )
                ],
              ),
              const SizedBox(
                height: 10,
              ),
              const Divider(),
              const SizedBox(
                height: 10,
              ),
              const Text(
                'Opciones',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              const SizedBox(
                height: 20,
              ),
              Row(
                children: [
                  Expanded(
                    child: ElevatedButton(
                        onPressed: () async {
                          await [
                            Permission.bluetoothScan,
                            Permission.bluetoothAdvertise,
                            Permission.bluetoothConnect
                          ].request();

                          if (await Permission.bluetoothConnect
                              .request()
                              .isGranted) {
                            setState(() {
                              _statusBluetooth = true;
                            });
                          }
                        },
                        child: const Text('Activar Bluetooth')),
                  ),
                  const SizedBox(
                    width: 20,
                  ),
                  Expanded(
                    child: ElevatedButton(
                        style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.brown)),
                        onPressed: () async {
                          getListReaders();
                        },
                        child: const Text('Obtener terminales')),
                  ),
                ],
              ),
              const SizedBox(
                height: 10,
              ),
              const Divider(),
              const SizedBox(
                height: 10,
              ),
              const Text(
                'Realizar cobro',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              const SizedBox(
                height: 20,
              ),
              TextField(
                controller: amountController,
                keyboardType: TextInputType.phone,
                inputFormatters: [
                  FilteringTextInputFormatter.allow(RegExp(r"[0-9.]"))
                ],
                decoration: const InputDecoration.collapsed(
                  hintText: 'Monto',
                ),
              ),
              const SizedBox(
                height: 20,
              ),
              Row(
                children: [
                  Expanded(
                    child: ElevatedButton(
                        style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.green)),
                        onPressed: () async {
                          FocusManager.instance.primaryFocus?.unfocus();
                          setState(() {
                            log.clear();
                          });
                          await Billpocket.doTransaction(
                              amount: amountController.text,
                              tip: "0",
                              latitude: 19.42691938620286,
                              longitude: -99.16780320031096,
                              description: "description");
                        },
                        child: const Text('Cobrar')),
                  ),
                ],
              ),
              const SizedBox(
                height: 20,
              ),
              const Text('Log de Transacción',
                  style: TextStyle(fontWeight: FontWeight.bold)),
              const SizedBox(
                height: 10,
              ),
              ListView.separated(
                itemBuilder: (context, pos) {
                  if (pos == 0) {
                    return Row(children: [
                      const Icon(Icons.arrow_forward_ios_rounded, size: 15, color: Colors.lightGreen,),
                      const SizedBox(width: 10,),
                      Expanded(child: Text(log[pos], style: const TextStyle(color: Colors.lightGreen, fontWeight: FontWeight.bold),))
                    ],);
                  }
                  return Text(log[pos], style: const TextStyle(color: Colors.grey),);
                },
                itemCount: log.length,
                shrinkWrap: true, separatorBuilder: (BuildContext context, int index) {
                  return Divider();
              },
              )
            ],
          ),
        ),
      ),
    );
  }

  Future<dynamic> _showLogs(BuildContext context, String log) {
    return showDialog(
      context: context, 
      builder: (context) => AlertDialog(
        content: Column(
          children: [
            const Text( 'LOGS' ),
            Expanded(
              child: SingleChildScrollView(
                child: Text( log.isEmpty ? 'Sin logs' : log )
              )
            ),
          ],
        ),
      )
    );
  }

  Future<void> getStatusSDK() async {
    bool statusSDK;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      statusSDK = await Billpocket.getStatusSDK();
    } on PlatformException {
      statusSDK = false;
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _statusSDK = statusSDK;
    });
  }

  getListReaders() async {
    List<Reader> readers;

    try {
      readers = await Billpocket.getReaders();
    } on PlatformException {
      readers = [];
    }

    if (!mounted) return;

    setState(() {
      _readers = readers;
      showTerminals();
    });
  }

  connectReader(
      {required int readerType,
      required String readerMacAddress,
      required String name}) async {
    bool statusConnection;

    try {
      statusConnection = await Billpocket.connectReader(
          readerType: readerType,
          readerMacAddress: readerMacAddress,
          name: name);
    } on PlatformException {
      statusConnection = false;
    }

    if (!mounted) return;

    setState(() {
      _statusConnection = statusConnection;
    });
  }

  getStatusBluetoothPermission() async {
    var status = await Permission.bluetoothScan.status;
    if (status.isGranted) {
      setState(() {
        _statusBluetooth = true;
      });
    } else {
      setState(() {
        _statusBluetooth = false;
      });
    }
  }

  void listenTransactionStream() {
    _subscription = Billpocket.transactionStream().listen((event) {
      final eventName = event['event'];
      final message = event['message'];

      switch (eventName) {
        case 'onTransactionAborted':
          // Handle the onTransactionAborted event
          print('Transaction aborted: $message');
          break;
        case 'onBeforeTransaction':
          // Handle the onBeforeTransaction event
          print('Transaction before: $message');
          break;
        case 'onCardRead':
          // Handle the onCardRead event
          print('Transaction card read: $message');
          break;
        case 'getSignature':
          // Handle the getSignature event
          print('Transaction get signature: $message');
          break;
        case 'onReaderWaitingForCard':
          // Handle the onReaderWaitingForCard event
          print('Transaction reader waiting for card: $message');
          break;
        case 'onMsiDefined':
          // Handle the onMsiDefined event
          final list = event['list'];
          print('Transaction msi defined: $message');
          print('MSI list: $list');
          showMSI(list);
          break;
        case 'onGetPin':
          // Handle the onGetPin event
          print('Transaction get pin: $message');
          break;
        case 'onMagneticCardFound':
          // Handle the onMagneticCardFound event
          print('Transaction magnetic card found: $message');
          break;
        case 'onTransactionFinished':
          // Handle the onTransactionFinished event
          print('Transaction finished: $message');
          break;
        case 'onTransactionSuccessful':
          // Handle the onTransactionSuccessful event
          print('Transaction successful: $message');
          break;
        case 'resultStartTransaction':
          // Handle the resultStartTransaction event
          print('Transaction result start: $message');
          break;
        case 'resultStartTransactionSuccess':
          // Handle the resultStartTransactionSuccess event
          print('Transaction result start success: $message');
          break;
        case 'resultStartTransactionError':
          // Handle the resultStartTransactionError event
          print('Transaction result start error: $message');
          break;
        // Handle other events similarly
        default:
          print('Unknown event received: $eventName');
          break;
      }

      setState(() {
        log.insert(0, message);
      });
    }, onError: (error) {
      print("Error received: $error");
    });
  }

  @override
  void dispose() {
    _subscription?.cancel();
    super.dispose();
  }

  void showTerminals() {
    showModalBottomSheet<void>(
        context: context,
        builder: (context) {
          return Padding(
            padding: const EdgeInsets.all(8.0),
            child: SizedBox(
              child: ListView.separated(
                itemBuilder: (context, pos) => Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      _readers[pos].name,
                      style: const TextStyle(
                          fontWeight: FontWeight.bold, fontSize: 17),
                    ),
                    ElevatedButton(
                        style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.orange)),
                        onPressed: () {
                          Navigator.pop(context);
                          connectReader(
                              readerType: _readers[pos].type,
                              readerMacAddress: _readers[pos].macAddress,
                              name: _readers[pos].name);
                        },
                        child: const Text('Conectar'))
                  ],
                ),
                itemCount: _readers.length,
                shrinkWrap: true,
                separatorBuilder: (BuildContext context, int index) {
                  return const Divider();
                },
              ),
            ),
          );
        });
  }

  void showMSI(list) {
    List<Installment> installment = List<Installment>.from(
        json.decode(list).map((x) => Installment.fromJson(x)));

    showModalBottomSheet<void>(
        context: context,
        builder: (context) {
          return Padding(
            padding: const EdgeInsets.all(8.0),
            child: SizedBox(
              child: ListView.separated(
                itemBuilder: (context, pos) => Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      '${installment[pos].value.toString()} meses sin intereses',
                      style: const TextStyle(
                          fontWeight: FontWeight.bold, fontSize: 17),
                    ),
                    ElevatedButton(
                        style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.orange)),
                        onPressed: () {
                          Billpocket.continueWithMsi(
                            commission: installment[pos].commission!,
                            installments: installment[pos].value!,
                            minAmount: installment[pos].minAmount!,
                          );
                          Navigator.pop(context);
                        },
                        child: const Text('Elegir'))
                  ],
                ),
                itemCount: installment.length,
                shrinkWrap: true,
                separatorBuilder: (BuildContext context, int index) {
                  return const Divider();
                },
              ),
            ),
          );
        });
  }
}

class Status extends StatelessWidget {
  const Status({
    super.key,
    required this.isActive,
    required this.title,
  });

  final bool isActive;
  final String title;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: isActive ? Colors.green : Colors.red),
          width: 10,
          height: 10,
        ),
        const SizedBox(
          height: 10,
        ),
        Text(
          title,
          textAlign: TextAlign.center,
          style: const TextStyle(fontWeight: FontWeight.bold),
        )
      ],
    );
  }
}
5
likes
130
points
17
downloads

Publisher

verified publisherapprecio.mx

Weekly Downloads

Flutter implementation of Billpocket for Android

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_billpocket