Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 5 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ void main() {
ble: _ble,
logMessage: _bleLogger.addToLog,
);
final _serviceDiscoverer = BleServiceDiscoverer(
final _serviceDiscoverer = BleDeviceInteractor(
bleDiscoverServices: _ble.discoverServices,
readCharacteristic: _ble.readCharacteristic,
writeWithResponse: _ble.writeCharacteristicWithResponse,
writeWithOutResponse: _ble.writeCharacteristicWithoutResponse,
subscribeToCharacteristic: _ble.subscribeToCharacteristic,
logMessage: _bleLogger.addToLog,
);
runApp(
Expand Down
82 changes: 80 additions & 2 deletions example/lib/src/ble/ble_device_interactor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,43 @@ import 'dart:async';

import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';

class BleServiceDiscoverer {
BleServiceDiscoverer({
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 {
Expand All @@ -26,4 +52,56 @@ class BleServiceDiscoverer {
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);
}
}
2 changes: 1 addition & 1 deletion example/lib/src/ble/ble_logger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:intl/intl.dart';

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

List<String> get messages => _logMessages;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_reactive_ble_example/src/ble/ble_device_interactor.dart';
import 'package:provider/provider.dart';

class CharacteristicInteractionDialog extends StatelessWidget {
const CharacteristicInteractionDialog({
required this.characteristic,
Key? key,
}) : super(key: key);
final QualifiedCharacteristic characteristic;

@override
Widget build(BuildContext context) {
return Consumer<BleDeviceInteractor>(builder: (context, interactor, _) {
return _CharacteristicInteractionDialog(
characteristic: characteristic,
readCharacteristic: interactor.readCharacteristic,
writeWithResponse: interactor.writeCharacterisiticWithResponse,
writeWithoutResponse: interactor.writeCharacterisiticWithoutResponse,
subscribeToCharacteristic: interactor.subScribeToCharacteristic,
);
});
}
}

class _CharacteristicInteractionDialog extends StatefulWidget {
const _CharacteristicInteractionDialog({
required this.characteristic,
required this.readCharacteristic,
required this.writeWithResponse,
required this.writeWithoutResponse,
required this.subscribeToCharacteristic,
Key? key,
}) : super(key: key);

final QualifiedCharacteristic characteristic;
final Future<List<int>> Function(QualifiedCharacteristic characteristic)
readCharacteristic;
final Future<void> Function(
QualifiedCharacteristic characteristic, List<int> value)
writeWithResponse;

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

final Future<void> Function(
QualifiedCharacteristic characteristic, List<int> value)
writeWithoutResponse;

@override
_CharacteristicInteractionDialogState createState() =>
_CharacteristicInteractionDialogState();
}

class _CharacteristicInteractionDialogState
extends State<_CharacteristicInteractionDialog> {
late String readOutput;
late String writeOutput;
late String subscribeOutput;
late TextEditingController textEditingController;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, I didn't know about this new keyword late 👍

Stream<List<int>?>? subScribeStream;

@override
void initState() {
readOutput = '';
writeOutput = '';
subscribeOutput = '';
textEditingController = TextEditingController();
super.initState();
}

Future<void> subscribeCharacteristic() async {
subScribeStream = widget.subscribeToCharacteristic(widget.characteristic);
setState(() {
subscribeOutput = 'Done';
});
}

Future<void> readCharacteristic() async {
final result = await widget.readCharacteristic(widget.characteristic);
setState(() {
readOutput = result.toString();
});
}

List<int> _parseInput() {
return textEditingController.text
.split(',')
.map(
(value) => int.parse(value),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it clear in UI that this is a decimal number input?

)
.toList();
}

Future<void> writeCharacteristicWithResponse() async {
await widget.writeWithResponse(widget.characteristic, _parseInput());
setState(() {
writeOutput = 'Ok';
});
}

Future<void> writeCharacteristicWithoutResponse() async {
await widget.writeWithoutResponse(widget.characteristic, _parseInput());
setState(() {
writeOutput = 'Done';
});
}

@override
Widget build(BuildContext context) {
return Dialog(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 14.0),
child: Text(
'Characteristic: ${widget.characteristic.characteristicId}',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
Row(
children: [
ElevatedButton(
onPressed: readCharacteristic,
child: Text('Read'),
),
Padding(
padding: const EdgeInsetsDirectional.only(start: 14.0),
child: Text('Output: $readOutput'),
),
],
),
Divider(
thickness: 2.0,
),
TextField(
controller: textEditingController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Value',
),
),
Row(
children: [
ElevatedButton(
onPressed: writeCharacteristicWithResponse,
child: Text('Write with response'),
),
Padding(
padding: const EdgeInsetsDirectional.only(start: 14.0),
child: Text('Output: $writeOutput'),
),
],
),
ElevatedButton(
onPressed: writeCharacteristicWithoutResponse,
child: Text('Write without response'),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 14.0),
child: Text(
'Characteristic: ${widget.characteristic.characteristicId}',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
ElevatedButton(
onPressed: subscribeCharacteristic,
child: Text('Subscribe/notify'),
),
StreamBuilder<List<int>?>(
stream: subScribeStream,
builder: (context, value) {
return Padding(
padding: const EdgeInsetsDirectional.only(start: 14.0),
child: Text('Output: $value'),
);
}),
Divider(
thickness: 2.0,
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('close')),
),
)
],
),
),
);
}
}
Loading