import 'dart:async'; import 'package:logger/logger.dart'; import 'package:universal_ble/universal_ble.dart'; import 'package:uvok_epaper_badge/control/scanner_controller.dart'; import 'package:uvok_epaper_badge/control/scanner_controller_impl.dart'; import 'package:uvok_epaper_badge/model/device/universal_ble_device.dart'; Logger logger = Logger(); class UniversalBleScannerController extends ScannerControllerImpl { StreamSubscription? _subScan; StreamSubscription? _subAvail; final List _devices = []; UniversalBleScannerController() { // fuck this limitation, I want an instance method to be called, which doesn't // work in an initializer. _subScan = UniversalBle.scanStream.listen(_newDeviceAction); _subAvail = UniversalBle.availabilityStream.listen(_newAvailabilityAction); } void _newDeviceAction(BleDevice dev) { //logger.i("Found device: ${dev.toString()}"); bool added = _devices.addIf(dev, (exDev) => exDev.deviceId != dev.deviceId); if (added) { super.setDevices( _devices .map((d) => UniversalBleDevice.fromDevice(d)) .toList(growable: false), ); } } void _newAvailabilityAction(AvailabilityState event) { super.setAvailability( event == AvailabilityState.poweredOn ? ScanAvailability.available : ScanAvailability.unavailable, ); } @override Future startScan({ Duration timeout = const Duration(seconds: 5), }) async { AvailabilityState state = await UniversalBle.getBluetoothAvailabilityState(); if (state != AvailabilityState.poweredOn) return; _devices.clear(); super.setDevices([]); super.setStatus(ScanStatus.scanning); await UniversalBle.startScan(); await Future.delayed(timeout); await UniversalBle.stopScan(); super.setStatus(ScanStatus.finished); logger.i("Found ${_devices.length} devices"); } @override Future stopScan() async { await UniversalBle.stopScan(); } @override void dispose() { super.dispose(); stopScan().ignore(); _subScan?.cancel().ignore(); _subAvail?.cancel().ignore(); } } extension ListAddExt on List { /// An element if the predicate is true only for all elements. /// predicate is passed all existing elements. bool addIf(T dev, bool Function(T exDev) predicate) { if (every(predicate)) { add(dev); return true; } return false; } }