Skip to content

Commit

Permalink
Merge pull request #248 from PhilipsHue/null-safety
Browse files Browse the repository at this point in the history
Null safety integration
  • Loading branch information
remonh87 authored Mar 27, 2021
2 parents fc94bb4 + 541974c commit c035b78
Show file tree
Hide file tree
Showing 70 changed files with 2,527 additions and 930 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Main releases

## 3.0.0

* Breaking: Migration to null-safety.
* Improve example app by adding discover services, read, write and subscribe to characteristic.

## 2.7.3

* Upgrade Android dependencies to comply to newer Gradle distributions.
Expand Down
8 changes: 4 additions & 4 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_reactive_ble/ios"

SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_reactive_ble: 118af63a7cda4e26ae1791bd1ddf659e2ae0a76d
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_reactive_ble: ac0ccac596f481b221549cad2abe16987e1f411b
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699

PODFILE CHECKSUM: fe0e1ee7f3d1f7d00b11b474b62dd62134535aea
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

COCOAPODS: 1.9.3
COCOAPODS: 1.10.0
2 changes: 0 additions & 2 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -262,14 +262,12 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
"${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
"${BUILT_PRODUCTS_DIR}/flutter_reactive_ble/flutter_reactive_ble.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_reactive_ble.framework",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 23 additions & 6 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_device_connector.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_device_interactor.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_scanner.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_status_monitor.dart';
import 'package:flutter_reactive_ble_example/src/ui/ble_status_screen.dart';
import 'package:flutter_reactive_ble_example/src/ui/device_list.dart';
import 'package:provider/provider.dart';

import 'src/ble/ble_logger.dart';

const _themeColor = Colors.lightGreen;

