urovo_pos 0.2.0 copy "urovo_pos: ^0.2.0" to clipboard
urovo_pos: ^0.2.0 copied to clipboard

PlatformAndroid

Flutter plugin for Urovo POS (Android) with printer and scanner APIs, designed for modular feature expansion.

example/lib/main.dart

import 'dart:async';

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

class _TableItem {
  final String name;
  final int qty;
  final int unitPrice;

  const _TableItem({
    required this.name,
    required this.qty,
    required this.unitPrice,
  });
}

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

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

  @override
  State<UrovoExampleApp> createState() => _UrovoExampleAppState();
}

class _UrovoExampleAppState extends State<UrovoExampleApp> {
  static const String _persianFontAsset = 'assets/fonts/RaviFaNum-Regular.ttf';

  String _status = 'Ready';
  final List<String> _logs = <String>[];
  bool _isBusy = false;
  StreamSubscription<UrovoScannerEvent>? _scannerSubscription;

  @override
  void initState() {
    super.initState();
    _scannerSubscription = UrovoPos.scannerEvents.listen(_onScannerEvent);
    _checkSdk();
  }

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

  Future<void> _run(String label, Future<void> Function() action) async {
    if (_isBusy) {
      return;
    }
    setState(() {
      _isBusy = true;
      _status = label;
    });

    try {
      await action();
    } catch (error) {
      if (!mounted) {
        return;
      }
      setState(() {
        _status = 'Failed: $error';
        _logs.insert(0, '[ERROR] $label -> $error');
      });
    } finally {
      if (mounted) {
        setState(() {
          _isBusy = false;
        });
      }
    }
  }

  Future<void> _checkSdk() async {
    await _run('Checking SDK...', () async {
      final available = await UrovoPos.isUrovoSdkAvailable();
      setState(() {
        _status = available
            ? 'SDK available'
            : 'SDK missing. Place urovoSDK-v1.0.13.aar in example/android/app/libs.';
        _logs.insert(0, 'SDK available: $available');
      });
    });
  }

  Future<void> _initPrinter() async {
    await _run('Initializing printer...', () async {
      await UrovoPos.printerInit();
      setState(() {
        _status = 'Printer initialized';
        _logs.insert(0, 'printerInit: OK');
      });
    });
  }

  Future<void> _readStatus() async {
    await _run('Reading printer status...', () async {
      final detail = await UrovoPos.printerGetStatusDetail();
      setState(() {
        _status = detail.status.name;
        _logs.insert(
          0,
          'status: ${detail.status.name} | code=${detail.rawCode} | ${detail.message} | retryable=${detail.retryable}',
        );
      });
    });
  }

  Future<void> _printSample() async {
    await _run('Running printSample...', () async {
      await UrovoPos.printSample();
      setState(() {
        _status = 'Sample print done';
        _logs.insert(
          0,
          'printSample: OK @ ${DateTime.now().toIso8601String()}',
        );
      });
    });
  }

  Future<void> _printTextOnly() async {
    await _run('Running single text sample...', () async {
      final job = UrovoPrintJob()
        ..setGray(2)
        ..text(
          'UROVO TEXT SAMPLE',
          style: const UrovoTextStyle(
            align: UrovoAlign.center,
            bold: true,
            font: UrovoFont.large,
          ),
        )
        ..feedLine(3);

      await UrovoPos.printerRunJob(job);
      setState(() {
        _status = 'Single text print done';
        _logs.insert(
          0,
          'singleTextPrint: OK @ ${DateTime.now().toIso8601String()}',
        );
      });
    });
  }

  Future<void> _printTableDemo() async {
    await _run('Running table print demo...', () async {
      const items = <_TableItem>[
        _TableItem(name: 'Burger', qty: 2, unitPrice: 180000),
        _TableItem(name: 'Fries', qty: 1, unitPrice: 95000),
        _TableItem(name: 'Cola', qty: 3, unitPrice: 45000),
      ];

      var total = 0;
      final job = UrovoPrintJob()
        ..setGray(0)
        ..text(
          'TABLE DEMO',
          style: const UrovoTextStyle(
            align: UrovoAlign.center,
            bold: true,
            font: UrovoFont.large,
          ),
        )
        ..feedLine(1)
        ..blackLine()
        ..textLeftCenterRight(
          'Item',
          'Qty',
          'Price',
          style: const UrovoTextStyle(bold: true),
        )
        ..blackLine();

      for (final item in items) {
        final lineTotal = item.qty * item.unitPrice;
        total += lineTotal;
        job.textLeftCenterRight(item.name, 'x${item.qty}', '$lineTotal');
      }

      job
        ..blackLine()
        ..textLeftRight(
          'TOTAL',
          '$total',
          style: const UrovoTextStyle(bold: true, font: UrovoFont.large),
        )
        ..feedLine(3);

      await UrovoPos.printerRunJob(job);
      setState(() {
        _status = 'Table print done';
        _logs.insert(0, 'tablePrint: OK @ ${DateTime.now().toIso8601String()}');
      });
    });
  }

