Commit bfdf6ac
Changed files (6)
app
lib
bluetooth
components
dialoges
app/lib/bluetooth/mock/fake_characteristic.dart
@@ -0,0 +1,84 @@
+import 'dart:async';
+
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class FakeBleBpCharacteristic implements BluetoothCharacteristic {
+ final StreamController<List<int>> _valueReceivedController = StreamController.broadcast();
+
+ @override
+ Guid get characteristicUuid => Guid('2A35');
+ @override
+ Guid get uuid => characteristicUuid;
+
+ @override
+ Stream<List<int>> get onValueReceived => _valueReceivedController.stream;
+
+ @override
+ Future<bool> setNotifyValue(bool notify, {int timeout = 15, bool forceIndications = false}) async{
+ if (notify) {
+ _valueReceivedController.add([22, 124, 0, 86, 0, 97, 0, 232, 7, 6, 15, 17, 17, 27, 51, 0, 0, 0]);
+ }
+ return true;
+ }
+
+ @override
+ // TODO: implement descriptors
+ List<BluetoothDescriptor> get descriptors => throw UnimplementedError();
+
+ @override
+ // TODO: implement device
+ BluetoothDevice get device => throw UnimplementedError();
+
+ @override
+ // TODO: implement deviceId
+ DeviceIdentifier get deviceId => throw UnimplementedError();
+
+ @override
+ // TODO: implement isNotifying
+ bool get isNotifying => throw UnimplementedError();
+
+ @override
+ // TODO: implement lastValue
+ List<int> get lastValue => throw UnimplementedError();
+
+ @override
+ // TODO: implement lastValueStream
+ Stream<List<int>> get lastValueStream => throw UnimplementedError();
+
+ @override
+ // TODO: implement onValueChangedStream
+ Stream<List<int>> get onValueChangedStream => throw UnimplementedError();
+
+ @override
+ // TODO: implement properties
+ CharacteristicProperties get properties => throw UnimplementedError();
+
+ @override
+ Future<List<int>> read({int timeout = 15}) {
+ // TODO: implement read
+ throw UnimplementedError();
+ }
+
+ @override
+ // TODO: implement remoteId
+ DeviceIdentifier get remoteId => throw UnimplementedError();
+
+ @override
+ // TODO: implement secondaryServiceUuid
+ Guid? get secondaryServiceUuid => throw UnimplementedError();
+
+ @override
+ // TODO: implement serviceUuid
+ Guid get serviceUuid => throw UnimplementedError();
+
+ @override
+ // TODO: implement value
+ Stream<List<int>> get value => throw UnimplementedError();
+
+ @override
+ Future<void> write(List<int> value, {bool withoutResponse = false, bool allowLongWrite = false, int timeout = 15}) {
+ // TODO: implement write
+ throw UnimplementedError();
+ }
+
+}
\ No newline at end of file
app/lib/bluetooth/mock/fake_device.dart
@@ -0,0 +1,187 @@
+import 'dart:async';
+
+import 'package:blood_pressure_app/bluetooth/mock/fake_service.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class FakeDevice implements BluetoothDevice {
+ FakeDevice() {
+ Timer.periodic(Duration(seconds: 2), (timer) {
+ _connectedController.add(_connected ? BluetoothConnectionState.connected : BluetoothConnectionState.disconnected);
+ });
+ }
+
+ bool _connected = false;
+ StreamController<BluetoothConnectionState> _connectedController = StreamController.broadcast();
+
+
+ List<BluetoothService> _services = [
+ FakeBleBPService(),
+ ];
+
+ String _platformName = 'test device 1234';
+
+ AdvertisementData createFakeData() => AdvertisementData(
+ advName: advName,
+ txPowerLevel: null,
+ appearance: null,
+ connectable: true,
+ manufacturerData: {},
+ serviceData: {},
+ serviceUuids: [],
+ );
+
+ @override
+ String get advName => platformName;
+
+ @override
+ // TODO: implement bondState
+ Stream<BluetoothBondState> get bondState => throw UnimplementedError();
+
+ @override
+ void cancelWhenDisconnected(StreamSubscription subscription, {bool next = false, bool delayed = false}) {
+ // TODO: implement cancelWhenDisconnected
+ }
+
+ @override
+ Future<void> clearGattCache() {
+ // TODO: implement clearGattCache
+ throw UnimplementedError();
+ }
+
+ @override
+ Future<void> connect({Duration timeout = const Duration(seconds: 35), int? mtu = 512, bool autoConnect = false}) async {
+ print('CALLED CONNECT');
+ _connected = true;
+ final state = _connected
+ ? BluetoothConnectionState.connected
+ : BluetoothConnectionState.disconnected;
+ _connectedController.add(state);
+ }
+
+ @override
+ Stream<BluetoothConnectionState> get connectionState => _connectedController.stream;
+
+ @override
+ Future<void> createBond({int timeout = 90}) {
+ // TODO: implement createBond
+ throw UnimplementedError();
+ }
+
+ @override
+ Future<void> disconnect({int timeout = 35, bool queue = true}) async {
+ print('CALLED DISCONNECT:');
+ debugPrintStack();
+ _connected = false;
+ final state = _connected
+ ? BluetoothConnectionState.connected
+ : BluetoothConnectionState.disconnected;
+ _connectedController.add(state);
+ }
+
+ @override
+ DisconnectReason? get disconnectReason => null;
+
+ @override
+ Future<List<BluetoothService>> discoverServices({bool subscribeToServicesChanged = true, int timeout = 15}) async {
+ assert(_connected);
+ return _services;
+ }
+
+ @override
+ // TODO: implement id
+ DeviceIdentifier get id => throw UnimplementedError();
+
+ @override
+ bool get isAutoConnectEnabled => false;
+
+ @override
+ bool get isConnected => _connected;
+
+ @override
+ bool get isDisconnected => !_connected;
+
+ @override
+ // TODO: implement isDiscoveringServices
+ Stream<bool> get isDiscoveringServices => throw UnimplementedError();
+
+ @override
+ // TODO: implement localName
+ String get localName => throw UnimplementedError();
+
+ @override
+ // TODO: implement mtu
+ Stream<int> get mtu => throw UnimplementedError();
+
+ @override
+ // TODO: implement mtuNow
+ int get mtuNow => throw UnimplementedError();
+
+ @override
+ // TODO: implement name
+ String get name => throw UnimplementedError();
+
+ @override
+ // TODO: implement onServicesReset
+ Stream<void> get onServicesReset => throw UnimplementedError();
+
+ @override
+ Future<void> pair() {
+ // TODO: implement pair
+ throw UnimplementedError();
+ }
+
+ @override
+ String get platformName => _platformName;
+
+ @override
+ // TODO: implement prevBondState
+ BluetoothBondState? get prevBondState => throw UnimplementedError();
+
+ @override
+ Future<int> readRssi({int timeout = 15}) {
+ // TODO: implement readRssi
+ throw UnimplementedError();
+ }
+
+ @override
+ // TODO: implement remoteId
+ DeviceIdentifier get remoteId => throw UnimplementedError();
+
+ @override
+ Future<void> removeBond({int timeout = 30}) {
+ // TODO: implement removeBond
+ throw UnimplementedError();
+ }
+
+ @override
+ Future<void> requestConnectionPriority({required ConnectionPriority connectionPriorityRequest}) {
+ // TODO: implement requestConnectionPriority
+ throw UnimplementedError();
+ }
+
+ @override
+ Future<int> requestMtu(int desiredMtu, {double predelay = 0.35, int timeout = 15}) {
+ // TODO: implement requestMtu
+ throw UnimplementedError();
+ }
+
+ @override
+ Stream<List<BluetoothService>> get services => Stream.value(_services);
+
+ @override
+ List<BluetoothService> get servicesList => _services;
+
+ @override
+ Stream<List<BluetoothService>> get servicesStream => Stream.value(_services);
+
+ @override
+ Future<void> setPreferredPhy({required int txPhy, required int rxPhy, required PhyCoding option}) {
+ // TODO: implement setPreferredPhy
+ throw UnimplementedError();
+ }
+
+ @override
+ Stream<BluetoothConnectionState> get state => connectionState;
+
+}
app/lib/bluetooth/mock/fake_flutter_blue_plus.dart
@@ -0,0 +1,105 @@
+import 'dart:async';
+
+import 'package:blood_pressure_app/bluetooth/flutter_blue_plus_mockable.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+import 'fake_device.dart';
+
+/// Wrapper for FlutterBluePlus in order to easily mock it
+/// Wraps all calls for testing purposes
+class FakeFlutterBluePlus extends FlutterBluePlusMockable {
+ FakeFlutterBluePlus(): assert(kDebugMode);
+
+ final BluetoothAdapterState _kFakeAdapterState = BluetoothAdapterState.on;
+ final List<ScanResult> _kFakeScanResults = [
+ ScanResult(
+ device: FakeDevice(),
+ advertisementData: FakeDevice().createFakeData(),
+ rssi: 123,
+ timeStamp: DateTime.now()
+ )
+ ];
+
+ StreamController<List<ScanResult>> _fakeScanResultsEmiter = StreamController.broadcast();
+ Timer? _fakeScanResultsEmitTimer;
+
+ @override
+ BluetoothAdapterState get adapterStateNow => BluetoothAdapterState.on;
+
+ StreamController<bool> _isScanning = StreamController.broadcast();
+ bool _scanningNow = false;
+
+ @override
+ Stream<bool> get isScanning => _isScanning.stream;
+
+ @override
+ bool get isScanningNow => _scanningNow;
+
+ @override
+ List<ScanResult> get lastScanResults => _kFakeScanResults;
+
+ @override
+ Stream<List<ScanResult>> get scanResults => _fakeScanResultsEmiter.stream;
+
+ @override
+ Stream<List<ScanResult>> get onScanResults => _fakeScanResultsEmiter.stream;
+
+ @override
+ BluetoothEvents get events => throw UnimplementedError();
+
+ @override
+ Stream<BluetoothAdapterState> get adapterState => Stream.value(_kFakeAdapterState);
+
+ @override
+ List<BluetoothDevice> get connectedDevices => throw UnimplementedError();
+
+ @override
+ Future<List<BluetoothDevice>> get systemDevices => throw UnimplementedError();
+
+ @override
+ Future<List<BluetoothDevice>> get bondedDevices => throw UnimplementedError();
+
+ @override
+ Future<void> setOptions({bool showPowerAlert = true,}) => throw UnimplementedError();
+
+ @override
+ Future<void> turnOn({int timeout = 60}) async => null;
+
+ @override
+ Future<void> startScan({
+ List<Guid> withServices = const [],
+ List<String> withRemoteIds = const [],
+ List<String> withNames = const [],
+ List<String> withKeywords = const [],
+ List<MsdFilter> withMsd = const [],
+ List<ServiceDataFilter> withServiceData = const [],
+ Duration? timeout,
+ Duration? removeIfGone,
+ bool continuousUpdates = false,
+ int continuousDivisor = 1,
+ bool oneByOne = false,
+ AndroidScanMode androidScanMode = AndroidScanMode.lowLatency,
+ bool androidUsesFineLocation = false,
+ }) async {
+ assert(_fakeScanResultsEmitTimer == null);
+ _scanningNow = true;
+ _fakeScanResultsEmitTimer = Timer.periodic(Duration(seconds: 1), (timer) {
+ _fakeScanResultsEmiter.add(_kFakeScanResults);
+ });
+ }
+
+ @override
+ Future<void> stopScan() async {
+ _scanningNow = false;
+ _fakeScanResultsEmitTimer!.cancel();
+ }
+
+ @override
+ void cancelWhenScanComplete(StreamSubscription subscription) =>
+ FlutterBluePlus.cancelWhenScanComplete(subscription); // TODO: figure out if useful
+
+
+ @override
+ Future<PhySupport> getPhySupport() => throw UnimplementedError();
+}
\ No newline at end of file
app/lib/bluetooth/mock/fake_service.dart
@@ -0,0 +1,29 @@
+import 'package:blood_pressure_app/bluetooth/mock/fake_characteristic.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class FakeBleBPService implements BluetoothService {
+ @override
+ List<BluetoothCharacteristic> get characteristics => [FakeBleBpCharacteristic()];
+
+ @override
+ // TODO: implement deviceId
+ DeviceIdentifier get deviceId => throw UnimplementedError();
+
+ @override
+ List<BluetoothService> get includedServices => [];
+
+ @override
+ // TODO: implement isPrimary
+ bool get isPrimary => throw UnimplementedError();
+
+ @override
+ // TODO: implement remoteId
+ DeviceIdentifier get remoteId => throw UnimplementedError();
+
+ @override
+ Guid get serviceUuid => Guid('1810');
+
+ @override
+ Guid get uuid => Guid('1810');
+
+}
app/lib/bluetooth/mock/mock_ble_read_cubit.dart
@@ -0,0 +1,35 @@
+import 'package:blood_pressure_app/bluetooth/ble_read_cubit.dart';
+import 'package:blood_pressure_app/bluetooth/characteristics/ble_measurement_data.dart';
+import 'package:blood_pressure_app/bluetooth/characteristics/ble_measurement_status.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+class MockBleReadCubit extends Cubit<BleReadState> implements BleReadCubit {
+ MockBleReadCubit(): super(BleReadSuccess(
+ BleMeasurementData(
+ systolic: 123,
+ diastolic: 456,
+ pulse: 67,
+ meanArterialPressure: 123456,
+ isMMHG: true,
+ userID: 3,
+ status: BleMeasurementStatus(
+ bodyMovementDetected: true,
+ cuffTooLose: true,
+ irregularPulseDetected: true,
+ pulseRateInRange: true,
+ pulseRateExceedsUpperLimit: true,
+ pulseRateIsLessThenLowerLimit: true,
+ improperMeasurementPosition: true,
+ ),
+ timestamp: DateTime.now(),
+ ),
+ ));
+
+ @override
+ Guid get characteristicUUID => throw UnimplementedError();
+
+ @override
+ Guid get serviceUUID => throw UnimplementedError();
+
+}
app/lib/components/dialoges/add_measurement_dialoge.dart
@@ -285,6 +285,7 @@ class _AddEntryDialogeState extends State<AddEntryDialoge> {
if (widget.settings.bleInput)
BluetoothInput(
settings: widget.settings,
+ /* flutterBluePlus: FakeFlutterBluePlus(), */
onMeasurement: (record) => setState(() => _loadFields(record)),
),
if (widget.settings.allowManualTimeInput)