update printer

This commit is contained in:
Efril 2026-03-01 19:37:23 +07:00
parent f7cafeb583
commit 5058f99fe0
4 changed files with 146 additions and 94 deletions

View File

@ -5,6 +5,7 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter_esc_pos_network/flutter_esc_pos_network.dart'; import 'package:flutter_esc_pos_network/flutter_esc_pos_network.dart';
import 'package:injectable/injectable.dart' hide Order; import 'package:injectable/injectable.dart' hide Order;
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart'; import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import 'package:synchronized/synchronized.dart';
import '../../../domain/order/order.dart'; import '../../../domain/order/order.dart';
import '../../../domain/outlet/outlet.dart'; import '../../../domain/outlet/outlet.dart';
@ -28,6 +29,13 @@ class PrinterRepository implements IPrinterRepository {
this._authLocalDataProvider, this._authLocalDataProvider,
); );
final Map<String, Lock> _locks = {};
String? _connectedMac;
Lock _getLock(String address) {
return _locks.putIfAbsent(address, () => Lock());
}
@override @override
Future<Either<PrinterFailure, bool>> connectBluetooth( Future<Either<PrinterFailure, bool>> connectBluetooth(
String macAddress, String macAddress,
@ -213,33 +221,38 @@ class PrinterRepository implements IPrinterRepository {
Printer printer, Printer printer,
List<int> printData, List<int> printData,
) async { ) async {
try {
log(printer.toString());
if (printer.type == 'Bluetooth') { if (printer.type == 'Bluetooth') {
final connected = await connectBluetooth(printer.address); return await _getLock(printer.address).synchronized(() async {
try {
bool isConnected = await PrintBluetoothThermal.connectionStatus;
connected.fold( // Hanya reconnect jika memang perlu
(f) { if (!isConnected || _connectedMac != printer.address) {
return left( // Disconnect hanya jika terhubung ke printer LAIN
PrinterFailure.dynamicErrorMessage( if (isConnected && _connectedMac != printer.address) {
'Printer cannot connect to bluetooth, Please connect in printer setting!', await PrintBluetoothThermal.disconnect;
), await Future.delayed(
const Duration(milliseconds: 300),
); // dari 1500ms
}
bool connected = await PrintBluetoothThermal.connect(
macPrinterAddress: printer.address,
); );
},
(connect) async { if (!connected) {
if (!connect) { _connectedMac = null;
FirebaseCrashlytics.instance.recordError( FirebaseCrashlytics.instance.recordError(
'Failed to connect to Bluetooth printer', 'Failed to connect to Bluetooth printer',
null, null,
reason: 'Failed to connect to Bluetooth print', reason: 'Failed to connect to Bluetooth print',
information: [ information: [
'function: printStruct(Printer printer, List<int> printValue,)', 'function: printStruct(Printer printer, List<int> printData)',
'Printer: ${printer.name}', 'Printer: ${printer.name}',
'macAddress: ${printer.address}', 'macAddress: ${printer.address}',
'in: $_logName', 'in: $_logName',
], ],
); );
return left( return left(
PrinterFailure.dynamicErrorMessage( PrinterFailure.dynamicErrorMessage(
'Printer cannot connect to bluetooth, Please connect in printer setting!', 'Printer cannot connect to bluetooth, Please connect in printer setting!',
@ -247,18 +260,28 @@ class PrinterRepository implements IPrinterRepository {
); );
} }
_connectedMac = printer.address;
await Future.delayed(
const Duration(milliseconds: 300),
); // dari 1000ms
}
log( log(
'Printer connected to bluetooth: ${printer.name}, ${printer.address}', 'Printer connected to bluetooth: ${printer.name}, ${printer.address}',
name: _logName, name: _logName,
); );
bool printResult = await _printBluetooth(printData); bool printResult = await _writeBytesChunked(printData);
// Hapus delay 1000ms setelah print tidak perlu untuk hasil cetak
log("Print result ${printer.name}: $printResult");
if (!printResult) { if (!printResult) {
FirebaseCrashlytics.instance.recordError( FirebaseCrashlytics.instance.recordError(
'Failed to print to ${printer.name}', 'Failed to print to ${printer.name}',
null, null,
information: [ information: [
'function: await printBluetooth(printData);', 'function: await _writeBytesChunked(printData)',
'print: $printData', 'print: $printData',
'in: $_logName', 'in: $_logName',
], ],
@ -271,9 +294,25 @@ class PrinterRepository implements IPrinterRepository {
} }
return right(printResult); 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 { } else {
// Network printer tetap sama
try {
bool printResult = await _printNetwork(printer.address, printData); bool printResult = await _printNetwork(printer.address, printData);
if (!printResult) { if (!printResult) {
@ -282,7 +321,7 @@ class PrinterRepository implements IPrinterRepository {
null, null,
reason: 'Failed to connect to Network Printer', reason: 'Failed to connect to Network Printer',
information: [ information: [
'function: await printNetwork(printer.address, printData);', 'function: await _printNetwork(printer.address, printData)',
'Printer: ${printer.name}', 'Printer: ${printer.name}',
'ipAddress: ${printer.address}', 'ipAddress: ${printer.address}',
'print: $printData', 'print: $printData',
@ -290,59 +329,64 @@ class PrinterRepository implements IPrinterRepository {
], ],
); );
} }
return right(printResult); return right(printResult);
}
return right(false);
} catch (e) {
log("Error printing struct", name: _logName, error: e);
return left(PrinterFailure.dynamicErrorMessage('Error printing struct'));
}
}
Future<bool> _printBluetooth(List<int> 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<int> printData)',
'printData: $printData',
'in: $_logName',
],
);
log("Failed to print via Bluetooth", name: _logName);
}
return printResult;
} catch (e, stackTrace) { } catch (e, stackTrace) {
FirebaseCrashlytics.instance.recordError( FirebaseCrashlytics.instance.recordError(
e, e,
stackTrace, stackTrace,
reason: 'Error printing via Bluetooth', reason: 'Error printing ${printer.name}',
information: [ information: ['Printer: ${printer.name}', 'IP: ${printer.address}'],
'function: printBluetooth(List<int> printData)', );
'Printer: Bluetooth printer', return left(
'printData: $printData', PrinterFailure.dynamicErrorMessage('Error printing struct'),
'in: $_logName',
],
); );
log("Error printing via Bluetooth: $e", name: _logName);
return false;
} }
} }
}
// Future<bool> _printBluetooth(List<int> 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<int> 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<int> printData)',
// 'Printer: Bluetooth printer',
// 'printData: $printData',
// 'in: $_logName',
// ],
// );
// log("Error printing via Bluetooth: $e", name: _logName);
// return false;
// }
// }
Future<bool> _printNetwork(String ipAddress, List<int> printData) async { Future<bool> _printNetwork(String ipAddress, List<int> printData) async {
try { try {
@ -979,4 +1023,15 @@ class PrinterRepository implements IPrinterRepository {
); );
} }
} }
Future<bool> _writeBytesChunked(List<int> 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;
}
} }

View File

@ -46,11 +46,7 @@ class CustomModalDialog extends StatelessWidget {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( color: AppColor.primary,
colors: AppColor.primaryGradient,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.vertical(top: Radius.circular(16)), borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
), ),
child: Row( child: Row(

View File

@ -1230,7 +1230,7 @@ packages:
source: hosted source: hosted
version: "1.4.1" version: "1.4.1"
synchronized: synchronized:
dependency: transitive dependency: "direct main"
description: description:
name: synchronized name: synchronized
sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0

View File

@ -43,6 +43,7 @@ dependencies:
flutter_esc_pos_network: ^1.0.3 flutter_esc_pos_network: ^1.0.3
esc_pos_utils_plus: ^2.0.4 esc_pos_utils_plus: ^2.0.4
table_calendar: ^3.1.2 table_calendar: ^3.1.2
synchronized: ^3.4.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: