Files
app-grosir/lib/screens/printer_screen.dart
2026-07-23 22:12:32 +07:00

280 lines
9.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import '../services/printer_service.dart';
import '../utils/colors.dart';
class PrinterScreen extends StatefulWidget {
final bool embedded;
const PrinterScreen({super.key, this.embedded = false});
@override
State<PrinterScreen> createState() => _PrinterScreenState();
}
class _PrinterScreenState extends State<PrinterScreen> {
List<BluetoothInfo> _devices = [];
bool _loading = false;
bool _scanning = false;
bool _connecting = false;
@override
void initState() {
super.initState();
_loadDevices();
}
Future<void> _loadDevices() async {
setState(() => _loading = true);
try {
final enabled = await printerService.isBluetoothEnabled();
if (!enabled) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Bluetooth belum aktif. Nyalakan Bluetooth di HP.'),
backgroundColor: kDanger,
),
);
}
}
_devices = await printerService.getPairedDevices();
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal memuat printer: $e')),
);
}
} finally {
if (mounted) setState(() => _loading = false);
}
}
Future<void> _scan() async {
setState(() => _scanning = true);
try {
_devices = await printerService.getPairedDevices();
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal scan: $e')),
);
}
} finally {
if (mounted) setState(() => _scanning = false);
}
}
Future<void> _connect(BluetoothInfo device) async {
setState(() => _connecting = true);
final ok = await printerService.connect(device.macAdress);
if (mounted) {
setState(() => _connecting = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(ok
? 'Terhubung ke ${device.name}'
: 'Gagal hubungkan ${device.name}'),
backgroundColor: ok ? kSuccess : kDanger,
),
);
if (ok) setState(() {});
}
}
Future<void> _disconnect() async {
await printerService.disconnect();
if (mounted) setState(() {});
}
@override
Widget build(BuildContext context) {
final body = _buildBody(context);
if (widget.embedded) return body;
return Scaffold(
appBar: AppBar(
title: const Text('Printer Bluetooth'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: body,
),
);
}
Widget _buildBody(BuildContext context) {
final connected = printerService.isConnected;
final connectedMac = printerService.connectedMac;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.print_outlined, color: kAccent),
const SizedBox(width: 8),
Text(
'Printer Bluetooth',
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w700, color: kText),
),
],
),
const SizedBox(height: 12),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: connected
? kSuccess.withValues(alpha: 0.12)
: kSurface,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: connected ? kSuccess : kBorder,
),
),
child: Row(
children: [
Icon(
connected ? Icons.bluetooth_connected : Icons.bluetooth,
color: connected ? kSuccess : kMuted,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
connected ? 'Terhubung' : 'Tidak terhubung',
style: TextStyle(
fontWeight: FontWeight.w600,
color: connected ? kSuccess : kMuted,
),
),
if (connected && connectedMac != null)
Text(
connectedMac,
style: const TextStyle(
fontSize: 12, color: kMuted),
),
],
),
),
if (connected)
TextButton(
onPressed: _connecting ? null : _disconnect,
child: const Text('Putus'),
),
],
),
),
const SizedBox(height: 14),
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: _scanning ? null : _scan,
icon: _scanning
? const SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(
strokeWidth: 2, color: kAccent),
)
: const Icon(Icons.refresh),
label: Text(_scanning ? 'Scanning...' : 'Scan Ulang'),
),
),
],
),
],
),
),
),
const SizedBox(height: 12),
Text(
'Perangkat Tersedia',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w700, color: kText),
),
const SizedBox(height: 10),
if (_loading)
const Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 40),
child: CircularProgressIndicator(color: kAccent),
))
else if (_devices.isEmpty)
const Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 40),
child: Column(
children: [
Icon(Icons.print_disabled_outlined, size: 48, color: kMuted),
SizedBox(height: 8),
Text('Tidak ada printer terpasang',
style: TextStyle(color: kMuted)),
SizedBox(height: 4),
Text('Pasangkan printer di pengaturan Bluetooth HP',
style: TextStyle(color: kMuted, fontSize: 12)),
],
),
),
)
else
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _devices.length,
separatorBuilder: (_, __) => const SizedBox(height: 8),
itemBuilder: (context, i) {
final d = _devices[i];
final isThis = connected && connectedMac == d.macAdress;
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: isThis
? kSuccess.withValues(alpha: 0.15)
: kAccent.withValues(alpha: 0.15),
child: Icon(
isThis ? Icons.bluetooth_connected : Icons.print_outlined,
color: isThis ? kSuccess : kAccent,
),
),
title: Text(d.name.isNotEmpty ? d.name : 'Printer',
style: const TextStyle(fontWeight: FontWeight.w600)),
subtitle: Text(d.macAdress,
style: const TextStyle(fontSize: 12, color: kMuted)),
trailing: _connecting
? const SizedBox(
height: 18,
width: 18,
child: CircularProgressIndicator(
strokeWidth: 2, color: kAccent),
)
: isThis
? const Chip(
label: Text('Aktif',
style: TextStyle(fontSize: 11)),
backgroundColor: kSuccess,
labelPadding: EdgeInsets.zero,
)
: TextButton(
onPressed: () => _connect(d),
child: const Text('Hubungkan'),
),
),
);
},
),
],
);
}
}