diff --git a/lib/src/enums.dart b/lib/src/enums.dart index d8211ab..afbc691 100644 --- a/lib/src/enums.dart +++ b/lib/src/enums.dart @@ -15,6 +15,7 @@ class PosPrintResult { static const ticketEmpty = PosPrintResult._internal(4); static const printInProgress = PosPrintResult._internal(5); static const scanInProgress = PosPrintResult._internal(6); + static const error = PosPrintResult._internal(7); String get msg { if (value == PosPrintResult.success.value) { diff --git a/lib/src/printer_bluetooth_manager.dart b/lib/src/printer_bluetooth_manager.dart index b4ebc07..281bc43 100644 --- a/lib/src/printer_bluetooth_manager.dart +++ b/lib/src/printer_bluetooth_manager.dart @@ -63,83 +63,83 @@ class PrinterBluetoothManager { }); } - void stopScan() async { - await _bluetoothManager.stopScan(); + Future stopScan() async { + return _bluetoothManager.stopScan(); } void selectPrinter(PrinterBluetooth printer) { _selectedPrinter = printer; } - Future writeBytes( - List bytes, { - int chunkSizeBytes = 20, - int queueSleepTimeMs = 20, - }) async { - final Completer completer = Completer(); - - const int timeout = 5; + Future writeBytes(List bytes, + {int chunkSizeBytes = 20, + int queueSleepTimeMs = 20, + Duration timeout = const Duration(seconds: 5)}) async { if (_selectedPrinter == null) { - return Future.value(PosPrintResult.printerNotSelected); + return PosPrintResult.printerNotSelected; } else if (_isScanning.value!) { - return Future.value(PosPrintResult.scanInProgress); + return PosPrintResult.scanInProgress; } else if (_isPrinting) { - return Future.value(PosPrintResult.printInProgress); + return PosPrintResult.printInProgress; + } + + if (!_isConnected) { + // We have to rescan before connecting, otherwise we can connect only once + await _bluetoothManager.startScan(timeout: Duration(seconds: 1)); + await _bluetoothManager.stopScan(); + + // Connect + await _bluetoothManager.connect(_selectedPrinter!._device); + + if (await _bluetoothManager.state + .firstWhere((element) => element == BluetoothManager.CONNECTED) + .timeout(timeout, onTimeout: () { + return BluetoothManager.DISCONNECTED; + }) != + BluetoothManager.CONNECTED) { + _isConnected = false; + return PosPrintResult.timeout; + } + _isConnected = true; } + final len = bytes.length; + List> chunks = []; + for (var i = 0; i < len; i += chunkSizeBytes) { + var end = (i + chunkSizeBytes < len) ? i + chunkSizeBytes : len; + chunks.add(bytes.sublist(i, end)); + } + + List futures = []; + _isPrinting = true; - // We have to rescan before connecting, otherwise we can connect only once - await _bluetoothManager.startScan(timeout: Duration(seconds: 1)); - await _bluetoothManager.stopScan(); - - // Connect - await _bluetoothManager.connect(_selectedPrinter!._device); - - // Subscribe to the events - _bluetoothManager.state.listen((state) async { - switch (state) { - case BluetoothManager.CONNECTED: - // To avoid double call - if (!_isConnected) { - final len = bytes.length; - List> chunks = []; - for (var i = 0; i < len; i += chunkSizeBytes) { - var end = (i + chunkSizeBytes < len) ? i + chunkSizeBytes : len; - chunks.add(bytes.sublist(i, end)); - } - - for (var i = 0; i < chunks.length; i += 1) { - await _bluetoothManager.writeData(chunks[i]); - sleep(Duration(milliseconds: queueSleepTimeMs)); - } - - completer.complete(PosPrintResult.success); - } - // TODO sending disconnect signal should be event-based - _runDelayed(3).then((dynamic v) async { - await _bluetoothManager.disconnect(); - _isPrinting = false; - }); - _isConnected = true; - break; - case BluetoothManager.DISCONNECTED: - _isConnected = false; - break; - default: - break; - } - }); + for (var i = 0; i < chunks.length; i += 1) { + futures.add(_bluetoothManager.writeData(chunks[i])); + sleep(Duration(milliseconds: queueSleepTimeMs)); + } - // Printing timeout - _runDelayed(timeout).then((dynamic v) async { - if (_isPrinting) { - _isPrinting = false; - completer.complete(PosPrintResult.timeout); - } + await Future.delayed(timeout); + + return Future.wait(futures).then((_) async { + _isPrinting = false; + return PosPrintResult.success; + }).catchError((e) async { + _isPrinting = false; + _isConnected = false; + await _bluetoothManager.disconnect(); + return PosPrintResult.error; + }).timeout(timeout, onTimeout: () async { + _isPrinting = false; + _isConnected = false; + await _bluetoothManager.disconnect(); + return PosPrintResult.timeout; }); + } - return completer.future; + Future disconnect() async { + await _bluetoothManager.disconnect(); + _isConnected = false; } Future printTicket( diff --git a/pubspec.yaml b/pubspec.yaml index a50c402..bf6bfb7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,6 +2,7 @@ name: esc_pos_bluetooth description: The library allows to print receipts using an ESC/POS thermal Bluetooth printer. version: 0.4.1 homepage: https://github.com/andrey-ushakov/esc_pos_bluetooth +publish_to: none environment: sdk: ">=2.12.0 <3.0.0" @@ -9,11 +10,13 @@ environment: dependencies: flutter: sdk: flutter - rxdart: ^0.26.0 + rxdart: ^0.27.7 esc_pos_utils: ^1.1.0 # esc_pos_utils: # path: ../esc_pos_utils - flutter_bluetooth_basic: ^0.1.7 + flutter_bluetooth_basic: + git: + url: https://github.com/benlrichards/flutter_bluetooth_basic.git dev_dependencies: flutter_test: