import 'dart:async'; import 'package:uvok_epaper_badge/control/scanner_controller_impl.dart'; import 'package:uvok_epaper_badge/model/device/flutter_blue_plus_device.dart'; import 'package:uvok_epaper_badge/model/device/device.dart'; import 'package:uvok_epaper_badge/control/scanner_controller.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:logger/logger.dart'; var logger = Logger(); class FlutterBluePlusScannerController extends ScannerControllerImpl { @override Future startScan({ Duration timeout = const Duration(seconds: 5), }) async { stopScan(); var system = await FlutterBluePlus.systemDevices([]); for (var d in system) { logger.i('${d.platformName} already connected to! ${d.remoteId}'); } super.setStatus(ScanStatus.scanning); var subscription = FlutterBluePlus.scanResults.listen( (results) { List devices = results .map((d) => FlutterBluePlusDevice.fromScan(d)) .toList(); super.setDevices(devices); }, onError: (err) { logger.e(err); super.setStatus(ScanStatus.error); }, ); // either this, or the cancel in the finally block, should do the same? FlutterBluePlus.cancelWhenScanComplete(subscription); // withKeywords: ["NimBLE"], on Android await FlutterBluePlus.startScan(timeout: Duration(seconds: 5)); await FlutterBluePlus.isScanning.where((val) => val == false).first; super.setStatus(ScanStatus.finished); } @override Future stopScan() async { await FlutterBluePlus.stopScan(); } @override void dispose() { stopScan().ignore(); super.dispose(); } final List _scanResults = []; bool _deviceInResults(ScanResult incomingDev) => _scanResults.any( (existingDev) => existingDev.device.remoteId == incomingDev.device.remoteId, ); void _onScanResult(List results) { if (results.isNotEmpty) { for (var r in results.where( (d) => d.rssi > -90 && !_deviceInResults(d), )) { logger.i( '${r.device.remoteId}: "${r.device.platformName}" / "${r.device.advName}" / "${r.advertisementData.advName}" found!', ); _scanResults.add(r); } } } }