void main() {
WidgetsFlutterBinding.ensureInitialized();

final _bleLogger = BleLogger();
final _ble = FlutterReactiveBle();
final _scanner = BleScanner(_ble);
final _scanner = BleScanner(ble: _ble, logMessage: _bleLogger.addToLog);
final _monitor = BleStatusMonitor(_ble);
final _connector = BleDeviceConnector(_ble);
final _connector = BleDeviceConnector(
ble: _ble,
logMessage: _bleLogger.addToLog,
);
final _serviceDiscoverer = BleDeviceInteractor(
bleDiscoverServices: _ble.discoverServices,
readCharacteristic: _ble.readCharacteristic,
writeWithResponse: _ble.writeCharacteristicWithResponse,
writeWithOutResponse: _ble.writeCharacteristicWithoutResponse,
subscribeToCharacteristic: _ble.subscribeToCharacteristic,
logMessage: _bleLogger.addToLog,
);
runApp(
MultiProvider(
providers: [
Provider.value(value: _scanner),
Provider.value(value: _monitor),
Provider.value(value: _connector),
StreamProvider<BleScannerState>(
Provider.value(value: _serviceDiscoverer),
Provider.value(value: _bleLogger),
StreamProvider<BleScannerState?>(
create: (_) => _scanner.state,
initialData: const BleScannerState(
discoveredDevices: [],
scanIsInProgress: false,
),
),
StreamProvider<BleStatus>(
StreamProvider<BleStatus?>(
create: (_) => _monitor.state,
initialData: BleStatus.unknown,
),
Expand All @@ -54,12 +71,12 @@ void main() {

class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) => Consumer<BleStatus>(
Widget build(BuildContext context) => Consumer<BleStatus?>(
builder: (_, status, __) {
if (status == BleStatus.ready) {
return DeviceListScreen();
} else {
return BleStatusScreen(status: status);
return BleStatusScreen(status: status ?? BleStatus.unknown);
}
},
);
Expand Down
59 changes: 31 additions & 28 deletions example/lib/src/ble/ble_device_connector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,54 @@ import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_reactive_ble_example/src/ble/reactive_state.dart';

class BleDeviceConnector extends ReactiveState<ConnectionStateUpdate> {
BleDeviceConnector(this._ble);
BleDeviceConnector({
required FlutterReactiveBle ble,
required Function(String message) logMessage,
}) : _ble = ble,
_logMessage = logMessage;

final FlutterReactiveBle _ble;
final void Function(String message) _logMessage;

@override
Stream<ConnectionStateUpdate> get state => _deviceConnectionController.stream;

final _deviceConnectionController = StreamController<ConnectionStateUpdate>();

StreamSubscription<ConnectionStateUpdate> _connection;
// ignore: cancel_subscriptions
late StreamSubscription<ConnectionStateUpdate> _connection;

Future<void> connect(String deviceId) async {
if (_connection != null) {
await _connection.cancel();
}
_logMessage('Start connecting to $deviceId');
_connection = _ble.connectToDevice(id: deviceId).listen(
_deviceConnectionController.add,
);
(update) {
_logMessage(
'ConnectionState for device $deviceId : ${update.connectionState}');
_deviceConnectionController.add(update);
},
onError: (e) =>
_logMessage('Connecting to device $deviceId resulted in error $e'),
);
}

Future<void> disconnect(String deviceId) async {
if (_connection != null) {
try {
await _connection.cancel();
} on Exception catch (e, _) {
print("Error disconnecting from a device: $e");
} finally {
// Since [_connection] subscription is terminated, the "disconnected" state cannot be received and propagated
_deviceConnectionController.add(
ConnectionStateUpdate(
deviceId: deviceId,
connectionState: DeviceConnectionState.disconnected,
failure: null,
),
);
}
try {
_logMessage('disconnecting to device: $deviceId');
await _connection.cancel();
} on Exception catch (e, _) {
_logMessage("Error disconnecting from a device: $e");
} finally {
// Since [_connection] subscription is terminated, the "disconnected" state cannot be received and propagated
_deviceConnectionController.add(
ConnectionStateUpdate(
deviceId: deviceId,
connectionState: DeviceConnectionState.disconnected,
failure: null,
),
);
}
}

Future<void> discoverServices(String deviceId) async {
await _ble.discoverServices(deviceId).then(
(value) => print('Services discovered: $value'),
);
}

Future<void> dispose() async {
await _deviceConnectionController.close();
}
Expand Down
107 changes: 107 additions & 0 deletions example/lib/src/ble/ble_device_interactor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import 'dart:async';

import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';

class BleDeviceInteractor {
BleDeviceInteractor({
required Future<List<DiscoveredService>> Function(String deviceId)
bleDiscoverServices,
required Future<List<int>> Function(QualifiedCharacteristic characteristic)
readCharacteristic,
required Future<void> Function(QualifiedCharacteristic characteristic,
{required List<int> value})
writeWithResponse,
required Future<void> Function(QualifiedCharacteristic characteristic,
{required List<int> value})
writeWithOutResponse,
required void Function(String message) logMessage,
required Stream<List<int>> Function(QualifiedCharacteristic characteristic)
subscribeToCharacteristic,
}) : _bleDiscoverServices = bleDiscoverServices,
_readCharacteristic = readCharacteristic,
_writeWithResponse = writeWithResponse,
_writeWithoutResponse = writeWithOutResponse,
_subScribeToCharacteristic = subscribeToCharacteristic,
_logMessage = logMessage;

final Future<List<DiscoveredService>> Function(String deviceId)
_bleDiscoverServices;

final Future<List<int>> Function(QualifiedCharacteristic characteristic)
_readCharacteristic;

final Future<void> Function(QualifiedCharacteristic characteristic,
{required List<int> value}) _writeWithResponse;

final Future<void> Function(QualifiedCharacteristic characteristic,
{required List<int> value}) _writeWithoutResponse;

final Stream<List<int>> Function(QualifiedCharacteristic characteristic)
_subScribeToCharacteristic;

final void Function(String message) _logMessage;

Future<List<DiscoveredService>> discoverServices(String deviceId) async {
try {
_logMessage('Start discovering services for: $deviceId');
final result = await _bleDiscoverServices(deviceId);
_logMessage('Discovering services finished');
return result;
} on Error catch (e) {
_logMessage('Error occured when discovering services: $e');
throw e;
}
}

Future<List<int>> readCharacteristic(
QualifiedCharacteristic characteristic) async {
try {
final result = await _readCharacteristic(characteristic);

_logMessage('Read ${characteristic.characteristicId}: value = $result');
return result;
} on Error catch (e, s) {
_logMessage(
'Error occured when reading ${characteristic.characteristicId} : $e',
);
print(s);
throw e;
}
}

Future<void> writeCharacterisiticWithResponse(
QualifiedCharacteristic characteristic, List<int> value) async {
try {
_logMessage(
'Write with response value : $value to ${characteristic.characteristicId}');
await _writeWithResponse(characteristic, value: value);
} on Error catch (e, s) {
_logMessage(
'Error occured when writing ${characteristic.characteristicId} : $e',
);
print(s);
throw e;
}
}

Future<void> writeCharacterisiticWithoutResponse(
QualifiedCharacteristic characteristic, List<int> value) async {
try {
await _writeWithoutResponse(characteristic, value: value);
_logMessage(
'Write without response value: $value to ${characteristic.characteristicId}');
} on Error catch (e, s) {
_logMessage(
'Error occured when writing ${characteristic.characteristicId} : $e',
);
print(s);
throw e;
}
}

Stream<List<int>> subScribeToCharacteristic(
QualifiedCharacteristic characteristic) {
_logMessage('Subscribing to: ${characteristic.characteristicId} ');
return _subScribeToCharacteristic(characteristic);
}
}
15 changes: 15 additions & 0 deletions example/lib/src/ble/ble_logger.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:intl/intl.dart';

class BleLogger {
final List<String> _logMessages = [];
final DateFormat formatter = DateFormat('HH:mm:ss.SSS');

List<String> get messages => _logMessages;

void addToLog(String message) {
final now = DateTime.now();
_logMessages.add('${formatter.format(now)} - $message');
}

void clearLogs() => _logMessages.clear();
}
18 changes: 13 additions & 5 deletions example/lib/src/ble/ble_scanner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ import 'package:flutter_reactive_ble_example/src/ble/reactive_state.dart';
import 'package:meta/meta.dart';

class BleScanner implements ReactiveState<BleScannerState> {
BleScanner(this._ble);
BleScanner({
required FlutterReactiveBle ble,
required Function(String message) logMessage,
}) : _ble = ble,
_logMessage = logMessage;

final FlutterReactiveBle _ble;
final void Function(String message) _logMessage;
final StreamController<BleScannerState> _stateStreamController =
StreamController();

Expand All @@ -17,6 +22,7 @@ class BleScanner implements ReactiveState<BleScannerState> {
Stream<BleScannerState> get state => _stateStreamController.stream;

void startScan(List<Uuid> serviceIds) {
_logMessage('Start ble discovery');
_devices.clear();
_subscription?.cancel();
_subscription =
Expand All @@ -28,7 +34,7 @@ class BleScanner implements ReactiveState<BleScannerState> {
_devices.add(device);
}
_pushState();
});
}, onError: (e) => _logMessage('Device scan fails with error: $e'));
_pushState();
}

Expand All @@ -42,6 +48,8 @@ class BleScanner implements ReactiveState<BleScannerState> {
}

Future<void> stopScan() async {
_logMessage('Stop ble discovery');

await _subscription?.cancel();
_subscription = null;
_pushState();
Expand All @@ -51,14 +59,14 @@ class BleScanner implements ReactiveState<BleScannerState> {
await _stateStreamController.close();
}

StreamSubscription _subscription;
StreamSubscription? _subscription;
}

@immutable
class BleScannerState {
const BleScannerState({
@required this.discoveredDevices,
@required this.scanIsInProgress,
required this.discoveredDevices,
required this.scanIsInProgress,
});

final List<DiscoveredDevice> discoveredDevices;
Expand Down
Loading

0 comments on commit c035b78

Please sign in to comment.