Commit 50202d15 authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬

Continuing "Connect to BluetoothLE device" dialog

Need to add checks, need to complete device connect/disconnection, need to hardwire UUID's (I think)
parent 0f093fc4
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-02-12 00:30:36.235783","version":"1.14.7-pre.83"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-02-12 15:05:29.450383","version":"1.14.7-pre.83"}
\ No newline at end of file
import 'dart:async';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:kotlin_flavor/scope_functions.dart';
import 'package:logair_application/platform/wake_service.dart';
class BTLEHandler {
......@@ -21,7 +22,22 @@ class BTLEHandler {
_flutterBlueInstance.startScan(timeout: Duration(seconds: 5));
Future<List<BluetoothDevice>> get connectedDevices => _flutterBlueInstance.connectedDevices;
Stream<List<ScanResult>> get scanResults => _flutterBlueInstance.scanResults;
Future<void> connect() => this._device?.let((it) => it.connect());
Future<void> disconnect() => this._device?.let((it) {
_device = null;
return it.disconnect();
});
String get address => this._device?.let((it) => it.id.toString());
BluetoothDevice _device;
setDevice(BluetoothDevice device) => device?.let((it) => this._device = it);
bool switchState() {
if (started)
_end();
......
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:logair_application/ui/components/slim_list_tile.dart';
class BTLEScanTile extends StatelessWidget {
final ScanResult result;
final VoidCallback onTap;
const BTLEScanTile({Key key, this.result, this.onTap}) : super(key: key);
Widget _title(BuildContext context) {
return SlimListTile(
title: result.device.name,
subtitle: result.device.id.toString(),
);
}
@override
Widget build(BuildContext context) {
return ListTile(
title: _title(context),
onTap: (result.advertisementData.connectable) ? onTap : null,
);
}
}
\ No newline at end of file
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SlimListTile extends StatelessWidget {
final String title;
final String subtitle;
final Color color;
SlimListTile({@required this.title, @required this.subtitle, this.color});
@override
Widget build(BuildContext context) {
return Container(
color: this.color ?? Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
overflow: TextOverflow.fade,
),
Text(
subtitle,
style: Theme.of(context).textTheme.caption,
),
],
),
);
}
}
\ No newline at end of file
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:logair_application/localization/localization.dart';
import 'package:logair_application/platform/bluetooth_le_service.dart';
import 'package:logair_application/ui/components/bt_scan_tile.dart';
import 'package:logair_application/ui/components/slim_list_tile.dart';
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
......@@ -19,10 +23,13 @@ class Device {
}
showBluetoothSelectionDialog(BuildContext context) async {
/// Connected + frequent devices.
SharedPreferences prefs = await SharedPreferences.getInstance();
// TODO Catch BT disabled
List<Device> _frequentDevices = List.from(json.decode((prefs.getString('json') ?? '[ ]')).map((device) => Device(name: device["name"], address: device["address"]))); // await Devices, filter with cached values
BTLEHandler().startScan();
/// Get the previous connections for this device.
SharedPreferences prefs = await SharedPreferences.getInstance();
List<Device> _frequentDevices = List.from(json.decode((prefs.getString('json') ?? '[ {"name": "logair7003", "address": "19:08:10:17:17:1C" } ]')).map((device) => Device(name: device["name"], address: device["address"]))); // await Devices, filter with cached values
print(_frequentDevices);
showDialog(
......@@ -32,38 +39,100 @@ showBluetoothSelectionDialog(BuildContext context) async {
children: <Widget>[
SingleChildScrollView(
padding: EdgeInsets.all(0),
child: Column(
children: <Widget>[
ListTile(
title: Text(InternalLocalization.of(context).bluetoothScanMessage),
dense: true,
trailing: IconButton(
icon: Icon(Icons.refresh),
onPressed: () => BTLEHandler().startScan(),
child: Container(
child: Column(
children: <Widget>[
ListTile(
title: Text(InternalLocalization.of(context).bluetoothScanMessage),
dense: true,
trailing: IconButton(
icon: Icon(Icons.refresh),
onPressed: () => BTLEHandler().startScan(),
),
),
),
Divider(),
ListTile(title: Text("Connected"), dense: true),
/// Currently connected BT Devices.
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 2)).asyncMap((_) => BTLEHandler().connectedDevices),
initialData: [],
builder: (context, snapshot) => Column(
children: snapshot.data.map(
(data) => ListTile(
dense: true,
title: Text(data.name),
subtitle: Text(data.id.toString()),
onTap: () => {
/// Do connect with this device.
print('Pressed ${data.name}')
}
Divider(),
Text("Connected devices"),
/// Currently connected BT Devices.
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 2)).asyncMap((_) => BTLEHandler().connectedDevices),
initialData: [],
builder: (context, snapshot) => Column(
children: snapshot.data.map(
(device) => ListTile(
title: SlimListTile(
title: device.name,
subtitle: device.id.toString(),
color: BTLEHandler().address == device.id.toString() ? Colors.green.shade100.withAlpha(50) : Colors.white
),
onTap: () {
if (BTLEHandler().address == device.id.toString())
BTLEHandler().disconnect();
}
),
).toList(),
),
),
Divider(),
Text("Frequent"),
StreamBuilder<List<ScanResult>>(
stream: BTLEHandler().scanResults.transform(
new StreamTransformer.fromHandlers(
handleData: (List<ScanResult> list, EventSink<List<ScanResult>> sink) =>
sink.add(list.where((result) => _frequentDevices.map((Device d) => d.address).contains(result.device.id.toString())).toList())
)
),
initialData: [],
builder: (context, snapshot) => Column(
children: (snapshot.data.length > 0) ?
snapshot.data.map(
(data) => BTLEScanTile(
result: data,
onTap: () {
BTLEHandler().setDevice(data.device);
BTLEHandler().connect();
Navigator.of(context).pop();
}
),
).toList() : <Widget>[
Text(
"None",
style: Theme.of(context).textTheme.caption,
)
],
)
),
Divider(),
Text("Available"),
StreamBuilder<List<ScanResult>>(
stream: BTLEHandler().scanResults.transform(
new StreamTransformer.fromHandlers(
handleData: (List<ScanResult> list, EventSink<List<ScanResult>> sink) =>
sink.add(list.where((result) => !_frequentDevices.map((Device d) => d.address).contains(result.device.id.toString()) && result.device.name.length > 0).toList())
)
).toList(),
)
)
],
)
),
initialData: [],
builder: (context, snapshot) => Column(
children: (snapshot.data.length > 0) ?
snapshot.data.map(
(data) => BTLEScanTile(
result: data,
onTap: () {
BTLEHandler().setDevice(data.device);
BTLEHandler().connect();
Navigator.of(context).pop();
}
),
).toList() : <Widget>[
Text(
"None",
style: Theme.of(context).textTheme.caption,
)
],
)
),
],
),
),
)
],
);
......
import 'package:flutter/material.dart';
import 'package:logair_application/localization/localization.dart';
import 'package:permission_handler/permission_handler.dart';
// TODO INTERNATIONALIZE
class PermissionDialog extends StatelessWidget {
final String title;
final String dialogText;
final PermissionGroup permissionGroup;
const PermissionDialog({Key key, @required this.title, this.dialogText, @required this.permissionGroup}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title),
content: Text(dialogText),
actions: <Widget>[
SimpleDialogOption(
child: Text('NO'),
onPressed: () => Navigator.of(context).pop(false),
),
SimpleDialogOption(
child: Text("YES"),
onPressed: () => Navigator.of(context).pop(true),
),
],
);
}
import 'package:flutter/material.dart';
import 'package:logair_application/localization/localization.dart';
import 'package:permission_handler/permission_handler.dart';
// TODO INTERNATIONALIZE
class PermissionDialog extends StatelessWidget {
final String title;
final String dialogText;
final PermissionGroup permissionGroup;
const PermissionDialog({Key key, @required this.title, this.dialogText, @required this.permissionGroup}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title),
content: Text(dialogText),
actions: <Widget>[
SimpleDialogOption(
child: Text('NO'),
onPressed: () => Navigator.of(context).pop(false),
),
SimpleDialogOption(
child: Text("YES"),
onPressed: () => Navigator.of(context).pop(true),
),
],
);
}
}
\ No newline at end of file
......@@ -247,6 +247,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.1+1"
kotlin_flavor:
dependency: "direct main"
description:
name: kotlin_flavor
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
latlong:
dependency: transitive
description:
......
......@@ -23,6 +23,7 @@ dependencies:
permission_handler: ^4.2.0+hotfix.3
get_it: ^3.1.0
shared_preferences: ^0.4.3
kotlin_flavor: ^0.1.0
intl_translation: ^0.17.9
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment