apskel-pos-flutter/lib/presentation/setting/pages/manage_printer_page.dart
2025-08-01 18:27:40 +07:00

431 lines
13 KiB
Dart

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<ManagePrinterPage> createState() => _ManagePrinterPageState();
}
class _ManagePrinterPageState extends State<ManagePrinterPage> {
int selectedIndex = 0;
int? selectedSize;
// final List<PrinterModel> 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<BluetoothInfo> items = [];
final List<String> _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<String> options = ["58 mm", "80 mm"];
@override
void initState() {
super.initState();
initPlatformState();
loadData();
}
Future<void> 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<void> 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<BluetoothInfo> 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<void> 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<void> disconnect() async {
final bool status = await PrintBluetoothThermal.disconnect;
setState(() {
connected = false;
});
print("status disconnect $status");
}
Future<void> printTest() async {
bool conexionStatus = await PrintBluetoothThermal.connectionStatus;
//print("connection status: $conexionStatus");
if (conexionStatus) {
List<int> ticket = await testTicket();
final result = await PrintBluetoothThermal.writeBytes(ticket);
print("print test result: $result");
} else {
//no conectado, reconecte
}
}
Future<List<int>> testTicket() async {
List<int> 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('Apskel 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<void> 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<void> 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<void> 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<int>(
value: 58,
groupValue: selectedSize,
onChanged: (value) {
setState(() {
selectedSize = value;
});
},
),
const Text('58 mm'),
],
),
),
// Radio button untuk ukuran 80
Expanded(
child: Row(
children: [
Radio<int>(
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<BluetoothInfo> 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();
}
}