diff options
Diffstat (limited to 'lib/scan_page.dart')
-rw-r--r-- | lib/scan_page.dart | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/lib/scan_page.dart b/lib/scan_page.dart new file mode 100644 index 0000000..d21ade7 --- /dev/null +++ b/lib/scan_page.dart @@ -0,0 +1,173 @@ +import 'dart:io' show Platform; + +import 'package:badge/device_details.dart'; +import 'package:badge/device_scan_select.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()); + +class ScanPage extends StatefulWidget { + const ScanPage({super.key, required this.title}); + + // Original doc: Fields in a Widget subclass are always marked "final". + + final String title; + + @override + State<ScanPage> createState() => _ScanPageState(); +} + +class _ScanPageState extends State<ScanPage> { + List<ScanResult> scanResults = []; + bool isScanning = false; + + ScanResult? selectedDevice; + + void _doConnect() async { + var dev = selectedDevice?.device; + if (dev == null) return; + //??? + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DeviceDetailsScreen(btDevice: 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; + }); + } + } + + 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(() {}); + } + } + + bool _deviceInResults(ScanResult incomingDev) => scanResults.any( + (existingDev) => existingDev.device.remoteId == incomingDev.device.remoteId, + ); + + Future getPermissions() async { + try { + await Permission.bluetooth.request(); + } catch (e) { + logger.e(e.toString()); + } + } + + 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 + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: Text(widget.title), + ), + body: Center( + child: Column( + // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" + // action in the IDE, or press "p" in the console), to see the + // wireframe for each widget. + mainAxisAlignment: MainAxisAlignment.center, + spacing: 24, + children: <Widget>[ + SizedBox(height: 15), + Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 15.0, + children: [ + ElevatedButton( + onPressed: isScanning ? null : _doScan, + child: isScanning ? Text("Scanning...") : Text("Start scan"), + ), + ElevatedButton( + onPressed: (selectedDevice == null || isScanning) + ? null + : _doConnect, + child: Text("Connect"), + ), + ], + ), + Expanded( + child: DeviceScanSelection( + items: scanResults, + onItemSelected: (item) { + setState(() => selectedDevice = item); + }, + ), + ), + ], + ), + ), + ); + } +} |