diff options
author | uvok | 2025-07-30 13:59:48 +0200 |
---|---|---|
committer | uvok | 2025-07-30 13:59:48 +0200 |
commit | b968fb872d459c37a8e400b7e2d999688728b59b (patch) | |
tree | 20e5a62b5ea4c28e0f8806821074c1e301aa4db5 /lib | |
parent | 5e1ec6faca3f89cfb96918c48cb2b1deccac65c5 (diff) |
Clear all hardcoded flutter ble stuff
Diffstat (limited to 'lib')
-rw-r--r-- | lib/control/flutter_blue_plus_scanner_controller.dart | 47 | ||||
-rw-r--r-- | lib/device_details.dart | 130 | ||||
-rw-r--r-- | lib/device_scan_select.dart | 18 | ||||
-rw-r--r-- | lib/main.dart | 2 | ||||
-rw-r--r-- | lib/model/device.dart | 2 | ||||
-rw-r--r-- | lib/scan_page.dart | 84 |
6 files changed, 125 insertions, 158 deletions
diff --git a/lib/control/flutter_blue_plus_scanner_controller.dart b/lib/control/flutter_blue_plus_scanner_controller.dart index b6f9dfc..f8cd741 100644 --- a/lib/control/flutter_blue_plus_scanner_controller.dart +++ b/lib/control/flutter_blue_plus_scanner_controller.dart @@ -4,6 +4,9 @@ import 'package:badge/model/flutter_blue_plus_device.dart'; import 'package:badge/model/device.dart'; import 'package: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 { final StreamController<List<Device>> _scanResultsController = @@ -17,18 +20,33 @@ class FlutterBluePlusScannerController extends ScannerControllerImpl { 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<Device> devices = results - .map((d) => FlutterBluePlusDevice.fromScan(d)) - .toList(); - _scanResultsController.add(devices); - }); + var subscription = FlutterBluePlus.scanResults.listen( + (results) { + List<Device> devices = results + .map((d) => FlutterBluePlusDevice.fromScan(d)) + .toList(); + _scanResultsController.add(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 @@ -41,4 +59,21 @@ class FlutterBluePlusScannerController extends ScannerControllerImpl { stopScan().ignore(); _scanResultsController.close(); } + + List<ScanResult> _scanResults = []; + bool _deviceInResults(ScanResult incomingDev) => _scanResults.any( + (existingDev) => existingDev.device.remoteId == incomingDev.device.remoteId, + ); + void _onScanResult(List<ScanResult> 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); + } + } + } } diff --git a/lib/device_details.dart b/lib/device_details.dart index 9c92a64..961ad33 100644 --- a/lib/device_details.dart +++ b/lib/device_details.dart @@ -1,16 +1,13 @@ -import 'dart:async'; - -import 'package:badge/first_where_ext.dart'; +import 'package:badge/model/device.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:logger/logger.dart'; -var logger = Logger(printer: PrettyPrinter()); +var logger = Logger(); class DeviceDetailsScreen extends StatefulWidget { - final BluetoothDevice btDevice; + final Device device; - const DeviceDetailsScreen({super.key, required this.btDevice}); + const DeviceDetailsScreen({super.key, required this.device}); @override State<StatefulWidget> createState() { @@ -21,15 +18,14 @@ class DeviceDetailsScreen extends StatefulWidget { class DeviceDetailsState extends State<DeviceDetailsScreen> { String connectStatus = "<Status>"; // Just to have a resonable default subscription? - StreamSubscription<BluetoothConnectionState> subs = - Stream<BluetoothConnectionState>.empty().listen((e) => ()); + // StreamSubscription<BluetoothConnectionState> subs = + // Stream<BluetoothConnectionState>.empty().listen((e) => ()); /// Whether the back button should be active. bool backActive = false; - BluetoothCharacteristic? current; - - BluetoothCharacteristic? available; + // BluetoothCharacteristic? current; + // BluetoothCharacteristic? available; @override Widget build(BuildContext context) { @@ -63,7 +59,7 @@ class DeviceDetailsState extends State<DeviceDetailsScreen> { Navigator.pop(context); } - void onConnStateChange(BluetoothConnectionState event) { + void onConnStateChange(ConnectionStatus event) { setState(() { connectStatus = event.toString(); }); @@ -74,40 +70,40 @@ class DeviceDetailsState extends State<DeviceDetailsScreen> { void deactivate() { super.deactivate(); logger.i("Closing state"); - subs.cancel().ignore(); - widget.btDevice.disconnect().ignore(); + // subs.cancel().ignore(); + // widget.device.disconnect().ignore(); } void _doConnect() async { - final dev = widget.btDevice; - subs.cancel().ignore(); - subs = dev.connectionState.listen(onConnStateChange); + final dev = widget.device; + // subs.cancel().ignore(); + // subs = dev.connectionState.listen(onConnStateChange); try { logger.i("Try to connect..."); // connect timeout doesn't work under Linux - await dev.connect().timeout(Duration(seconds: 2)); - logger.i("Connected!"); - - connectStatus = "Connected"; - - // ???? WTF ???? - List<BluetoothService> svcs = await dev.discoverServices(); - dev.onServicesReset.listen((_) async { - logger.i("Services Reset"); - try { - List<BluetoothService> svcs = await dev.discoverServices(); - findCharac(svcs); - } catch (e) { - logger.e(e); - } - }); - - logger.i("services discovered"); - - findCharac(svcs); + // await dev.connect().timeout(Duration(seconds: 2)); + // logger.i("Connected!"); + + // connectStatus = "Connected"; + + // // ???? WTF ???? + // List<BluetoothService> svcs = await dev.discoverServices(); + // dev.onServicesReset.listen((_) async { + // logger.i("Services Reset"); + // try { + // List<BluetoothService> svcs = await dev.discoverServices(); + // findCharac(svcs); + // } catch (e) { + // logger.e(e); + // } + // }); + + // logger.i("services discovered"); + + // findCharac(svcs); } catch (e) { logger.e(e); - dev.disconnect().ignore(); + // dev.disconnect().ignore(); connectStatus = e.toString(); } finally { backActive = true; @@ -117,32 +113,32 @@ class DeviceDetailsState extends State<DeviceDetailsScreen> { } } - void findCharac(List<BluetoothService> svcs) { - if (svcs.isEmpty) { - connectStatus += ", No services found!"; - return; - } - connectStatus += ", Services found!"; - BluetoothService? badgeService = svcs.firstWhereOrNull( - (s) => s.serviceUuid.str == "ca260000-b4bb-46b2-bd06-b7b7a61ea990", - ); - - if (badgeService == null) { - } else { - logger.i("badge service found"); - current = badgeService.characteristics.firstWhereOrNull( - (c) => - c.characteristicUuid.str == "ca260001-b4bb-46b2-bd06-b7b7a61ea990", - ); - available = badgeService.characteristics.firstWhereOrNull( - (c) => - c.characteristicUuid.str == "ca260002-b4bb-46b2-bd06-b7b7a61ea990", - ); - } - - if (current == null || available == null) { - } else { - logger.i("characteristics found"); - } - } + // void findCharac(List<BluetoothService> svcs) { + // if (svcs.isEmpty) { + // connectStatus += ", No services found!"; + // return; + // } + // connectStatus += ", Services found!"; + // BluetoothService? badgeService = svcs.firstWhereOrNull( + // (s) => s.serviceUuid.str == "ca260000-b4bb-46b2-bd06-b7b7a61ea990", + // ); + + // if (badgeService == null) { + // } else { + // logger.i("badge service found"); + // current = badgeService.characteristics.firstWhereOrNull( + // (c) => + // c.characteristicUuid.str == "ca260001-b4bb-46b2-bd06-b7b7a61ea990", + // ); + // available = badgeService.characteristics.firstWhereOrNull( + // (c) => + // c.characteristicUuid.str == "ca260002-b4bb-46b2-bd06-b7b7a61ea990", + // ); + // } + + // if (current == null || available == null) { + // } else { + // logger.i("characteristics found"); + // } + // } } diff --git a/lib/device_scan_select.dart b/lib/device_scan_select.dart index 7dafe2b..9ed0583 100644 --- a/lib/device_scan_select.dart +++ b/lib/device_scan_select.dart @@ -1,5 +1,5 @@ +import 'package:badge/model/device.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_blue_plus/flutter_blue_plus.dart'; abstract class NotifyingListWidget<T> extends StatefulWidget { final List<T> items; @@ -12,7 +12,7 @@ abstract class NotifyingListWidget<T> extends StatefulWidget { }); } -class DeviceScanSelection extends NotifyingListWidget<ScanResult> { +class DeviceScanSelection extends NotifyingListWidget<Device> { const DeviceScanSelection({ super.key, required super.items, @@ -33,16 +33,12 @@ class _DeviceScanSelectionState extends State<DeviceScanSelection> { itemCount: widget.items.length, itemBuilder: (context, index) { if (index >= widget.items.length) return null; - final ScanResult result = widget.items[index]; - final String name = firstGiven([ - result.device.advName, - result.device.platformName, - "<Unknown>", - ]); + final Device result = widget.items[index]; + final String name = result.name ?? "???"; return ListTile( title: Text(name), - subtitle: Text(result.device.remoteId.str), + subtitle: Text(result.address ?? "???"), trailing: Text('RSSI: ${result.rssi}'), selectedTileColor: Colors.amber, selectedColor: Colors.black, @@ -73,10 +69,10 @@ class _DeviceScanSelectionState extends State<DeviceScanSelection> { } } - bool _deviceListEqual(List<ScanResult> oldList, List<ScanResult> newList) { + bool _deviceListEqual(List<Device> oldList, List<Device> newList) { if (oldList.length != newList.length) return false; for (int i = 0; i < oldList.length; i++) { - if (oldList[i].device.remoteId != newList[i].device.remoteId) { + if (oldList[i].address != newList[i].address) { return false; } } diff --git a/lib/main.dart b/lib/main.dart index 64aab35..45f69db 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; -var logger = Logger(printer: PrettyPrinter()); +var logger = Logger(); void main() { runApp(const BadgeApp()); diff --git a/lib/model/device.dart b/lib/model/device.dart index 98445fa..27d33dd 100644 --- a/lib/model/device.dart +++ b/lib/model/device.dart @@ -1,3 +1,5 @@ +enum ConnectionStatus { disconnected, connected, error } + /// Represents a (badge) device to be connected to. abstract class Device { String? get name; diff --git a/lib/scan_page.dart b/lib/scan_page.dart index d21ade7..0ebc2e3 100644 --- a/lib/scan_page.dart +++ b/lib/scan_page.dart @@ -1,13 +1,11 @@ -import 'dart:io' show Platform; - import 'package:badge/device_details.dart'; import 'package:badge/device_scan_select.dart'; +import 'package:badge/model/device.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:logger/logger.dart'; import 'package:permission_handler/permission_handler.dart'; -var logger = Logger(printer: PrettyPrinter()); +var logger = Logger(); class ScanPage extends StatefulWidget { const ScanPage({super.key, required this.title}); @@ -21,85 +19,36 @@ class ScanPage extends StatefulWidget { } class _ScanPageState extends State<ScanPage> { - List<ScanResult> scanResults = []; + List<Device> scanResults = []; bool isScanning = false; - ScanResult? selectedDevice; + Device? selectedDevice; void _doConnect() async { - var dev = selectedDevice?.device; + Device? dev = selectedDevice; if (dev == null) return; //??? Navigator.push( context, - MaterialPageRoute( - builder: (context) => DeviceDetailsScreen(btDevice: dev), - ), + MaterialPageRoute(builder: (context) => DeviceDetailsScreen(device: dev)), ); } void _doScan() async { - var system = await FlutterBluePlus.systemDevices([]); - for (var d in system) { - logger.i('${d.platformName} already connected to! ${d.remoteId}'); - } - setState(() { selectedDevice = null; scanResults = []; isScanning = true; }); - var subscription = FlutterBluePlus.scanResults.listen( - onScanResult, - onError: (e) => logger.e(e), - ); - // either this, or the cancel in the finally block, should do the same? - FlutterBluePlus.cancelWhenScanComplete(subscription); - - try { - if (Platform.isAndroid) { - // Ehhhh... can't have both keyword/services - await FlutterBluePlus.startScan( - withKeywords: ["NimBLE"], - timeout: Duration(seconds: 5), - ); - } else { - // for Linux, which can't do advNames (but platformname, for whatever reason) - // msd doesn't work, either???? - await FlutterBluePlus.startScan( - //withMsd: [MsdFilter(0xffff, data: ascii.encode("uvok"))], - timeout: Duration(seconds: 5), - ); - } - // wait for scanning to stop - await FlutterBluePlus.isScanning.where((val) => val == false).first; - } finally { - subscription.cancel(); - setState(() { - isScanning = false; - }); - } - } + // ... + await Future.delayed(Duration(seconds: 5)); - void onScanResult(List<ScanResult> 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); - } - setState(() {}); - } + setState(() { + isScanning = false; + }); } - bool _deviceInResults(ScanResult incomingDev) => scanResults.any( - (existingDev) => existingDev.device.remoteId == incomingDev.device.remoteId, - ); - Future getPermissions() async { try { await Permission.bluetooth.request(); @@ -108,21 +57,10 @@ class _ScanPageState extends State<ScanPage> { } } - void btHandler(BluetoothAdapterState event) { - logger.i(event); - switch (event) { - case BluetoothAdapterState.on: - break; - default: - break; - } - } - @override void initState() { super.initState(); getPermissions(); - FlutterBluePlus.adapterState.listen(btHandler); } @override |