1import 'dart:async';
 2import 'dart:io';
 3
 4import 'package:blood_pressure_app/features/old_bluetooth/logic/flutter_blue_plus_mockable.dart';
 5import 'package:flutter/foundation.dart';
 6import 'package:flutter_bloc/flutter_bloc.dart';
 7import 'package:flutter_blue_plus/flutter_blue_plus.dart';
 8
 9part 'bluetooth_state.dart';
10
11/// Availability of the devices bluetooth adapter.
12///
13/// The only state that allows using the adapter is [BluetoothReady].
14class BluetoothCubit extends Cubit<BluetoothState> {
15  /// Create a cubit connecting to the bluetooth module for availability.
16  ///
17  /// [flutterBluePlus] may be provided for testing purposes.
18  BluetoothCubit({
19    FlutterBluePlusMockable? flutterBluePlus
20  }): _flutterBluePlus = flutterBluePlus ?? FlutterBluePlusMockable(),
21        super(BluetoothInitial()) {
22    _adapterStateStateSubscription = _flutterBluePlus.adapterState.listen(_onAdapterStateChanged);
23  }
24
25  final FlutterBluePlusMockable _flutterBluePlus;
26
27  BluetoothAdapterState _adapterState = BluetoothAdapterState.unknown;
28
29  late StreamSubscription<BluetoothAdapterState> _adapterStateStateSubscription;
30
31  @override
32  Future<void> close() async {
33    await _adapterStateStateSubscription.cancel();
34    await super.close();
35  }
36
37  void _onAdapterStateChanged(BluetoothAdapterState state) async {
38    _adapterState = state;
39    switch (_adapterState) {
40      case BluetoothAdapterState.unavailable:
41        emit(BluetoothUnfeasible());
42      case BluetoothAdapterState.unauthorized:
43        // Bluetooth permissions should always be granted on normal android
44        // devices. Users on non-standard android devices will know how to
45        // enable them. If this is not the case there will be bug reports.
46        emit(BluetoothUnauthorized());
47      case BluetoothAdapterState.on:
48        emit(BluetoothReady());
49      case BluetoothAdapterState.off:
50      case BluetoothAdapterState.turningOff:
51      case BluetoothAdapterState.turningOn:
52        emit(BluetoothDisabled());
53      case BluetoothAdapterState.unknown:
54        emit(BluetoothInitial());
55    }
56  }
57
58  /// Request to enable bluetooth on the device
59  Future<bool> enableBluetooth() async {
60    assert(state is BluetoothDisabled, 'No need to enable bluetooth when '
61        'already enabled or not known to be disabled.');
62    try {
63      if (!Platform.isAndroid) return false;
64      await _flutterBluePlus.turnOn();
65      return true;
66    } on FlutterBluePlusException {
67      return false;
68    }
69  }
70
71  /// Reevaluate the current state.
72  ///
73  /// When the user is in another app like the device settings, sometimes
74  /// the app won't get notified about permission changes and such. In those
75  /// instances the user should have the option to manually recheck the state to
76  /// avoid getting stuck on a unauthorized state.
77  Future<void> forceRefresh() async {
78    _onAdapterStateChanged(_flutterBluePlus.adapterStateNow);
79  }
80}