From 5058f99fe0ae7c7f6a46fb8c7c2af60c6fa0fde5 Mon Sep 17 00:00:00 2001 From: Efril Date: Sun, 1 Mar 2026 19:37:23 +0700 Subject: [PATCH] update printer --- .../repositories/printer_repository.dart | 231 +++++++++++------- .../dialog/custom_modal_dialog.dart | 6 +- pubspec.lock | 2 +- pubspec.yaml | 1 + 4 files changed, 146 insertions(+), 94 deletions(-) diff --git a/lib/infrastructure/printer/repositories/printer_repository.dart b/lib/infrastructure/printer/repositories/printer_repository.dart index f055e29..c6504b8 100644 --- a/lib/infrastructure/printer/repositories/printer_repository.dart +++ b/lib/infrastructure/printer/repositories/printer_repository.dart @@ -5,6 +5,7 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter_esc_pos_network/flutter_esc_pos_network.dart'; import 'package:injectable/injectable.dart' hide Order; import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart'; +import 'package:synchronized/synchronized.dart'; import '../../../domain/order/order.dart'; import '../../../domain/outlet/outlet.dart'; @@ -28,6 +29,13 @@ class PrinterRepository implements IPrinterRepository { this._authLocalDataProvider, ); + final Map _locks = {}; + String? _connectedMac; + + Lock _getLock(String address) { + return _locks.putIfAbsent(address, () => Lock()); + } + @override Future> connectBluetooth( String macAddress, @@ -213,33 +221,38 @@ class PrinterRepository implements IPrinterRepository { Printer printer, List printData, ) async { - try { - log(printer.toString()); - if (printer.type == 'Bluetooth') { - final connected = await connectBluetooth(printer.address); + if (printer.type == 'Bluetooth') { + return await _getLock(printer.address).synchronized(() async { + try { + bool isConnected = await PrintBluetoothThermal.connectionStatus; - connected.fold( - (f) { - return left( - PrinterFailure.dynamicErrorMessage( - 'Printer cannot connect to bluetooth, Please connect in printer setting!', - ), + // Hanya reconnect jika memang perlu + if (!isConnected || _connectedMac != printer.address) { + // Disconnect hanya jika terhubung ke printer LAIN + if (isConnected && _connectedMac != printer.address) { + await PrintBluetoothThermal.disconnect; + await Future.delayed( + const Duration(milliseconds: 300), + ); // dari 1500ms + } + + bool connected = await PrintBluetoothThermal.connect( + macPrinterAddress: printer.address, ); - }, - (connect) async { - if (!connect) { + + if (!connected) { + _connectedMac = null; FirebaseCrashlytics.instance.recordError( 'Failed to connect to Bluetooth printer', null, reason: 'Failed to connect to Bluetooth print', information: [ - 'function: printStruct(Printer printer, List printValue,)', + 'function: printStruct(Printer printer, List printData)', 'Printer: ${printer.name}', 'macAddress: ${printer.address}', - 'in: $_logName ', + 'in: $_logName', ], ); - return left( PrinterFailure.dynamicErrorMessage( 'Printer cannot connect to bluetooth, Please connect in printer setting!', @@ -247,33 +260,59 @@ class PrinterRepository implements IPrinterRepository { ); } - log( - 'Printer connected to bluetooth: ${printer.name}, ${printer.address}', - name: _logName, + _connectedMac = printer.address; + await Future.delayed( + const Duration(milliseconds: 300), + ); // dari 1000ms + } + + log( + 'Printer connected to bluetooth: ${printer.name}, ${printer.address}', + name: _logName, + ); + + bool printResult = await _writeBytesChunked(printData); + + // Hapus delay 1000ms setelah print — tidak perlu untuk hasil cetak + log("Print result ${printer.name}: $printResult"); + + if (!printResult) { + FirebaseCrashlytics.instance.recordError( + 'Failed to print to ${printer.name}', + null, + information: [ + 'function: await _writeBytesChunked(printData)', + 'print: $printData', + 'in: $_logName', + ], ); - - bool printResult = await _printBluetooth(printData); - if (!printResult) { - FirebaseCrashlytics.instance.recordError( + return left( + PrinterFailure.dynamicErrorMessage( 'Failed to print to ${printer.name}', - null, - information: [ - 'function: await printBluetooth(printData);', - 'print: $printData', - 'in: $_logName', - ], - ); - return left( - PrinterFailure.dynamicErrorMessage( - 'Failed to print to ${printer.name}', - ), - ); - } + ), + ); + } - return right(printResult); - }, - ); - } else { + return right(printResult); + } catch (e, stackTrace) { + _connectedMac = null; + FirebaseCrashlytics.instance.recordError( + e, + stackTrace, + reason: 'Error printing ${printer.name}', + information: [ + 'Printer: ${printer.name}', + 'MAC: ${printer.address}', + ], + ); + return left( + PrinterFailure.dynamicErrorMessage('Error printing struct'), + ); + } + }); + } else { + // Network printer tetap sama + try { bool printResult = await _printNetwork(printer.address, printData); if (!printResult) { @@ -282,7 +321,7 @@ class PrinterRepository implements IPrinterRepository { null, reason: 'Failed to connect to Network Printer', information: [ - 'function: await printNetwork(printer.address, printData);', + 'function: await _printNetwork(printer.address, printData)', 'Printer: ${printer.name}', 'ipAddress: ${printer.address}', 'print: $printData', @@ -290,59 +329,64 @@ class PrinterRepository implements IPrinterRepository { ], ); } + return right(printResult); - } - - return right(false); - } catch (e) { - log("Error printing struct", name: _logName, error: e); - return left(PrinterFailure.dynamicErrorMessage('Error printing struct')); - } - } - - Future _printBluetooth(List printData) async { - try { - bool isConnected = await PrintBluetoothThermal.connectionStatus; - - if (!isConnected) { - log("Not connected to Bluetooth printer", name: _logName); - return false; - } - - bool printResult = await PrintBluetoothThermal.writeBytes(printData); - if (printResult) { - log("Successfully printed via Bluetooth", name: _logName); - } else { + } catch (e, stackTrace) { FirebaseCrashlytics.instance.recordError( - 'Failed to print via Bluetooth', - null, - reason: 'Failed to print via Bluetooth', - information: [ - 'function: printBluetooth(List printData)', - 'printData: $printData', - 'in: $_logName', - ], + e, + stackTrace, + reason: 'Error printing ${printer.name}', + information: ['Printer: ${printer.name}', 'IP: ${printer.address}'], + ); + return left( + PrinterFailure.dynamicErrorMessage('Error printing struct'), ); - log("Failed to print via Bluetooth", name: _logName); } - - return printResult; - } catch (e, stackTrace) { - FirebaseCrashlytics.instance.recordError( - e, - stackTrace, - reason: 'Error printing via Bluetooth', - information: [ - 'function: printBluetooth(List printData)', - 'Printer: Bluetooth printer', - 'printData: $printData', - 'in: $_logName', - ], - ); - log("Error printing via Bluetooth: $e", name: _logName); - return false; } } + // Future _printBluetooth(List printData) async { + // try { + // bool isConnected = await PrintBluetoothThermal.connectionStatus; + + // if (!isConnected) { + // log("Not connected to Bluetooth printer", name: _logName); + // return false; + // } + + // bool printResult = await PrintBluetoothThermal.writeBytes(printData); + // if (printResult) { + // log("Successfully printed via Bluetooth", name: _logName); + // } else { + // FirebaseCrashlytics.instance.recordError( + // 'Failed to print via Bluetooth', + // null, + // reason: 'Failed to print via Bluetooth', + // information: [ + // 'function: printBluetooth(List printData)', + // 'printData: $printData', + // 'in: $_logName', + // ], + // ); + // log("Failed to print via Bluetooth", name: _logName); + // } + + // return printResult; + // } catch (e, stackTrace) { + // FirebaseCrashlytics.instance.recordError( + // e, + // stackTrace, + // reason: 'Error printing via Bluetooth', + // information: [ + // 'function: printBluetooth(List printData)', + // 'Printer: Bluetooth printer', + // 'printData: $printData', + // 'in: $_logName', + // ], + // ); + // log("Error printing via Bluetooth: $e", name: _logName); + // return false; + // } + // } Future _printNetwork(String ipAddress, List printData) async { try { @@ -979,4 +1023,15 @@ class PrinterRepository implements IPrinterRepository { ); } } + + Future _writeBytesChunked(List data, {int chunkSize = 512}) async { + for (int i = 0; i < data.length; i += chunkSize) { + final end = (i + chunkSize > data.length) ? data.length : i + chunkSize; + final chunk = data.sublist(i, end); + bool result = await PrintBluetoothThermal.writeBytes(chunk); + if (!result) return false; + await Future.delayed(const Duration(milliseconds: 30)); + } + return true; + } } diff --git a/lib/presentation/components/dialog/custom_modal_dialog.dart b/lib/presentation/components/dialog/custom_modal_dialog.dart index 89d7f2f..80c88a6 100644 --- a/lib/presentation/components/dialog/custom_modal_dialog.dart +++ b/lib/presentation/components/dialog/custom_modal_dialog.dart @@ -46,11 +46,7 @@ class CustomModalDialog extends StatelessWidget { padding: const EdgeInsets.all(16), width: double.infinity, decoration: BoxDecoration( - gradient: LinearGradient( - colors: AppColor.primaryGradient, - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), + color: AppColor.primary, borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), child: Row( diff --git a/pubspec.lock b/pubspec.lock index 934ab5f..4818828 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1230,7 +1230,7 @@ packages: source: hosted version: "1.4.1" synchronized: - dependency: transitive + dependency: "direct main" description: name: synchronized sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 diff --git a/pubspec.yaml b/pubspec.yaml index 8ae724d..405320a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: flutter_esc_pos_network: ^1.0.3 esc_pos_utils_plus: ^2.0.4 table_calendar: ^3.1.2 + synchronized: ^3.4.0 dev_dependencies: flutter_test: