Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 33
compileSdkVersion 34

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand All @@ -45,7 +45,7 @@ android {
defaultConfig {
applicationId "com.signify.hue.reactivebleexample"
minSdkVersion 21
targetSdkVersion 33
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
Expand Down
2 changes: 1 addition & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:8.0.2'
classpath 'com.android.tools.build:gradle:8.7.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
5 changes: 3 additions & 2 deletions example/android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
3 changes: 3 additions & 0 deletions example/devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
6 changes: 2 additions & 4 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
classes = {
};
objectVersion = 54;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -169,7 +168,6 @@
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 29DK8LS8B3;
LastSwiftMigration = 0910;
};
};
Expand Down Expand Up @@ -431,7 +429,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 29DK8LS8B3;
DEVELOPMENT_TEAM = 5KK9N97KX3;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -446,7 +444,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.signify.hue.reactivebleExample;
PRODUCT_BUNDLE_IDENTIFIER = com.signify.hue.tangoReactiveBleExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand Down
8 changes: 8 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_device_bond_monitor.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';
Expand All @@ -19,8 +20,10 @@ void main() {
final _bleLogger = BleLogger(ble: _ble);
final _scanner = BleScanner(ble: _ble, logMessage: _bleLogger.addToLog);
final _monitor = BleStatusMonitor(_ble);
final _bondMonitor = BleDeviceBondMonitor(_ble);
final _connector = BleDeviceConnector(
ble: _ble,
bondMonitor: _bondMonitor,
logMessage: _bleLogger.addToLog,
);
final _serviceDiscoverer = BleDeviceInteractor(
Expand All @@ -39,6 +42,7 @@ void main() {
Provider.value(value: _connector),
Provider.value(value: _serviceDiscoverer),
Provider.value(value: _bleLogger),
Provider.value(value: _bondMonitor),
StreamProvider<BleScannerState?>(
create: (_) => _scanner.state,
initialData: const BleScannerState(
Expand All @@ -50,6 +54,10 @@ void main() {
create: (_) => _monitor.state,
initialData: BleStatus.unknown,
),
StreamProvider<DeviceBondState>(
create: (_) => _bondMonitor.state,
initialData: DeviceBondState.unknown,
),
StreamProvider<ConnectionStateUpdate>(
create: (_) => _connector.state,
initialData: const ConnectionStateUpdate(
Expand Down
34 changes: 34 additions & 0 deletions example/lib/src/ble/ble_device_bond_monitor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'dart:async';

import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_reactive_ble_example/src/ble/reactive_state.dart';

class BleDeviceBondMonitor implements ReactiveState<DeviceBondState> {
BleDeviceBondMonitor(this._ble);

final FlutterReactiveBle _ble;

@override
Stream<DeviceBondState> get state => _bondStateController.stream;

final StreamController<DeviceBondState> _bondStateController =
StreamController();

StreamSubscription<DeviceBondState>? _bondStateSubscription;

void startMonitoringDevice(String deviceId) {
_bondStateSubscription ??= _ble.bondUpdateStream
.where((update) => update.deviceId == deviceId)
.map((update) => update.bondState)
.listen(_bondStateController.add);
}

void stopMontoringDevice(String deviceId) {
_bondStateSubscription?.cancel();
_bondStateSubscription = null;
}

Future<void> dispose() async {
await _bondStateController.close();
}
}
8 changes: 8 additions & 0 deletions example/lib/src/ble/ble_device_connector.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import 'dart:async';

import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_device_bond_monitor.dart';
import 'package:flutter_reactive_ble_example/src/ble/reactive_state.dart';

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

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

@override
Expand All @@ -22,6 +26,8 @@ class BleDeviceConnector extends ReactiveState<ConnectionStateUpdate> {
late StreamSubscription<ConnectionStateUpdate> _connection;

Future<void> connect(String deviceId) async {
_bondMonitor.startMonitoringDevice(deviceId);

_logMessage('Start connecting to $deviceId');
_connection = _ble.connectToDevice(id: deviceId).listen(
(update) {
Expand All @@ -35,6 +41,8 @@ class BleDeviceConnector extends ReactiveState<ConnectionStateUpdate> {
}

Future<void> disconnect(String deviceId) async {
_bondMonitor.stopMontoringDevice(deviceId);

try {
_logMessage('disconnecting to device: $deviceId');
await _connection.cancel();
Expand Down
50 changes: 37 additions & 13 deletions example/lib/src/ui/device_detail/device_interaction_tab.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ class DeviceInteractionTab extends StatelessWidget {
final DiscoveredDevice device;

@override
Widget build(BuildContext context) => Consumer3<BleDeviceConnector, ConnectionStateUpdate, BleDeviceInteractor>(
builder: (_, deviceConnector, connectionStateUpdate, serviceDiscoverer, __) => _DeviceInteractionTab(
Widget build(BuildContext context) => Consumer4<BleDeviceConnector,
DeviceBondState, ConnectionStateUpdate, BleDeviceInteractor>(
builder: (_, deviceConnector, bondState, connectionStateUpdate,
serviceDiscoverer, __) =>
_DeviceInteractionTab(
viewModel: DeviceInteractionViewModel(
deviceId: device.id,
bondState: bondState,
connectableStatus: device.connectable,
connectionStatus: connectionStateUpdate.connectionState,
deviceConnector: deviceConnector,
discoverServices: () => serviceDiscoverer.discoverServices(device.id),
discoverServices: () =>
serviceDiscoverer.discoverServices(device.id),
readRssi: () => serviceDiscoverer.readRssi(device.id),
),
),
Expand All @@ -40,6 +45,7 @@ class DeviceInteractionViewModel extends $DeviceInteractionViewModel {
const DeviceInteractionViewModel({
required this.deviceId,
required this.connectableStatus,
required this.bondState,
required this.connectionStatus,
required this.deviceConnector,
required this.discoverServices,
Expand All @@ -48,14 +54,16 @@ class DeviceInteractionViewModel extends $DeviceInteractionViewModel {

final String deviceId;
final Connectable connectableStatus;
final DeviceBondState bondState;
final DeviceConnectionState connectionStatus;
final BleDeviceConnector deviceConnector;
final Future<int> Function() readRssi;

@CustomEquality(Ignore())
final Future<List<Service>> Function() discoverServices;

bool get deviceConnected => connectionStatus == DeviceConnectionState.connected;
bool get deviceConnected =>
connectionStatus == DeviceConnectionState.connected;

void connect() {
deviceConnector.connect(deviceId);
Expand Down Expand Up @@ -110,7 +118,8 @@ class _DeviceInteractionTabState extends State<_DeviceInteractionTab> {
delegate: SliverChildListDelegate.fixed(
[
Padding(
padding: const EdgeInsetsDirectional.only(top: 8.0, bottom: 16.0, start: 16.0),
padding: const EdgeInsetsDirectional.only(
top: 8.0, bottom: 16.0, start: 16.0),
child: Text(
"ID: ${widget.viewModel.deviceId}",
style: const TextStyle(fontWeight: FontWeight.bold),
Expand All @@ -137,27 +146,39 @@ class _DeviceInteractionTabState extends State<_DeviceInteractionTab> {
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsetsDirectional.only(start: 16.0),
child: Text(
"Bond status: ${widget.viewModel.bondState}",
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
children: <Widget>[
ElevatedButton(
onPressed: !widget.viewModel.deviceConnected ? widget.viewModel.connect : null,
onPressed: !widget.viewModel.deviceConnected
? widget.viewModel.connect
: null,
child: const Text("Connect"),
),
ElevatedButton(
onPressed: widget.viewModel.deviceConnected ? widget.viewModel.disconnect : null,
onPressed: widget.viewModel.deviceConnected
? widget.viewModel.disconnect
: null,
child: const Text("Disconnect"),
),
ElevatedButton(
onPressed: widget.viewModel.deviceConnected ? discoverServices : null,
onPressed: widget.viewModel.deviceConnected
? discoverServices
: null,
child: const Text("Discover Services"),
),
ElevatedButton(
onPressed: widget.viewModel.deviceConnected
? readRssi
: null,
onPressed:
widget.viewModel.deviceConnected ? readRssi : null,
child: const Text("Get RSSI"),
),
],
Expand Down Expand Up @@ -222,7 +243,8 @@ class _ServiceDiscoveryListState extends State<_ServiceDiscoveryList> {
Widget _characteristicTile(Characteristic characteristic) => ListTile(
onTap: () => showDialog<void>(
context: context,
builder: (context) => CharacteristicInteractionDialog(characteristic: characteristic),
builder: (context) =>
CharacteristicInteractionDialog(characteristic: characteristic),
),
title: Text(
'${characteristic.id}\n(${_characteristicSummary(characteristic)})',
Expand Down Expand Up @@ -253,7 +275,9 @@ class _ServiceDiscoveryListState extends State<_ServiceDiscoveryList> {
),
Column(
mainAxisSize: MainAxisSize.min,
children: service.characteristics.map(_characteristicTile).toList(),
children: service.characteristics
.map(_characteristicTile)
.toList(),
),
],
),
Expand Down
Loading
Loading