import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart'; import 'package:intl/intl.dart'; /// Reusable component builder untuk thermal receipt printer class ReceiptComponentBuilder { final Generator generator; final int paperSize; ReceiptComponentBuilder({required this.generator, this.paperSize = 58}); /// Get separator line based on paper size String get _separator => paperSize == 80 ? '------------------------------------------------' : '--------------------------------'; /// Print text centered with custom style List textCenter( String text, { bool bold = false, PosTextSize height = PosTextSize.size1, PosTextSize width = PosTextSize.size1, }) { return generator.text( text, styles: PosStyles( bold: bold, align: PosAlign.center, height: height, width: width, ), ); } /// Print text aligned left List textLeft(String text, {bool bold = false}) { return generator.text( text, styles: PosStyles(bold: bold, align: PosAlign.left), ); } /// Print text aligned right List textRight(String text, {bool bold = false}) { return generator.text( text, styles: PosStyles(bold: bold, align: PosAlign.right), ); } /// Print separator line List separator({bool bold = false}) { return generator.text( _separator, styles: PosStyles(bold: bold, align: PosAlign.center), ); } /// Print row with 2 columns (label: value) List row2Columns( String leftText, String rightText, { bool bold = false, int leftWidth = 6, int rightWidth = 6, }) { return generator.row([ PosColumn( text: leftText, width: leftWidth, styles: PosStyles(align: PosAlign.left, bold: bold), ), PosColumn( text: rightText, width: rightWidth, styles: PosStyles(align: PosAlign.right, bold: bold), ), ]); } /// Print row with 3 columns List row3Columns( String leftText, String centerText, String rightText, { int leftWidth = 4, int centerWidth = 4, int rightWidth = 4, }) { return generator.row([ PosColumn( text: leftText, width: leftWidth, styles: const PosStyles(align: PosAlign.left), ), PosColumn( text: centerText, width: centerWidth, styles: const PosStyles(align: PosAlign.center), ), PosColumn( text: rightText, width: rightWidth, styles: const PosStyles(align: PosAlign.right), ), ]); } /// Print empty lines List emptyLines(int count) { return generator.emptyLines(count); } /// Print feed lines List feed(int count) { return generator.feed(count); } /// Print header (outlet info) List header({ required String outletName, required String address, required String phoneNumber, }) { List bytes = []; bytes += textCenter( outletName, bold: true, height: PosTextSize.size1, width: PosTextSize.size1, ); bytes += textCenter(address); bytes += textCenter(phoneNumber); bytes += separator(); return bytes; } List printerType({required String printerType}) { List bytes = []; bytes += textCenter( printerType, bold: true, height: PosTextSize.size1, width: PosTextSize.size1, ); return bytes; } /// Print date and time List dateTime(DateTime dateTime) { return row2Columns( DateFormat('dd MMM yyyy').format(dateTime), DateFormat('HH:mm').format(dateTime), ); } /// Print order info section List orderInfo({ required String orderNumber, required String customerName, required String cashierName, String? paymentMethod, String? tableNumber, }) { List bytes = []; bytes += row2Columns('No. Pesanan', orderNumber); bytes += row2Columns('Pelanggan', customerName); bytes += row2Columns('Kasir', cashierName); if (paymentMethod != null) { bytes += row2Columns( 'Pembayaran', paymentMethod, leftWidth: 8, rightWidth: 4, ); } if (tableNumber != null && tableNumber.isNotEmpty) { bytes += row2Columns('Meja', tableNumber, leftWidth: 8, rightWidth: 4); } return bytes; } /// Print order type (Dine In, Take Away, etc) List orderType(String type) { List bytes = []; bytes += separator(); bytes += textCenter(type, bold: true); bytes += separator(); return bytes; } /// Print single item List orderItem({ required String productName, required int quantity, required String unitPrice, required String totalPrice, String? variantName, String? notes, }) { List bytes = []; final variantText = variantName != null && variantName.isNotEmpty ? "($variantName)" : ''; bytes += textLeft('$productName $variantText', bold: true); bytes += row2Columns( '$quantity x $unitPrice', totalPrice, leftWidth: 8, rightWidth: 4, ); if (notes != null && notes.isNotEmpty) { bytes += row2Columns('Note', notes, leftWidth: 4, rightWidth: 8); } bytes += emptyLines(1); return bytes; } /// Print summary section List summary({ required int totalItems, required String subtotal, required String discount, required String total, required String paid, }) { List bytes = []; bytes += separator(); bytes += row2Columns('Total Item', totalItems.toString()); bytes += row2Columns('Subtotal', subtotal); bytes += row2Columns('Diskon', discount); bytes += separator(); bytes += row2Columns('Total', total, bold: true); bytes += row2Columns('Bayar', paid); bytes += separator(); return bytes; } /// Print footer (thank you message) List footer({String message = 'Terima kasih'}) { List bytes = []; bytes += emptyLines(2); bytes += textCenter( message, bold: true, height: PosTextSize.size1, width: PosTextSize.size1, ); bytes += feed(paperSize == 80 ? 3 : 1); bytes += generator.cut(); return bytes; } /// Print QR Code List qrCode(String data, {PosAlign align = PosAlign.center}) { return generator.qrcode(data, align: align); } /// Print barcode // List barcode(String data, {BarcodeType type = BarcodeType.code128}) { // return generator.barcode( // Barcode.code128(data), // ); // } }