  Future<void> _printCustomDemo() async {
    await _run('Running custom receipt print...', () async {
      final job = UrovoPrintJob()
        ..setGray(2)
        ..text(
          'UROVO POS DEMO RECEIPT',
          style: const UrovoTextStyle(
            align: UrovoAlign.center,
            bold: true,
            font: UrovoFont.large,
          ),
        )
        ..feedLine(1)
        ..blackLine()
        ..textLeftRight('Item', 'Price')
        ..textLeftCenterRight('Coffee', 'x1', '120,000')
        ..textLeftCenterRight('Cake', 'x1', '180,000')
        ..blackLine()
        ..textLeftRight(
          'TOTAL',
          '300,000',
          style: const UrovoTextStyle(bold: true, font: UrovoFont.large),
        )
        ..feedLine(1)
        ..text(
          'BARCODE TEST',
          style: const UrovoTextStyle(align: UrovoAlign.center, bold: true),
        )
        ..barcode(
          '123456789012',
          align: UrovoAlign.center,
          type: UrovoBarcodeType.ean13,
        )
        ..text(
          'EAN13: 123456789012',
          style: const UrovoTextStyle(
            align: UrovoAlign.center,
            font: UrovoFont.small,
          ),
        )
        ..feedLine(2)
        ..text(
          'QR TEST',
          style: const UrovoTextStyle(align: UrovoAlign.center, bold: true),
        )
        ..qr(
          '222222222222222222222',
          expectedHeight: 220,
          align: UrovoAlign.center,
        )
        ..text(
          'QR payload: 222222222222222222222',
          style: const UrovoTextStyle(
            align: UrovoAlign.center,
            font: UrovoFont.small,
          ),
        )
        ..feedLine(5);

      await UrovoPos.printerRunJob(job);
      setState(() {
        _status = 'Custom print done';
        _logs.insert(
          0,
          'customPrint: OK @ ${DateTime.now().toIso8601String()}',
        );
      });
    });
  }

  Future<void> _printCustomDemoPersian() async {
    await _run('Running Persian table print demo...', () async {
      const items = <_TableItem>[
        _TableItem(name: 'همبرگر', qty: 2, unitPrice: 180000),
        _TableItem(name: 'سیب زمینی', qty: 1, unitPrice: 95000),
        _TableItem(name: 'نوشابه', qty: 3, unitPrice: 45000),
      ];

      var total = 0;
      final job = UrovoPrintJob()
        ..setGray(0)
        ..text(
          'نمونه جدول فارسی',
          style: const UrovoTextStyle(
            align: UrovoAlign.center,
            bold: true,
            font: UrovoFont.large,
            fontAsset: _persianFontAsset,
          ),
        )
        ..feedLine(1)
        ..blackLine()
        ..textLeftCenterRight(
          'مبلغ',
          'تعداد',
          'کالا',
          style: const UrovoTextStyle(
            bold: true,
            fontAsset: _persianFontAsset,
          ),
        )
        ..blackLine();

      for (final item in items) {
        final lineTotal = item.qty * item.unitPrice;
        total += lineTotal;
        job.textLeftCenterRight(
          _formatAmount(lineTotal),
          '${item.qty}',
          item.name,
          style: const UrovoTextStyle(fontAsset: _persianFontAsset),
        );
      }

      job
        ..blackLine()
        ..textLeftRight(
          _formatAmount(total),
          'جمع کل',
          style: const UrovoTextStyle(
            bold: true,
            font: UrovoFont.large,
            fontAsset: _persianFontAsset,
          ),
        )
        ..feedLine(4);

      await UrovoPos.printerRunJob(job);
      setState(() {
        _status = 'Persian table print done';
        _logs.insert(
          0,
          'persianPrint: OK @ ${DateTime.now().toIso8601String()}',
        );
      });
    });
  }

  String _formatAmount(int value) {
    final digits = value.toString();
    final buffer = StringBuffer();
    for (var index = 0; index < digits.length; index++) {
      if (index > 0 && (digits.length - index) % 3 == 0) {
        buffer.write('٬');
      }
      buffer.write(digits[index]);
    }
    return buffer.toString();
  }

