import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:enaklo_pos/core/components/components.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart'; import '../../../core/constants/colors.dart'; import '../widgets/menu_printer_button.dart'; import '../widgets/menu_printer_content.dart'; class ManagePrinterPage extends StatefulWidget { const ManagePrinterPage({super.key}); @override State createState() => _ManagePrinterPageState(); } class _ManagePrinterPageState extends State { int selectedIndex = 0; int? selectedSize; // final List datas = [ // PrinterModel( // name: 'Galaxy A30', // address: 12324567412, // ), // PrinterModel( // name: 'Galaxy A30', // address: 12324567412, // ), // PrinterModel( // name: 'Galaxy A30', // address: 12324567412, // ), // ]; String macName = ''; String _info = ""; String _msj = ''; bool connected = false; List items = []; final List _options = [ "permission bluetooth granted", "bluetooth enabled", "connection status", "update info" ]; final String _selectSize = "2"; final _txtText = TextEditingController(text: "Hello developer"); bool _progress = false; String _msjprogress = ""; String optionprinttype = "58 mm"; List options = ["58 mm", "80 mm"]; @override void initState() { super.initState(); initPlatformState(); loadData(); } Future initPlatformState() async { String platformVersion; int porcentbatery = 0; // Platform messages may fail, so we use a try/catch PlatformException. try { platformVersion = await PrintBluetoothThermal.platformVersion; print("patformversion: $platformVersion"); porcentbatery = await PrintBluetoothThermal.batteryLevel; } on PlatformException { platformVersion = 'Failed to get platform version.'; } // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. if (!mounted) return; final bool result = await PrintBluetoothThermal.bluetoothEnabled; print("bluetooth enabled: $result"); if (result) { _msj = "Bluetooth enabled, please search and connect"; } else { _msj = "Bluetooth not enabled"; } setState(() { _info = "$platformVersion ($porcentbatery% battery)"; }); } Future getBluetoots() async { setState(() { _progress = true; _msjprogress = "Wait"; items = []; }); var status2 = await Permission.bluetoothScan.status; if (status2.isDenied) { await Permission.bluetoothScan.request(); } var status = await Permission.bluetoothConnect.status; if (status.isDenied) { await Permission.bluetoothConnect.request(); } final List listResult = await PrintBluetoothThermal.pairedBluetooths; setState(() { _progress = false; }); if (listResult.isEmpty) { _msj = "There are no bluetoohs linked, go to settings and link the printer"; } else { _msj = "Touch an item in the list to connect"; } setState(() { items = listResult; }); } Future connect(String mac) async { setState(() { _progress = true; _msjprogress = "Connecting..."; connected = false; }); final bool result = await PrintBluetoothThermal.connect(macPrinterAddress: mac); print("state conected $result"); if (result) connected = true; setState(() { _progress = false; }); } Future disconnect() async { final bool status = await PrintBluetoothThermal.disconnect; setState(() { connected = false; }); print("status disconnect $status"); } Future printTest() async { bool conexionStatus = await PrintBluetoothThermal.connectionStatus; //print("connection status: $conexionStatus"); if (conexionStatus) { List ticket = await testTicket(); final result = await PrintBluetoothThermal.writeBytes(ticket); print("print test result: $result"); } else { //no conectado, reconecte } } Future> testTicket() async { List bytes = []; // Using default profile final profile = await CapabilityProfile.load(); final generator = Generator( optionprinttype == "58 mm" ? PaperSize.mm58 : PaperSize.mm80, profile); //bytes += generator.setGlobalFont(PosFontType.fontA); bytes += generator.reset(); bytes += generator.text('Enaklo POS', styles: const PosStyles(bold: true)); bytes += generator.text('Reverse text', styles: const PosStyles(reverse: true)); bytes += generator.text('Underlined text', styles: const PosStyles(underline: true), linesAfter: 1); bytes += generator.text('Align left', styles: const PosStyles(align: PosAlign.left)); bytes += generator.text('Align center', styles: const PosStyles(align: PosAlign.center)); bytes += generator.text('Align right', styles: const PosStyles(align: PosAlign.right), linesAfter: 1); bytes += generator.text( 'FIC Batch 11', styles: const PosStyles( height: PosTextSize.size2, width: PosTextSize.size2, ), ); bytes += generator.feed(2); //bytes += generator.cut(); return bytes; } Future printWithoutPackage() async { //impresion sin paquete solo de PrintBluetoothTermal bool connectionStatus = await PrintBluetoothThermal.connectionStatus; if (connectionStatus) { String text = "${_txtText.text}\n"; bool result = await PrintBluetoothThermal.writeString( printText: PrintTextSize(size: int.parse(_selectSize), text: text)); print("status print result: $result"); setState(() { _msj = "printed status: $result"; }); } else { //no conectado, reconecte setState(() { _msj = "no connected device"; }); print("no conectado"); } } Future printString() async { bool conexionStatus = await PrintBluetoothThermal.connectionStatus; if (conexionStatus) { String enter = '\n'; await PrintBluetoothThermal.writeBytes(enter.codeUnits); //size of 1-5 String text = "Hello"; await PrintBluetoothThermal.writeString( printText: PrintTextSize(size: 1, text: text)); await PrintBluetoothThermal.writeString( printText: PrintTextSize(size: 2, text: "$text size 2")); await PrintBluetoothThermal.writeString( printText: PrintTextSize(size: 3, text: "$text size 3")); } else { //desconectado print("desconectado bluetooth $conexionStatus"); } } Future loadData() async { final savedSize = await AuthLocalDataSource().getSizeReceipt(); if (savedSize.isNotEmpty) { setState(() { selectedSize = int.parse(savedSize); }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Kelola Printer'), centerTitle: true, ), bottomNavigationBar: SizedBox( height: 60, child: Button.filled( onPressed: () async { // Periksa apakah ukuran dan printer telah dipilih if (selectedSize != null && macName.isNotEmpty) { // Simpan ukuran dan alamat MAC printer AuthLocalDataSource().saveSizeReceipt(selectedSize.toString()); await connect(macName); // Tampilkan pesan berhasil ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Pengaturan berhasil disimpan')), ); } else { // Tampilkan pesan error jika belum dipilih ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Pilih ukuran dan printer terlebih dahulu')), ); } }, label: 'Simpan'), ), body: ListView( padding: const EdgeInsets.all(24.0), children: [ Text( "Pilih Ukuran", style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.bold, color: AppColors.primary), ), SpaceHeight(16), Container( width: context.deviceWidth / 2, padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(8), ), child: Row( children: [ // Radio button untuk ukuran 58 Expanded( child: Row( children: [ Radio( value: 58, groupValue: selectedSize, onChanged: (value) { setState(() { selectedSize = value; }); }, ), const Text('58 mm'), ], ), ), // Radio button untuk ukuran 80 Expanded( child: Row( children: [ Radio( value: 80, groupValue: selectedSize, onChanged: (value) { setState(() { selectedSize = value; }); }, ), const Text('80 mm'), ], ), ), ], ), ), SpaceHeight(24), Text( "Pilih Printer", style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.bold, color: AppColors.primary), ), SpaceHeight(16), Container( width: context.deviceWidth / 2, padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ MenuPrinterButton( label: 'Search', onPressed: () { getBluetoots(); selectedIndex = 0; setState(() {}); }, isActive: selectedIndex == 0, ), ], ), ), const SpaceHeight(34.0), _Body( // selectedIndex: selectedIndex, macName: macName, datas: items, clickHandler: (mac) async { macName = mac; setState(() {}); }, ), SpaceHeight(24), ], ), ); } } class _Body extends StatelessWidget { // final int selectedIndex; final String macName; final List datas; //clickHandler final Function(String) clickHandler; const _Body({ required this.macName, required this.datas, required this.clickHandler, }); @override Widget build(BuildContext context) { if (datas.isEmpty) { return const Text('No data available'); } else { return Container( padding: const EdgeInsets.all(24.0), decoration: BoxDecoration( color: Colors.white, border: Border.all(color: AppColors.card, width: 2), borderRadius: BorderRadius.circular(6), ), child: ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: datas.length, separatorBuilder: (context, index) => const SpaceHeight(16.0), itemBuilder: (context, index) => InkWell( onTap: () { clickHandler(datas[index].macAdress); }, child: MenuPrinterContent( isSelected: macName == datas[index].macAdress, data: datas[index], ), ), ), ); } // return const Placeholder(); } }