1

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");
    });

  }
}

1 Answers1

0

useState is just keeping a variable around. You can useStream to subscribe (and unsubscribe!) to a Stream.

ValiumdiƤt
  • 163
  • 11