  Future<void> _closePrinter() async {
    await _run('Closing printer...', () async {
      await UrovoPos.printerClose();
      setState(() {
        _status = 'Printer closed';
        _logs.insert(0, 'printerClose: OK');
      });
    });
  }

  Future<void> _scannerStart() async {
    await _run('Starting scanner...', () async {
      await UrovoPos.scannerStart(
        cameraId: 1,
        timeout: const Duration(seconds: 30),
      );
      setState(() {
        _status = 'Scanner started';
        _logs.insert(0, 'scannerStart: OK (cameraId=1, timeout=30s)');
      });
    });
  }

  Future<void> _scannerStop() async {
    await _run('Stopping scanner...', () async {
      await UrovoPos.scannerStop();
      setState(() {
        _status = 'Scanner stopped';
        _logs.insert(0, 'scannerStop: OK');
      });
    });
  }

  void _onScannerEvent(UrovoScannerEvent event) {
    if (!mounted) {
      return;
    }

    var shouldStopAfterDecode = false;
    setState(() {
      switch (event.type) {
        case UrovoScannerEventType.decoded:
          final data = event.result?.data ?? '';
          _status = 'Scanned: $data';
          _logs.insert(0, 'scan(decoded): $data');
          shouldStopAfterDecode = true;
          break;
        case UrovoScannerEventType.error:
          _status = 'Scanner error';
          _logs.insert(
            0,
            'scan(error): code=${event.errorCode} message=${event.message}',
          );
          break;
        case UrovoScannerEventType.timeout:
          _status = 'Scan timeout';
          _logs.insert(0, 'scan(timeout)');
          break;
        case UrovoScannerEventType.canceled:
          _status = 'Scan canceled';
          _logs.insert(0, 'scan(cancel)');
          break;
        case UrovoScannerEventType.unknown:
          _status = 'Unknown scan event';
          _logs.insert(0, 'scan(unknown)');
          break;
      }
    });

    if (!shouldStopAfterDecode) {
      return;
    }

    unawaited(
      Future<void>.microtask(() => UrovoPos.scannerStop()).catchError((
        Object error,
      ) {
        if (!mounted) {
          return;
        }
        setState(() {
          _logs.insert(0, '[WARN] scannerStop after decode failed: $error');
        });
      }),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Urovo POS Example')),
        body: Padding(
          padding: const EdgeInsets.all(24),
          child: ListView(
            children: <Widget>[
              Text(
                'Status: $_status',
                style: Theme.of(context).textTheme.titleMedium,
              ),
              const SizedBox(height: 16),
              Wrap(
                spacing: 12,
                runSpacing: 12,
                children: <Widget>[
                  ElevatedButton(
                    onPressed: _isBusy ? null : _checkSdk,
                    child: const Text('Check SDK'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _initPrinter,
                    child: const Text('Init Printer'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _readStatus,
                    child: const Text('Get Status'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _printSample,
                    child: const Text('Print Sample'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _printTextOnly,
                    child: const Text('Print Sample Text'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _printTableDemo,
                    child: const Text('Print Table Demo'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _printCustomDemo,
                    child: const Text('Print Demo Receipt'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _printCustomDemoPersian,
                    child: const Text('Print Persian Table'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _closePrinter,
                    child: const Text('Close Printer'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _scannerStart,
                    child: const Text('Start Scan'),
                  ),
                  ElevatedButton(
                    onPressed: _isBusy ? null : _scannerStop,
                    child: const Text('Stop Scan'),
                  ),
                ],
              ),
              const SizedBox(height: 24),
              const Text('Logs'),
              const SizedBox(height: 8),
              if (_logs.isEmpty)
                const Text('No logs yet.')
              else
                ..._logs.map(
                  (entry) => Padding(
                    padding: const EdgeInsets.only(bottom: 6),
                    child: Text(entry),
                  ),
                ),
              const SizedBox(height: 24),
              if (_isBusy) const Center(child: CircularProgressIndicator()),
              const SizedBox(height: 16),
              const Text(
                'AAR expected at: example/android/app/libs/urovoSDK-v1.0.13.aar',
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
160
points
172
downloads

Documentation

API reference

Publisher

verified publisherp-hatan.com

Weekly Downloads

Flutter plugin for Urovo POS (Android) with printer and scanner APIs, designed for modular feature expansion.

Repository (GitHub)
View/report issues

Topics

#pos #printer #scanner #urovo #android

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on urovo_pos

Packages that implement urovo_pos