123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- // Copyright 2017, Paul DeMarco.
- // All rights reserved. Use of this source code is governed by a
- // BSD-style license that can be found in the LICENSE file.
-
- import 'package:flutter/material.dart';
- import 'package:flutter_blue/flutter_blue.dart';
-
- class ScanResultTile extends StatelessWidget {
- const ScanResultTile({Key key, this.result, this.onTap}) : super(key: key);
-
- final ScanResult result;
- final VoidCallback onTap;
-
- Widget _buildTitle(BuildContext context) {
- if (result.device.name.length > 0) {
- return Column(
- mainAxisAlignment: MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text(result.device.name),
- Text(
- result.device.id.toString(),
- style: Theme.of(context).textTheme.caption,
- )
- ],
- );
- } else {
- return Text(result.device.id.toString());
- }
- }
-
- Widget _buildAdvRow(BuildContext context, String title, String value) {
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text(title, style: Theme.of(context).textTheme.caption),
- SizedBox(
- width: 12.0,
- ),
- Expanded(
- child: Text(
- value,
- style: Theme.of(context)
- .textTheme
- .caption
- .apply(color: Colors.black),
- softWrap: true,
- ),
- ),
- ],
- ),
- );
- }
-
- String getNiceHexArray(List<int> bytes) {
- return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
- .toUpperCase();
- }
-
- String getNiceManufacturerData(Map<int, List<int>> data) {
- if (data.isEmpty) {
- return null;
- }
- List<String> res = [];
- data.forEach((id, bytes) {
- res.add(
- '${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
- });
- return res.join(', ');
- }
-
- String getNiceServiceData(Map<String, List<int>> data) {
- if (data.isEmpty) {
- return null;
- }
- List<String> res = [];
- data.forEach((id, bytes) {
- res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
- });
- return res.join(', ');
- }
-
- @override
- Widget build(BuildContext context) {
- return ExpansionTile(
- title: _buildTitle(context),
- leading: Text(result.rssi.toString()),
- trailing: RaisedButton(
- child: Text('CONNECT'),
- color: Colors.black,
- textColor: Colors.white,
- 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) ??
- 'N/A'),
- _buildAdvRow(
- context,
- 'Service UUIDs',
- (result.advertisementData.serviceUuids.isNotEmpty)
- ? result.advertisementData.serviceUuids.join(', ').toUpperCase()
- : 'N/A'),
- _buildAdvRow(context, 'Service Data',
- getNiceServiceData(result.advertisementData.serviceData) ?? 'N/A'),
- ],
- );
- }
- }
-
- class ServiceTile extends StatelessWidget {
- final BluetoothService service;
- final List<CharacteristicTile> characteristicTiles;
-
- const ServiceTile({Key key, this.service, this.characteristicTiles})
- : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- if (characteristicTiles.length > 0) {
- return new ExpansionTile(
- title: new Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- const Text('Service'),
- new Text(
- '0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
- style: Theme.of(context)
- .textTheme
- .body1
- .copyWith(color: Theme.of(context).textTheme.caption.color))
- ],
- ),
- children: characteristicTiles,
- );
- } else {
- return new ListTile(
- title: const Text('Service'),
- subtitle: new Text(
- '0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
- );
- }
- }
- }
-
- class CharacteristicTile extends StatelessWidget {
- final BluetoothCharacteristic characteristic;
- final List<DescriptorTile> descriptorTiles;
- final VoidCallback onReadPressed;
- final VoidCallback onWritePressed;
- final VoidCallback onNotificationPressed;
-
- const CharacteristicTile(
- {Key key,
- this.characteristic,
- this.descriptorTiles,
- this.onReadPressed,
- this.onWritePressed,
- this.onNotificationPressed})
- : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- var actions = new Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- new IconButton(
- icon: new Icon(
- Icons.file_download,
- color: Theme.of(context).iconTheme.color.withOpacity(0.5),
- ),
- onPressed: onReadPressed,
- ),
- new IconButton(
- icon: new Icon(Icons.file_upload,
- color: Theme.of(context).iconTheme.color.withOpacity(0.5)),
- onPressed: onWritePressed,
- ),
- new IconButton(
- icon: new Icon(
- characteristic.isNotifying ? Icons.sync_disabled : Icons.sync,
- color: Theme.of(context).iconTheme.color.withOpacity(0.5)),
- onPressed: onNotificationPressed,
- )
- ],
- );
-
- var title = new Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- const Text('Characteristic'),
- new Text(
- '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
- style: Theme.of(context)
- .textTheme
- .body1
- .copyWith(color: Theme.of(context).textTheme.caption.color))
- ],
- );
-
- if (descriptorTiles.length > 0) {
- return new ExpansionTile(
- title: new ListTile(
- title: title,
- subtitle: new Text(characteristic.value.toString()),
- contentPadding: EdgeInsets.all(0.0),
- ),
- trailing: actions,
- children: descriptorTiles,
- );
- } else {
- return new ListTile(
- title: title,
- subtitle: new Text(characteristic.value.toString()),
- trailing: actions,
- );
- }
- }
- }
-
- class DescriptorTile extends StatelessWidget {
- final BluetoothDescriptor descriptor;
- final VoidCallback onReadPressed;
- final VoidCallback onWritePressed;
-
- const DescriptorTile(
- {Key key, this.descriptor, this.onReadPressed, this.onWritePressed})
- : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- var title = new Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- const Text('Descriptor'),
- new Text(
- '0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
- style: Theme.of(context)
- .textTheme
- .body1
- .copyWith(color: Theme.of(context).textTheme.caption.color))
- ],
- );
- return new ListTile(
- title: title,
- subtitle: new Text(descriptor.value.toString()),
- trailing: new Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- new IconButton(
- icon: new Icon(
- Icons.file_download,
- color: Theme.of(context).iconTheme.color.withOpacity(0.5),
- ),
- onPressed: onReadPressed,
- ),
- new IconButton(
- icon: new Icon(
- Icons.file_upload,
- color: Theme.of(context).iconTheme.color.withOpacity(0.5),
- ),
- onPressed: onWritePressed,
- )
- ],
- ),
- );
- }
- }
|