import 'dart:async'; import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:aman_kassa_flutter/core/logger.dart'; import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart'; import 'package:aman_kassa_flutter/redux/store.dart'; import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart'; import 'package:esc_pos_utils/esc_pos_utils.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart' hide Image; import 'package:flutter/rendering.dart'; import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart'; import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; import 'PrinterTest.dart'; class PrinterSelectView extends StatefulWidget { PrinterSelectView({Key key, this.title}) : super(key: key); final String title; @override _PrinterSelectViewState createState() => _PrinterSelectViewState(); } class _PrinterSelectViewState extends State { PrinterBluetoothManager printerManager = PrinterBluetoothManager(); List _devices = []; Logger _logger = getLogger('PrinterSelectView'); @override void initState() { super.initState(); printerManager.scanResults.listen((devices) async { // print('UI: Devices found ${devices.length}'); setState(() { _devices = devices; }); }); _startScanDevices(); } void _startScanDevices() { setState(() { _devices = []; }); printerManager.startScan(Duration(seconds: 4)); } void _stopScanDevices() { printerManager.stopScan(); } Future demoReceipt(PaperSize paper) async { final Ticket ticket = Ticket(paper, ); // Print image // final ByteData data = await rootBundle.load('assets/images/aman_kassa_check.png'); // final Uint8List bytes = data.buffer.asUint8List(); // final Im.Image image = Im.decodeImage(bytes); // Im.Image thumbnail = Im.copyResize(image, width: 270); // ticket.image(thumbnail, align: PosAlign.center); //ticket.imageRaster(image, align: PosAlign.center); ticket.text('AMAN-SATU', styles: PosStyles( align: PosAlign.center, height: PosTextSize.size2, width: PosTextSize.size2, ), linesAfter: 1); ticket.text('889 Watson Lane', styles: PosStyles(align: PosAlign.center)); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, codeTable: PosCodeTable.westEur), containsChinese: true); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, fontType: PosFontType.fontA), containsChinese: true); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, fontType: PosFontType.fontB), containsChinese: true); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, height: PosTextSize.size1), containsChinese: true); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, width: PosTextSize.size2), containsChinese: true); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, width: PosTextSize.size3), containsChinese: true); ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, width: PosTextSize.size4), containsChinese: true); ticket.text('Tel: 830-221-1234', styles: PosStyles(align: PosAlign.center)); ticket.text('Web: www.example.com', styles: PosStyles(align: PosAlign.center), linesAfter: 1); ticket.hr(); ticket.row([ PosColumn(text: 'Qty', width: 1), PosColumn(text: 'Item', width: 7), PosColumn( text: 'Price', width: 2, styles: PosStyles(align: PosAlign.right)), PosColumn( text: 'Total', width: 2, styles: PosStyles(align: PosAlign.right)), ]); ticket.row([ PosColumn(text: '2', width: 1), PosColumn(text: 'ONION RINGS', width: 7), PosColumn( text: '0.99', width: 2, styles: PosStyles(align: PosAlign.right)), PosColumn( text: '1.98', width: 2, styles: PosStyles(align: PosAlign.right)), ]); ticket.row([ PosColumn(text: '1', width: 1), PosColumn(text: 'PIZZA', width: 7), PosColumn( text: '3.45', width: 2, styles: PosStyles(align: PosAlign.right)), PosColumn( text: '3.45', width: 2, styles: PosStyles(align: PosAlign.right)), ]); ticket.row([ PosColumn(text: '1', width: 1), PosColumn(text: 'SPRING ROLLS', width: 7), PosColumn( text: '2.99', width: 2, styles: PosStyles(align: PosAlign.right)), PosColumn( text: '2.99', width: 2, styles: PosStyles(align: PosAlign.right)), ]); ticket.row([ PosColumn(text: '3', width: 1), PosColumn(text: 'CRUNCHY STICKS', width: 7), PosColumn( text: '0.85', width: 2, styles: PosStyles(align: PosAlign.right)), PosColumn( text: '2.55', width: 2, styles: PosStyles(align: PosAlign.right)), ]); ticket.hr(); ticket.row([ PosColumn( text: 'TOTAL', width: 6, styles: PosStyles( height: PosTextSize.size2, width: PosTextSize.size2, )), PosColumn( text: '\$10.97', width: 6, styles: PosStyles( align: PosAlign.right, height: PosTextSize.size2, width: PosTextSize.size2, )), ]); ticket.hr(ch: '=', linesAfter: 1); ticket.row([ PosColumn( text: 'Cash', width: 7, styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), PosColumn( text: '\$15.00', width: 5, styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), ]); ticket.row([ PosColumn( text: 'Change', width: 7, styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), PosColumn( text: '\$4.03', width: 5, styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), ]); ticket.feed(2); ticket.text('Thank you!', styles: PosStyles(align: PosAlign.center, bold: true)); final now = DateTime.now(); final formatter = DateFormat('MM/dd/yyyy H:m'); final String timestamp = formatter.format(now); ticket.text(timestamp, styles: PosStyles(align: PosAlign.center), linesAfter: 2); // Print QR Code from image // try { // const String qrData = 'example.com'; // const double qrSize = 200; // final uiImg = await QrPainter( // data: qrData, // version: QrVersions.auto, // gapless: false, // ).toImageData(qrSize); // final dir = await getTemporaryDirectory(); // final pathName = '${dir.path}/qr_tmp.png'; // final qrFile = File(pathName); // final imgFile = await qrFile.writeAsBytes(uiImg.buffer.asUint8List()); // final img = decodeImage(imgFile.readAsBytesSync()); // ticket.image(img); // } catch (e) { // print(e); // } // Print QR Code using native function // ticket.qrcode('example.com'); ticket.feed(2); ticket.cut(); return ticket; } void _selectPrinter(PrinterBluetooth printer, BuildContext context, ) async { printerManager.selectPrinter(printer); _logger.i(printer.name); _logger.i(printer.address); BluetoothDevice device = new BluetoothDevice() ..address = printer.address ..name=printer.name ..type=printer.type; await Redux.store.dispatch(selectPrinterFromSetting(device)); Navigator.of(context).pop(false); } void _testPrint(PrinterBluetooth printer) async { printerManager.selectPrinter(printer); // TODO Don't forget to choose printer's paper const PaperSize paper = PaperSize.mm58; // TEST PRINT // final PosPrintResult res = // await printerManager.printTicket(await testTicket(paper), queueSleepTimeMs: 50); final PosPrintResult res = await printerManager.printTicket( await testTicketImage(paper), chunkSizeBytes: 1024, queueSleepTimeMs: 50 ); // DEMO RECEIPT // final PosPrintResult res = // await printerManager.printTicket(await demoReceipt(paper) , queueSleepTimeMs: 50); } final key = GlobalKey(); @override Widget build(BuildContext context) { return RepaintBoundary( key: key, child: Scaffold( appBar: AppBar( title: Text('Выберите принтер'), ), body: ListView.builder( itemCount: _devices.length, itemBuilder: (BuildContext _, int index) { return InkWell( onTap: () => _selectPrinter(_devices[index], context), child: Column( children: [ Container( height: 60, padding: EdgeInsets.only(left: 10), alignment: Alignment.centerLeft, child: Row( children: [ Icon(Icons.print), SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text(_devices[index].name ?? ''), Text(_devices[index].address), Text( 'Click to print a test receipt', style: TextStyle(color: Colors.grey[700]), ), ], ), ) ], ), ), Divider(), ], ), ); }), floatingActionButton: StreamBuilder( stream: printerManager.isScanningStream, initialData: false, builder: (c, snapshot) { if (snapshot.data) { return FloatingActionButton( child: Icon(Icons.stop), onPressed: _stopScanDevices, backgroundColor: Colors.red, ); } else { return FloatingActionButton( child: Icon(Icons.search), onPressed: _startScanDevices, ); } }, ), ), ); } }