So basically I have a class that handles all my bluetooth connection. Inside this class there are also some variables that I need inside my Widgettree. I need to listen for updates on these variables but that doesn't work out like I want it to.
In detail, the _ShowScanningStatus widget should be updated, because this is like a status bar if the bluetooth discovering devices is still going or finished.
So this is my current screen:
class ScreenDeviceSelect extends HookWidget {
const ScreenDeviceSelect({super.key});
@override
Widget build(BuildContext context) {
if (Config.instance?.deviceId != null) {
Future.microtask(
() => navigatorKey.currentState!.pushReplacementNamed('/app/dashboard'),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Select Device'),
),
body: RefreshIndicator(
onRefresh: () async {
// TODO: Create code to refresh
return Future(() => null);
},
child: TurnOnBluetoothWidget(
child: Align(
alignment: Alignment.topCenter,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// Header with scan status
const _ShowScanningStatus(), // <---- Here is the widget
// Info / Disclaimer
Container(
color: Colors.black38,
width: double.maxFinite,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
const Padding(
padding: EdgeInsets.only(right: 8),
child: Icon(Icons.info),
),
Expanded(
child: Text(
"If your bluetooth device doesn't appear, refresh by swiping down.",
style: Theme.of(context).textTheme.bodySmall,
),
),
],
),
),
),
StreamBuilder(
stream: BC.instance!.scanResultsStream,
builder: (context, snapshot) {
if (snapshot.data != null) {
if (snapshot.data!.isNotEmpty) {
return NearbyDeviceList(scanResults: snapshot.data!);
}
}
return const Padding(
padding: EdgeInsets.all(32),
child: CenteredLoadingIndicator(),
);
},
),
],
),
),
),
),
);
}
}
In there I used this self created widget:
class _ShowScanningStatus extends HookWidget {
const _ShowScanningStatus();
@override
Widget build(BuildContext context) {
var scan = useState(BC.instance!.scan);
return Container(
color: Colors.black45,
height: 70,
width: double.maxFinite,
child: scan.value == null
? Row(
children: const [
Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
child: Icon(
Icons.check,
size: 40,
),
),
Text('Scan completed.'),
],
)
: Row(
children: const [
Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
child: CircularProgressIndicator(),
),
Text('Scanning for bluetooth devices...')
],
),
);
}
}
As you can see, I used a BC.instance
. That is the class, that has the variable scan
and I need to update the Widgettree if this variable updates.
My Class BC:
class BC {
static BC? instance;
BCState state = BCState.offline;
List<DiscoveredDevice> scanResults = [];
StreamSubscription<DiscoveredDevice>? scan; // <--- This is the variable to look for
Stream<BleStatus> bleStatusStream = Stream<BleStatus>.periodic(
const Duration(seconds: 1),
(computationCount) {
return flutterReactiveBle.status;
},
);
late Stream<List<DiscoveredDevice>> scanResultsStream;
BC() {
BC.instance = this;
scanResultsStream = Stream<List<DiscoveredDevice>>.periodic(
const Duration(seconds: 1),
(computationCount) {
return scanResults;
},
);
}
Future\<void\> checkPermissions() async {
if (!await Permission.bluetooth.isGranted) {
await Permission.bluetooth.request();
}
if (!await Permission.bluetoothConnect.isGranted) {
await Permission.bluetoothConnect.request();
}
if (!await Permission.bluetoothScan.isGranted) {
await Permission.bluetoothScan.request();
}
if (!await Permission.bluetoothAdvertise.isGranted) {
await Permission.bluetoothAdvertise.request();
}
}
void searchDevice() async {
await checkPermissions();
if (scan != null) return;
// Here the scan variable is set, so it should "send" a signal to my _ShowScanningStatus widget to update
scan = flutterReactiveBle.scanForDevices(
withServices: [],
).listen((device) {
if (device.name.isEmpty) return;
if (scanResults.every((element) => element.id != device.id)) {
debugPrint("New device detected: ${device.id} ${device.name}");
List<DiscoveredDevice> newScanResults = [];
for (var scan in scanResults) {
newScanResults.add(scan);
}
scanResults = newScanResults..add(device);
}
});
Future.delayed(const Duration(seconds: 5)).then((value) {
scan?.cancel(); // here I update the variable again. I want the Widgettree to update if i execute this
scan = null;
debugPrint("stop scan");
});
}
}