Skip to content

Commit

Permalink
[Example] add carrot icon to Characteristic to make it clear it can b…
Browse files Browse the repository at this point in the history
…e clicked
  • Loading branch information
chipweinberger committed Jul 23, 2023
1 parent d877e5b commit 0a339ff
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 72 deletions.
4 changes: 2 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ class DeviceScreen extends StatelessWidget {
builder: (c, snapshot) => IndexedStack(
index: snapshot.data! ? 1 : 0,
children: <Widget>[
IconButton(
icon: const Icon(Icons.refresh),
TextButton(
child: const Text("Discover Services"),
onPressed: () async {
try {
await device.discoverServices();
Expand Down
135 changes: 65 additions & 70 deletions example/lib/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

class ScanResultTile extends StatelessWidget {
const ScanResultTile({Key? key, required this.result, this.onTap})
: super(key: key);
const ScanResultTile({Key? key, required this.result, this.onTap}) : super(key: key);

final ScanResult result;
final VoidCallback? onTap;
Expand Down Expand Up @@ -46,10 +45,7 @@ class ScanResultTile extends StatelessWidget {
Expanded(
child: Text(
value,
style: Theme.of(context)
.textTheme
.bodySmall
?.apply(color: Colors.black),
style: Theme.of(context).textTheme.bodySmall?.apply(color: Colors.black),
softWrap: true,
),
),
Expand All @@ -59,8 +55,7 @@ class ScanResultTile extends StatelessWidget {
}

String getNiceHexArray(List<int> bytes) {
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
.toUpperCase();
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'.toUpperCase();
}

String getNiceManufacturerData(Map<int, List<int>> data) {
Expand All @@ -69,8 +64,7 @@ class ScanResultTile extends StatelessWidget {
}
List<String> res = [];
data.forEach((id, bytes) {
res.add(
'${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
res.add('${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
});
return res.join(', ');
}
Expand Down Expand Up @@ -100,20 +94,16 @@ class ScanResultTile extends StatelessWidget {
onPressed: (result.advertisementData.connectable) ? onTap : null,
),
children: <Widget>[
_buildAdvRow(
context, 'Complete Local Name', result.advertisementData.localName),
_buildAdvRow(context, 'Tx Power Level',
'${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(context, 'Manufacturer Data',
getNiceManufacturerData(result.advertisementData.manufacturerData)),
_buildAdvRow(context, 'Complete Local Name', result.advertisementData.localName),
_buildAdvRow(context, 'Tx Power Level', '${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(context, 'Manufacturer Data', getNiceManufacturerData(result.advertisementData.manufacturerData)),
_buildAdvRow(
context,
'Service UUIDs',
(result.advertisementData.serviceUuids.isNotEmpty)
? result.advertisementData.serviceUuids.join(', ').toUpperCase()
: 'N/A'),
_buildAdvRow(context, 'Service Data',
getNiceServiceData(result.advertisementData.serviceData)),
_buildAdvRow(context, 'Service Data', getNiceServiceData(result.advertisementData.serviceData)),
],
);
}
Expand All @@ -123,9 +113,7 @@ class ServiceTile extends StatelessWidget {
final BluetoothService service;
final List<CharacteristicTile> characteristicTiles;

const ServiceTile(
{Key? key, required this.service, required this.characteristicTiles})
: super(key: key);
const ServiceTile({Key? key, required this.service, required this.characteristicTiles}) : super(key: key);

@override
Widget build(BuildContext context) {
Expand All @@ -137,23 +125,24 @@ class ServiceTile extends StatelessWidget {
children: <Widget>[
const Text('Service'),
Text('0x${service.serviceUuid.toString().toUpperCase()}',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).textTheme.bodySmall?.color))
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(color: Theme.of(context).textTheme.bodySmall?.color))
],
),
children: characteristicTiles,
);
} else {
return ListTile(
title: const Text('Service'),
subtitle:
Text('0x${service.serviceUuid.toString().toUpperCase()}'),
subtitle: Text('0x${service.serviceUuid.toString().toUpperCase()}'),
);
}
}
}

class CharacteristicTile extends StatelessWidget {
class CharacteristicTile extends StatefulWidget {
final BluetoothCharacteristic characteristic;
final List<DescriptorTile> descriptorTiles;
final VoidCallback? onReadPressed;
Expand All @@ -169,54 +158,65 @@ class CharacteristicTile extends StatelessWidget {
this.onNotificationPressed})
: super(key: key);

@override
State<CharacteristicTile> createState() => _CharacteristicTileState();
}

class _CharacteristicTileState extends State<CharacteristicTile> {
@override
Widget build(BuildContext context) {
return StreamBuilder<List<int>>(
stream: characteristic.lastValueStream,
initialData: characteristic.lastValue,
stream: widget.characteristic.lastValueStream,
initialData: widget.characteristic.lastValue,
builder: (c, snapshot) {
final value = snapshot.data;
return ExpansionTile(
title: ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Characteristic'),
Text(
'0x${characteristic.characteristicUuid.toString().toUpperCase()}',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).textTheme.bodySmall?.color))
title: Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Characteristic'),
Text('0x${widget.characteristic.characteristicUuid.toString().toUpperCase()}',
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(color: Theme.of(context).textTheme.bodySmall?.color))
],
),
Spacer(),
if (widget.characteristic.properties.read)
IconButton(
icon: Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
),
onPressed: () {
widget.onReadPressed!();
setState(() {});
}),
if (widget.characteristic.properties.write)
IconButton(
icon: Icon(Icons.file_upload, color: Theme.of(context).iconTheme.color?.withOpacity(0.5)),
onPressed: () {
widget.onWritePressed!();
setState(() {});
}),
if (widget.characteristic.properties.notify || widget.characteristic.properties.indicate)
TextButton(
child: Text(widget.characteristic.isNotifying ? "Unsubscribe" : "Subscribe"),
onPressed: () {
widget.onNotificationPressed!();
setState(() {});
})
],
),
subtitle: Text(value.toString()),
contentPadding: const EdgeInsets.all(0.0),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (characteristic.properties.read)
IconButton(
icon: Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
),
onPressed: onReadPressed,
),
if (characteristic.properties.write)
IconButton(
icon: Icon(Icons.file_upload,
color: Theme.of(context).iconTheme.color?.withOpacity(0.5)),
onPressed: onWritePressed,
),
if (characteristic.properties.notify || characteristic.properties.indicate)
TextButton(
child: Text(characteristic.isNotifying ? "Unsubscribe" : "Subscribe"),
onPressed: onNotificationPressed,
)
],
),
children: descriptorTiles,
children: widget.descriptorTiles,
);
},
);
Expand All @@ -228,12 +228,7 @@ class DescriptorTile extends StatelessWidget {
final VoidCallback? onReadPressed;
final VoidCallback? onWritePressed;

const DescriptorTile(
{Key? key,
required this.descriptor,
this.onReadPressed,
this.onWritePressed})
: super(key: key);
const DescriptorTile({Key? key, required this.descriptor, this.onReadPressed, this.onWritePressed}) : super(key: key);

@override
Widget build(BuildContext context) {
Expand All @@ -244,8 +239,8 @@ class DescriptorTile extends StatelessWidget {
children: <Widget>[
const Text('Descriptor'),
Text('0x${descriptor.descriptorUuid.toString().toUpperCase()}',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).textTheme.bodySmall?.color))
style:
Theme.of(context).textTheme.bodyLarge?.copyWith(color: Theme.of(context).textTheme.bodySmall?.color))
],
),
subtitle: StreamBuilder<List<int>>(
Expand Down

0 comments on commit 0a339ff

Please sign in to comment.