164 lines
4.5 KiB
Dart
164 lines
4.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/services.dart';
|
|
import 'package:rxdart/rxdart.dart';
|
|
|
|
import 'bluetooth_print_model.dart';
|
|
|
|
class BluetoothPrint {
|
|
static const String namespace = 'bluetooth_print';
|
|
static const int connected = 1;
|
|
static const int disconnected = 0;
|
|
|
|
static const MethodChannel _channel =
|
|
MethodChannel('$namespace/methods');
|
|
static const EventChannel _stateChannel =
|
|
EventChannel('$namespace/state');
|
|
|
|
Stream<MethodCall> get _methodStream => _methodStreamController.stream;
|
|
final StreamController<MethodCall> _methodStreamController =
|
|
StreamController.broadcast();
|
|
|
|
BluetoothPrint._() {
|
|
_channel.setMethodCallHandler((MethodCall call) async {
|
|
_methodStreamController.add(call);
|
|
});
|
|
}
|
|
|
|
static BluetoothPrint _instance = new BluetoothPrint._();
|
|
|
|
static BluetoothPrint get instance => _instance;
|
|
|
|
Future<bool> get isAvailable async =>
|
|
await _channel.invokeMethod('isAvailable').then<bool>((d) => d);
|
|
|
|
Future<bool> get isOn async =>
|
|
await _channel.invokeMethod('isOn').then<bool>((d) => d);
|
|
|
|
Future<bool?> get isConnected async =>
|
|
await _channel.invokeMethod('isConnected');
|
|
|
|
BehaviorSubject<bool> _isScanning = BehaviorSubject.seeded(false);
|
|
|
|
Stream<bool> get isScanning => _isScanning.stream;
|
|
|
|
BehaviorSubject<List<BluetoothDevice>> _scanResults =
|
|
BehaviorSubject.seeded([]);
|
|
|
|
Stream<List<BluetoothDevice>> get scanResults => _scanResults.stream;
|
|
|
|
PublishSubject _stopScanPill = new PublishSubject();
|
|
|
|
/// Gets the current state of the Bluetooth module
|
|
Stream<int> get state async* {
|
|
yield await _channel.invokeMethod('state').then((s) => s);
|
|
|
|
yield* _stateChannel.receiveBroadcastStream().map((s) => s);
|
|
}
|
|
|
|
/// Starts a scan for Bluetooth Low Energy devices
|
|
/// Timeout closes the stream after a specified [Duration]
|
|
Stream<BluetoothDevice> scan({
|
|
Duration? timeout,
|
|
}) async* {
|
|
if (_isScanning.value == true) {
|
|
throw Exception('Another scan is already in progress.');
|
|
}
|
|
|
|
// Emit to isScanning
|
|
_isScanning.add(true);
|
|
|
|
final killStreams = <Stream>[];
|
|
killStreams.add(_stopScanPill);
|
|
if (timeout != null) {
|
|
killStreams.add(Rx.timer(null, timeout));
|
|
}
|
|
|
|
// Clear scan results list
|
|
_scanResults.add(<BluetoothDevice>[]);
|
|
|
|
try {
|
|
await _channel.invokeMethod('startScan');
|
|
} catch (e) {
|
|
print('Error starting scan.');
|
|
_stopScanPill.add(null);
|
|
_isScanning.add(false);
|
|
throw e;
|
|
}
|
|
|
|
yield* BluetoothPrint.instance._methodStream
|
|
.where((m) => m.method == "ScanResult")
|
|
.map((m) => m.arguments)
|
|
.takeUntil(Rx.merge(killStreams))
|
|
.doOnDone(stopScan)
|
|
.map((map) {
|
|
final device = BluetoothDevice.fromJson(Map<String, dynamic>.from(map));
|
|
final List<BluetoothDevice> list = _scanResults.value;
|
|
int newIndex = -1;
|
|
list.asMap().forEach((index, e) {
|
|
if (e.address == device.address) {
|
|
newIndex = index;
|
|
}
|
|
});
|
|
|
|
if (newIndex != -1) {
|
|
list[newIndex] = device;
|
|
} else {
|
|
list.add(device);
|
|
}
|
|
_scanResults.add(list);
|
|
return device;
|
|
});
|
|
}
|
|
|
|
Future startScan({
|
|
Duration? timeout,
|
|
}) async {
|
|
await scan(timeout: timeout).drain();
|
|
return _scanResults.value;
|
|
}
|
|
|
|
/// Stops a scan for Bluetooth Low Energy devices
|
|
Future stopScan() async {
|
|
await _channel.invokeMethod('stopScan');
|
|
_stopScanPill.add(null);
|
|
_isScanning.add(false);
|
|
}
|
|
|
|
Future<dynamic> connect(BluetoothDevice device) =>
|
|
_channel.invokeMethod('connect', device.toJson());
|
|
|
|
Future<dynamic> disconnect() => _channel.invokeMethod('disconnect');
|
|
|
|
Future<dynamic> destroy() => _channel.invokeMethod('destroy');
|
|
|
|
Future<dynamic> printReceipt(
|
|
Map<String, dynamic> config, List<LineText> data) {
|
|
Map<String, Object> args = {};
|
|
args['config'] = config;
|
|
args['data'] = data.map((m) {
|
|
return m.toJson();
|
|
}).toList();
|
|
|
|
_channel.invokeMethod('printReceipt', args);
|
|
return Future.value(true);
|
|
}
|
|
|
|
Future<dynamic> printLabel(Map<String, dynamic> config, List<LineText> data) {
|
|
Map<String, Object> args = {};
|
|
args['config'] = config;
|
|
args['data'] = data.map((m) {
|
|
return m.toJson();
|
|
}).toList();
|
|
|
|
_channel.invokeMethod('printLabel', args);
|
|
return Future.value(true);
|
|
}
|
|
|
|
Future<dynamic> printTest() => _channel.invokeMethod('printTest');
|
|
|
|
Future<dynamic> printRawData(Uint8List data) {
|
|
return _channel.invokeMethod('printRawData', {'data': data});
|
|
}
|
|
}
|