fix: atasi glitch exception another scan pada dialog bluetooth printer
This commit is contained in:
parent
59ddce0c37
commit
bbcb925463
|
|
@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:cashumit/models/receipt_item.dart';
|
import 'package:cashumit/models/receipt_item.dart';
|
||||||
import 'package:cashumit/screens/add_item_screen.dart';
|
import 'package:cashumit/screens/add_item_screen.dart';
|
||||||
import 'package:bluetooth_print/bluetooth_print.dart';
|
import 'package:bluetooth_print/bluetooth_print.dart';
|
||||||
import 'package:bluetooth_print/bluetooth_print_model.dart';
|
|
||||||
import 'package:cashumit/services/bluetooth_service.dart';
|
import 'package:cashumit/services/bluetooth_service.dart';
|
||||||
import 'package:cashumit/widgets/receipt_body.dart';
|
import 'package:cashumit/widgets/receipt_body.dart';
|
||||||
import 'package:cashumit/widgets/receipt_tear_effect.dart';
|
import 'package:cashumit/widgets/receipt_tear_effect.dart';
|
||||||
|
|
@ -16,6 +15,7 @@ import 'package:cashumit/models/group_submission_result.dart';
|
||||||
import 'package:cashumit/models/receipt_group.dart';
|
import 'package:cashumit/models/receipt_group.dart';
|
||||||
import 'package:cashumit/widgets/group_tags_dialog.dart';
|
import 'package:cashumit/widgets/group_tags_dialog.dart';
|
||||||
import 'package:cashumit/widgets/cashier_status_bar.dart';
|
import 'package:cashumit/widgets/cashier_status_bar.dart';
|
||||||
|
import 'package:cashumit/widgets/bluetooth_scan_dialog.dart';
|
||||||
import 'package:cashumit/services/local_receipt_service.dart';
|
import 'package:cashumit/services/local_receipt_service.dart';
|
||||||
|
|
||||||
import 'package:cashumit/services/account_dialog_service.dart';
|
import 'package:cashumit/services/account_dialog_service.dart';
|
||||||
|
|
@ -408,173 +408,21 @@ class _ReceiptScreenState extends State<ReceiptScreen> {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (dialogContext) {
|
builder: (dialogContext) => BluetoothScanDialog(
|
||||||
bool isScanning = true;
|
bluetoothService: _bluetoothService,
|
||||||
List<BluetoothDevice> scannedDevices = [];
|
onDeviceConnected: (device, ok) {
|
||||||
String? connectingAddress;
|
if (mounted) {
|
||||||
StreamSubscription<List<BluetoothDevice>>? scanSub;
|
setState(() {});
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
return StatefulBuilder(
|
SnackBar(
|
||||||
builder: (context, setDialogState) {
|
content: Text(ok
|
||||||
void startScan() async {
|
? 'Terhubung ke ${device.name ?? device.address}'
|
||||||
setDialogState(() {
|
: 'Gagal terhubung ke ${device.name ?? device.address}'),
|
||||||
isScanning = true;
|
|
||||||
scannedDevices.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
await _bluetoothService.startScan(
|
|
||||||
timeout: const Duration(seconds: 5));
|
|
||||||
scanSub?.cancel();
|
|
||||||
scanSub = _bluetoothService.scanResults.listen((devices) {
|
|
||||||
if (context.mounted) {
|
|
||||||
setDialogState(() {
|
|
||||||
scannedDevices = devices;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
if (context.mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(content: Text('Gagal memindai: $e')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future.delayed(const Duration(seconds: 5), () {
|
|
||||||
if (context.mounted) {
|
|
||||||
setDialogState(() {
|
|
||||||
isScanning = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mulai scan otomatis saat dialog pertama kali dibuka
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
if (scannedDevices.isEmpty && isScanning && scanSub == null) {
|
|
||||||
startScan();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return AlertDialog(
|
|
||||||
title: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.bluetooth_searching, color: Colors.blue),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
const Expanded(
|
|
||||||
child: Text('Pindai Printer Bluetooth',
|
|
||||||
style: TextStyle(fontSize: 16)),
|
|
||||||
),
|
|
||||||
if (isScanning)
|
|
||||||
const SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
content: SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
height: 320,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
if (isScanning)
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 6.0),
|
|
||||||
child: Text(
|
|
||||||
'Mencari printer thermal di sekitar...',
|
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: scannedDevices.isEmpty
|
|
||||||
? Center(
|
|
||||||
child: isScanning
|
|
||||||
? const Text('Sedang memindai perangkat...')
|
|
||||||
: const Text(
|
|
||||||
'Tidak ada perangkat Bluetooth ditemukan.\nPastikan Bluetooth & printer aktif.',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(color: Colors.grey),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: ListView.builder(
|
|
||||||
itemCount: scannedDevices.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final dev = scannedDevices[index];
|
|
||||||
final isConnectingThis =
|
|
||||||
connectingAddress == dev.address;
|
|
||||||
return Card(
|
|
||||||
margin:
|
|
||||||
const EdgeInsets.symmetric(vertical: 4),
|
|
||||||
child: ListTile(
|
|
||||||
leading: const Icon(Icons.print,
|
|
||||||
color: Colors.blue),
|
|
||||||
title: Text(dev.name ?? 'Perangkat Bluetooth',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.w600)),
|
|
||||||
subtitle: Text(dev.address ?? ''),
|
|
||||||
trailing: ElevatedButton(
|
|
||||||
onPressed: isConnectingThis
|
|
||||||
? null
|
|
||||||
: () async {
|
|
||||||
setDialogState(() {
|
|
||||||
connectingAddress = dev.address;
|
|
||||||
});
|
|
||||||
final ok = await _bluetoothService
|
|
||||||
.connectToDevice(dev);
|
|
||||||
if (context.mounted) {
|
|
||||||
scanSub?.cancel();
|
|
||||||
Navigator.pop(dialogContext);
|
|
||||||
}
|
|
||||||
if (mounted) setState(() {});
|
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
this.context)
|
|
||||||
.showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(ok
|
|
||||||
? 'Terhubung ke ${dev.name ?? dev.address}'
|
|
||||||
: 'Gagal terhubung ke ${dev.name ?? dev.address}'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: isConnectingThis
|
|
||||||
? const SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2),
|
|
||||||
)
|
|
||||||
: const Text('Hubungkan'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: isScanning ? null : () => startScan(),
|
|
||||||
child: const Text('Pindai Ulang'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
scanSub?.cancel();
|
|
||||||
_bluetoothService.stopScan();
|
|
||||||
Navigator.pop(dialogContext);
|
|
||||||
},
|
|
||||||
child: const Text('Tutup'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,29 @@ class BluetoothService {
|
||||||
BluetoothDevice? get connectedDevice => _connectedDevice;
|
BluetoothDevice? get connectedDevice => _connectedDevice;
|
||||||
BluetoothPrint get bluetoothPrint => _bluetoothPrint;
|
BluetoothPrint get bluetoothPrint => _bluetoothPrint;
|
||||||
Stream<List<BluetoothDevice>> get scanResults => _bluetoothPrint.scanResults;
|
Stream<List<BluetoothDevice>> get scanResults => _bluetoothPrint.scanResults;
|
||||||
|
Stream<bool> get isScanning => _bluetoothPrint.isScanning;
|
||||||
|
bool get isScanningNow => _bluetoothPrint.isScanningSync;
|
||||||
|
|
||||||
Future<void> startScan({Duration timeout = const Duration(seconds: 4)}) =>
|
Future<void> startScan({Duration timeout = const Duration(seconds: 4)}) async {
|
||||||
_bluetoothPrint.startScan(timeout: timeout);
|
try {
|
||||||
Future<void> stopScan() => _bluetoothPrint.stopScan();
|
if (_bluetoothPrint.isScanningSync) {
|
||||||
|
await _bluetoothPrint.stopScan();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 150));
|
||||||
|
}
|
||||||
|
await _bluetoothPrint.startScan(timeout: timeout);
|
||||||
|
} catch (e) {
|
||||||
|
try {
|
||||||
|
await _bluetoothPrint.stopScan();
|
||||||
|
} catch (_) {}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> stopScan() async {
|
||||||
|
try {
|
||||||
|
await _bluetoothPrint.stopScan();
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
/// Inisialisasi Bluetooth printer
|
/// Inisialisasi Bluetooth printer
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
|
|
@ -103,7 +122,7 @@ class BluetoothService {
|
||||||
/// Mencetak struk ke printer thermal
|
/// Mencetak struk ke printer thermal
|
||||||
Future<void> printReceipt(Uint8List data) async {
|
Future<void> printReceipt(Uint8List data) async {
|
||||||
if (!_isConnected) {
|
if (!_isConnected) {
|
||||||
throw SocketException('Printer tidak terhubung');
|
throw const SocketException('Printer tidak terhubung');
|
||||||
}
|
}
|
||||||
|
|
||||||
_isPrinting = true;
|
_isPrinting = true;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:bluetooth_print/bluetooth_print_model.dart';
|
||||||
|
import '../services/bluetooth_service.dart';
|
||||||
|
|
||||||
|
class BluetoothScanDialog extends StatefulWidget {
|
||||||
|
final BluetoothService bluetoothService;
|
||||||
|
final void Function(BluetoothDevice device, bool success)? onDeviceConnected;
|
||||||
|
|
||||||
|
const BluetoothScanDialog({
|
||||||
|
super.key,
|
||||||
|
required this.bluetoothService,
|
||||||
|
this.onDeviceConnected,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<BluetoothScanDialog> createState() => _BluetoothScanDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BluetoothScanDialogState extends State<BluetoothScanDialog> {
|
||||||
|
bool _isScanning = false;
|
||||||
|
List<BluetoothDevice> _scannedDevices = [];
|
||||||
|
String? _connectingAddress;
|
||||||
|
|
||||||
|
StreamSubscription<List<BluetoothDevice>>? _scanResultsSub;
|
||||||
|
StreamSubscription<bool>? _isScanningSub;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
// 1. Langsung berlangganan ke stream hasil scan agar perangkat yang ditemukan seketika tampil di UI
|
||||||
|
_scanResultsSub = widget.bluetoothService.scanResults.listen((devices) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_scannedDevices = devices;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Berlangganan ke stream status scan untuk sinkronisasi indikator loading
|
||||||
|
_isScanningSub = widget.bluetoothService.isScanning.listen((scanning) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isScanning = scanning;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. Mulai pemindaian perdana tepat 1 kali saat dialog dibuka
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (mounted) {
|
||||||
|
_startScan();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scanResultsSub?.cancel();
|
||||||
|
_isScanningSub?.cancel();
|
||||||
|
widget.bluetoothService.stopScan();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _startScan() async {
|
||||||
|
if (_connectingAddress != null) return;
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isScanning = true;
|
||||||
|
_scannedDevices.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await widget.bluetoothService.startScan(timeout: const Duration(seconds: 5));
|
||||||
|
} catch (e) {
|
||||||
|
if (mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Gagal memindai: $e')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _connect(BluetoothDevice device) async {
|
||||||
|
if (_connectingAddress != null) return;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_connectingAddress = device.address;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hentikan pemindaian terlebih dahulu sebelum menyambungkan ke BLE device
|
||||||
|
await widget.bluetoothService.stopScan();
|
||||||
|
|
||||||
|
final ok = await widget.bluetoothService.connectToDevice(device);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
widget.onDeviceConnected?.call(device, ok);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return PopScope(
|
||||||
|
canPop: true,
|
||||||
|
onPopInvokedWithResult: (didPop, _) {
|
||||||
|
if (didPop) {
|
||||||
|
widget.bluetoothService.stopScan();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: AlertDialog(
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.bluetooth_searching, color: Colors.blue),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
const Expanded(
|
||||||
|
child: Text(
|
||||||
|
'Pindai Printer Bluetooth',
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_isScanning)
|
||||||
|
const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
content: SizedBox(
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
height: 320,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (_isScanning)
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 6.0),
|
||||||
|
child: Text(
|
||||||
|
'Mencari printer thermal di sekitar...',
|
||||||
|
style: TextStyle(color: Colors.grey, fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: _scannedDevices.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: _isScanning
|
||||||
|
? const Text('Sedang memindai perangkat...')
|
||||||
|
: const Text(
|
||||||
|
'Tidak ada perangkat Bluetooth ditemukan.\nPastikan Bluetooth & printer aktif.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: _scannedDevices.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final dev = _scannedDevices[index];
|
||||||
|
final isConnectingThis = _connectingAddress == dev.address;
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: ListTile(
|
||||||
|
leading: const Icon(Icons.print, color: Colors.blue),
|
||||||
|
title: Text(
|
||||||
|
dev.name ?? 'Perangkat Bluetooth',
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
subtitle: Text(dev.address ?? ''),
|
||||||
|
trailing: ElevatedButton(
|
||||||
|
onPressed: (_connectingAddress != null)
|
||||||
|
? null
|
||||||
|
: () => _connect(dev),
|
||||||
|
child: isConnectingThis
|
||||||
|
? const SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
|
)
|
||||||
|
: const Text('Hubungkan'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: (_isScanning || _connectingAddress != null)
|
||||||
|
? null
|
||||||
|
: () => _startScan(),
|
||||||
|
child: const Text('Pindai Ulang'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Tutup'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,6 +41,7 @@ class BluetoothPrint {
|
||||||
BehaviorSubject<bool> _isScanning = BehaviorSubject.seeded(false);
|
BehaviorSubject<bool> _isScanning = BehaviorSubject.seeded(false);
|
||||||
|
|
||||||
Stream<bool> get isScanning => _isScanning.stream;
|
Stream<bool> get isScanning => _isScanning.stream;
|
||||||
|
bool get isScanningSync => _isScanning.value;
|
||||||
|
|
||||||
BehaviorSubject<List<BluetoothDevice>> _scanResults =
|
BehaviorSubject<List<BluetoothDevice>> _scanResults =
|
||||||
BehaviorSubject.seeded([]);
|
BehaviorSubject.seeded([]);
|
||||||
|
|
@ -62,7 +63,7 @@ class BluetoothPrint {
|
||||||
Duration? timeout,
|
Duration? timeout,
|
||||||
}) async* {
|
}) async* {
|
||||||
if (_isScanning.value == true) {
|
if (_isScanning.value == true) {
|
||||||
throw Exception('Another scan is already in progress.');
|
await stopScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit to isScanning
|
// Emit to isScanning
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.6.0+6
|
version: 1.6.1+7
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.3
|
sdk: ^3.5.3
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:cashumit/services/bluetooth_service.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group('BluetoothService Tests', () {
|
||||||
|
late BluetoothService bluetoothService;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
SharedPreferences.setMockInitialValues({});
|
||||||
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||||
|
.setMockMethodCallHandler(
|
||||||
|
const MethodChannel('bluetooth_print/methods'),
|
||||||
|
(MethodCall methodCall) async {
|
||||||
|
switch (methodCall.method) {
|
||||||
|
case 'state':
|
||||||
|
return 12; // STATE_ON
|
||||||
|
case 'startScan':
|
||||||
|
return null;
|
||||||
|
case 'stopScan':
|
||||||
|
return null;
|
||||||
|
case 'isConnected':
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
bluetoothService = BluetoothService();
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() {
|
||||||
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||||
|
.setMockMethodCallHandler(
|
||||||
|
const MethodChannel('bluetooth_print/methods'),
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('initial values and getters work properly', () {
|
||||||
|
expect(bluetoothService.isConnected, false);
|
||||||
|
expect(bluetoothService.isPrinting, false);
|
||||||
|
expect(bluetoothService.connectedDevice, isNull);
|
||||||
|
expect(bluetoothService.isScanningNow, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('stopScan executes gracefully', () async {
|
||||||
|
await bluetoothService.stopScan();
|
||||||
|
expect(bluetoothService.isScanningNow, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('reconnectIfNeeded returns false when no saved device', () async {
|
||||||
|
final result = await bluetoothService.reconnectIfNeeded();
|
||||||
|
expect(result, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue