halo_sdk_ui 0.1.0
halo_sdk_ui: ^0.1.0 copied to clipboard
Halo Dot tap-on-phone payments for Flutter. Wraps the native sdk_ui library behind one Dart class, so an app can take a card payment on the phone itself without writing native code. Android only.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:halo_sdk_ui/halo_sdk_ui.dart';
/// Every call the plugin offers, on one screen.
///
/// The reads that need no SDK — its version, the NFC state, this device's
/// installation id — are shown first, then the bring-up runs behind them, and
/// the buttons drive the rest. Bring-up needs a real Halo JWT, which this app
/// takes from `--dart-define=HALO_JWT=…`; without one `init` fails and the
/// buttons that need a live SDK do nothing, while everything above still reads.
void main() => runApp(const ExampleApp());
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
final _halo = HaloSdkUi();
String _sdkVersion = 'unknown';
bool? _nfc;
String _installationId = 'not registered';
String _lastOutcome = '—';
@override
void initState() {
super.initState();
_start();
}
Future<void> _start() async {
final sdkVersion = await _read(_halo.sdkInfo) ?? 'unknown';
final nfc = await _read(_halo.nfc);
final installationId =
await _read(_halo.deviceInstallationId) ?? 'not registered';
// Shown before the slow half: `init` suspends until the SDK settles, so
// waiting for it here would leave the screen empty until it did.
if (!mounted) return;
setState(() {
_sdkVersion = sdkVersion;
_nfc = nfc;
_installationId = installationId;
});
_halo.setTokenProvider(() async {
return const String.fromEnvironment('HALO_JWT');
});
await _read(_halo.prepare);
final outcome = await _read(_halo.init);
debugPrint('init → $outcome');
}
/// One call, with the platform's refusals logged rather than thrown: on a
/// platform the plugin does not serve, every one of these is a
/// `MissingPluginException`.
Future<T?> _read<T>(Future<T?> Function() call) async {
try {
return await call();
} on PlatformException catch (error) {
debugPrint('${error.code}: ${error.message}');
} on MissingPluginException {
debugPrint('halo_sdk_ui serves Android only');
}
return null;
}
Future<void> _charge({String? amount, String? presentation}) async {
final result = await _read(
() => _halo.transact(
amount,
'ZAR',
reference: 'example-${DateTime.now().millisecondsSinceEpoch}',
presentation: presentation,
),
);
debugPrint('transact → $result');
if (!mounted) return;
setState(() => _lastOutcome = result?['resultType'] ?? 'no result');
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: const Text('halo_sdk_ui')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Text(
'SDK $_sdkVersion\n'
'NFC ${switch (_nfc) {
null => 'no hardware',
true => 'on',
false => 'off',
}}\n'
'Installation $_installationId\n'
'Last outcome $_lastOutcome',
),
const Divider(height: 32),
FilledButton(
onPressed: () => _charge(amount: '10.00'),
child: const Text('Charge R10.00'),
),
FilledButton(
onPressed: () => _charge(amount: '10.00', presentation: 'SHEET'),
child: const Text('Charge R10.00, as a sheet'),
),
FilledButton(
onPressed: _charge,
child: const Text("Charge on the SDK's own keypad"),
),
const SizedBox(height: 16),
OutlinedButton(
onPressed: () => _read(_halo.openNfcSettings),
child: const Text('Open NFC settings'),
),
OutlinedButton(
onPressed: () => _read(() => _halo.language('af')),
child: const Text('Speak Afrikaans'),
),
OutlinedButton(
onPressed: () => _read(
() => _halo.browser('https://docs.halodot.io'),
),
child: const Text('Open the docs in a browser'),
),
OutlinedButton(
onPressed: () async {
// The handshake a scanner sits inside: the kernel cancels a
// transaction when something else takes the camera unannounced.
await _read(() => _halo.camera(true));
await _read(() => _halo.camera(false));
},
child: const Text('Borrow and return the camera'),
),
OutlinedButton(
onPressed: () => _read(_halo.forgetRegistration),
child: const Text('Forget this terminal registration'),
),
],
),
),
);
}
}