diff --git a/lib/src/universal_ble.dart b/lib/src/universal_ble.dart index 5ecf9ae..d11b942 100644 --- a/lib/src/universal_ble.dart +++ b/lib/src/universal_ble.dart @@ -70,9 +70,15 @@ class UniversalBle { } /// Connection stream of a device - Stream connectionStream(String deviceId) => + static Stream get scanStream => _platform.scanStream(); + + static Stream connectionStream(String deviceId) => _platform.connectionStream(deviceId); + static Stream characteristicStream( + String deviceId, String characteristicId) => + _platform.characteristicStream(deviceId, characteristicId); + /// Connect to a device. /// It is advised to stop scanning before connecting. /// It might throw errors if device is not connectable. diff --git a/lib/src/universal_ble_platform_interface.dart b/lib/src/universal_ble_platform_interface.dart index b539cd8..7398df9 100644 --- a/lib/src/universal_ble_platform_interface.dart +++ b/lib/src/universal_ble_platform_interface.dart @@ -4,9 +4,21 @@ import 'dart:typed_data'; import 'package:universal_ble/universal_ble.dart'; abstract class UniversalBlePlatform { - StreamController? _connectionStreamController; + StreamController? _scanStreamController; + StreamController<({String deviceId, bool isConnected})>? + _connectionStreamController; + StreamController< + ({String deviceId, String characteristicId, Uint8List value})>? + _characteristicStreamController; + final Map _pairStateMap = {}; + OnScanResult? onScanResult; + OnConnectionChange? onConnectionChange; + OnValueChange? onValueChange; + OnAvailabilityChange? onAvailabilityChange; + OnPairingStateChange? onPairingStateChange; + Future getBluetoothAvailabilityState(); Future enableBluetooth(); @@ -51,33 +63,49 @@ abstract class UniversalBlePlatform { Future getConnectionState(String deviceId); - Future> getSystemDevices( - List? withServices, - ); + Future> getSystemDevices(List? withServices); bool receivesAdvertisements(String deviceId) => true; - Stream connectionStream(String deviceId) { - _setupConnectionStreamIfRequired(); - return _connectionStreamController!.stream - .where((event) => event.deviceId == deviceId) - .map((event) => event.isConnected); - } + Stream scanStream() => _getScanStreamController().stream; + + Stream connectionStream(String deviceId) => + _getConnectionStreamController() + .stream + .where((event) => event.deviceId == deviceId) + .map((event) => event.isConnected); + + Stream characteristicStream( + String deviceId, String characteristicId) => + _getCharacteristicStreamController() + .stream + .where((event) => + event.deviceId == deviceId && + event.characteristicId == characteristicId) + .map((event) => event.value); void updateScanResult(BleDevice bleDevice) { onScanResult?.call(bleDevice); + _scanStreamController?.add(bleDevice); } void updateConnection(String deviceId, bool isConnected) { onConnectionChange?.call(deviceId, isConnected); - _connectionStreamController - ?.add((deviceId: deviceId, isConnected: isConnected)); + _connectionStreamController?.add(( + deviceId: deviceId, + isConnected: isConnected, + )); } void updateCharacteristicValue( String deviceId, String characteristicId, Uint8List value) { onValueChange?.call( deviceId, BleUuidParser.string(characteristicId), value); + _characteristicStreamController?.add(( + deviceId: deviceId, + characteristicId: BleUuidParser.string(characteristicId), + value: value, + )); } void updateAvailability(AvailabilityState state) { @@ -90,31 +118,52 @@ abstract class UniversalBlePlatform { onPairingStateChange?.call(deviceId, isPaired); } - // Do not use these directly to push updates - OnScanResult? onScanResult; - OnConnectionChange? onConnectionChange; - OnValueChange? onValueChange; - OnAvailabilityChange? onAvailabilityChange; - OnPairingStateChange? onPairingStateChange; - - static void logInfo(String message, {bool isError = false}) { - if (isError) message = '\x1B[31m$message\x1B[31m'; - log(message, name: 'UniversalBle'); + /// Setup autoDisposable StreamControllers + StreamController<({String deviceId, bool isConnected})> + _getConnectionStreamController() { + if (_connectionStreamController != null) { + _connectionStreamController = + StreamController<({String deviceId, bool isConnected})>.broadcast(); + _connectionStreamController?.onCancel = () { + _connectionStreamController?.close(); + _connectionStreamController = null; + }; + } + return _connectionStreamController!; } - /// Creates an auto disposable streamController - void _setupConnectionStreamIfRequired() { - if (_connectionStreamController != null) return; + StreamController< + ({String deviceId, String characteristicId, Uint8List value})> + _getCharacteristicStreamController() { + if (_characteristicStreamController == null) { + _characteristicStreamController = StreamController< + ({ + String deviceId, + String characteristicId, + Uint8List value + })>.broadcast(); + _characteristicStreamController?.onCancel = () { + _characteristicStreamController?.close(); + _characteristicStreamController = null; + }; + } + return _characteristicStreamController!; + } - _connectionStreamController = - StreamController<({String deviceId, bool isConnected})>.broadcast(); + StreamController _getScanStreamController() { + if (_scanStreamController == null) { + _scanStreamController = StreamController.broadcast(); + _scanStreamController?.onCancel = () { + _scanStreamController?.close(); + _scanStreamController = null; + }; + } + return _scanStreamController!; + } - // Auto dispose if no more subscribers - _connectionStreamController?.onCancel = () { - // logInfo('Disposing Connection Stream'); - _connectionStreamController?.close(); - _connectionStreamController = null; - }; + static void logInfo(String message, {bool isError = false}) { + if (isError) message = '\x1B[31m$message\x1B[31m'; + log(message, name: 'UniversalBle'); } }