nexgo_flutter 0.1.0
nexgo_flutter: ^0.1.0 copied to clipboard
Free, open Flutter plugin for NEXGO SmartPOS Android terminals — card reader, EMV transactions, PIN pad, and receipt printer.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:nexgo_flutter/nexgo_flutter.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _pos = NexgoPos.instance;
StreamSubscription<CardInfo>? _cardSub;
String _status = 'Not initialized';
DeviceInfo? _info;
CardInfo? _card;
@override
void dispose() {
_cardSub?.cancel();
_emvSub?.cancel();
super.dispose();
}
Future<void> _init() async {
try {
await _pos.initialize();
final info = await _pos.getDeviceInfo();
setState(() {
_info = info;
_status = 'Initialized';
});
} on NexgoException catch (e) {
setState(() => _status = 'Init failed: $e');
}
}
Future<void> _printSample() async {
try {
await _pos.printReceipt([
PrintBlock.text(
'DEMO STORE',
fontSize: 32,
bold: true,
align: PrintAlign.center,
),
PrintBlock.text('Thank you!', align: PrintAlign.center),
PrintBlock.text('Total: 250.00 ETB', fontSize: 28, bold: true),
PrintBlock.qr('https://example.com/receipt/1001'),
]);
setState(() => _status = 'Printed');
} on NexgoException catch (e) {
setState(() => _status = 'Print failed: $e');
}
}
void _readCard() {
_cardSub?.cancel();
setState(() => _status = 'Present card…');
_cardSub = _pos.searchCard().listen((card) {
setState(() {
_card = card;
_status = 'Card read';
});
_cardSub?.cancel();
}, onError: (e) => setState(() => _status = 'Card error: $e'));
}
StreamSubscription<EmvEvent>? _emvSub;
/// Minimal EMV purchase for 250.00, auto-approving the online step.
/// A real integration loads AIDs/CAPKs first and calls its host at [EmvOnlineRequest].
void _startEmv() {
_emvSub?.cancel();
setState(() => _status = 'EMV: insert/tap card…');
final config = EmvConfig(
amount: '25000',
entryMode: EmvEntryMode.contact,
forceOnline: true,
);
_emvSub = _pos.startTransaction(config).listen((event) async {
switch (event) {
case EmvSelectApp(:final apps):
setState(() => _status = 'EMV: selecting ${apps.first}');
await _pos.emvSelectApp(0);
case EmvConfirmCard(:final card):
setState(() => _status = 'EMV: card ${card.maskCardNo}');
await _pos.emvConfirmCard(true);
case EmvOnlineRequest(:final field55):
setState(() => _status = 'EMV: going online…');
// Authorize with your host using field55/pinBlock/ksn here.
await _pos.emvSubmitOnline(
OnlineDecision.approve(authCode: '123456', field55Hex: field55),
);
case EmvFinish(:final code):
setState(() => _status = 'EMV finished: code $code');
_emvSub?.cancel();
case EmvPrompt(:final prompt):
setState(() => _status = 'EMV prompt: $prompt');
default:
break; // pinEntry / tapCardAgain / removeCard are auto-handled
}
}, onError: (e) => setState(() => _status = 'EMV error: $e'));
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('nexgo_flutter example')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Status: $_status'),
const SizedBox(height: 8),
if (_info != null) Text('Device: ${_info!}'),
if (_card != null) Text('Card: ${_card!}'),
const Spacer(),
FilledButton(onPressed: _init, child: const Text('Initialize')),
FilledButton(
onPressed: () => _pos.beep(),
child: const Text('Beep'),
),
FilledButton(
onPressed: () => _pos.setLed(LedColor.green, on: true),
child: const Text('Green LED on'),
),
FilledButton(
onPressed: _printSample,
child: const Text('Print sample receipt'),
),
FilledButton(
onPressed: _readCard,
child: const Text('Read card'),
),
FilledButton(
onPressed: _startEmv,
child: const Text('Start EMV purchase (250.00)'),
),
],
),
),
),
);
}
}