feat: connect to ESense via AlertDialog

This commit is contained in:
Orangerot 2025-01-06 19:21:36 +01:00
parent acebb2431c
commit 36e859d2fe
4 changed files with 197 additions and 1 deletions

View file

@ -1,4 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The following permission is related to the eSense library -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<application <application
android:label="sense_the_rhythm" android:label="sense_the_rhythm"
android:name="${applicationName}" android:name="${applicationName}"

View file

@ -1,7 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'package:esense_flutter/esense.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'level.dart'; import 'level.dart';
@ -17,12 +19,85 @@ class _LevelSelectionState extends State<LevelSelection> {
String? stepmaniaCoursesPath; String? stepmaniaCoursesPath;
List<FileSystemEntity> stepmaniaCoursesFolders = []; List<FileSystemEntity> stepmaniaCoursesFolders = [];
ESenseManager? eSenseManager;
String _deviceStatus = '';
String eSenseDeviceName = '';
bool connected = false;
bool sampling = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadFolderPath(); loadFolderPath();
} }
Future<void> _askForPermissions() async {
if (!(await Permission.bluetoothScan.request().isGranted &&
await Permission.bluetoothConnect.request().isGranted)) {
print(
'WARNING - no permission to use Bluetooth granted. Cannot access eSense device.');
}
// for some strange reason, Android requires permission to location for Bluetooth to work.....?
if (Platform.isAndroid) {
if (!(await Permission.locationWhenInUse.request().isGranted)) {
print(
'WARNING - no permission to access location granted. Cannot access eSense device.');
}
}
}
Future<void> _listenToESense() async {
await _askForPermissions();
// if you want to get the connection events when connecting,
// set up the listener BEFORE connecting...
eSenseManager!.connectionEvents.listen((event) {
print('CONNECTION event: $event');
// when we're connected to the eSense device, we can start listening to events from it
// if (event.type == ConnectionType.connected) _listenToESenseEvents();
setState(() {
connected = false;
switch (event.type) {
case ConnectionType.connected:
_deviceStatus = 'connected';
connected = true;
break;
case ConnectionType.unknown:
_deviceStatus = 'unknown';
break;
case ConnectionType.disconnected:
_deviceStatus = 'disconnected';
sampling = false;
break;
case ConnectionType.device_found:
_deviceStatus = 'device_found';
break;
case ConnectionType.device_not_found:
_deviceStatus = 'device_not_found';
break;
}
});
});
}
Future<void> _connectToESense() async {
if (!connected) {
await _askForPermissions();
print('Trying to connect to eSense device...');
print(eSenseDeviceName);
eSenseManager = ESenseManager(eSenseDeviceName);
connected = await eSenseManager!.connect();
print('success!');
setState(() {
_deviceStatus = connected ? 'connecting...' : 'connection failed';
});
_listenToESense();
}
}
Future<void> loadFolderPath() async { Future<void> loadFolderPath() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
final String? stepmaniaCoursesPathSetting = final String? stepmaniaCoursesPathSetting =
@ -68,7 +143,52 @@ class _LevelSelectionState extends State<LevelSelection> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Sense the Rhythm')), appBar: AppBar(
title: const Text('Sense the Rhythm'),
actions: [
IconButton(
onPressed: () => showDialog<String>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Connect to ESense'),
content: StatefulBuilder(builder:
(BuildContext context, StateSetter setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
onChanged: (input) {
setState(() {
eSenseDeviceName = input;
});
},
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'eSense-xxxx',
labelText: 'Device name',
),
),
Text(eSenseDeviceName),
Text(_deviceStatus)
]);
}),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Discard'),
),
TextButton(
onPressed: () => _connectToESense(),
child: const Text('Connect'),
),
],
);
},
),
icon: const Icon(Icons.bluetooth))
],
),
body: Builder(builder: (context) { body: Builder(builder: (context) {
if (stepmaniaCoursesPath == null) { if (stepmaniaCoursesPath == null) {
return Text('Add a Directory with Stepmania Songs on \'+\''); return Text('Add a Directory with Stepmania Songs on \'+\'');

View file

@ -121,6 +121,15 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.8"
esense_flutter:
dependency: "direct main"
description:
path: "packages/esense_flutter"
ref: master
resolved-ref: "3784963fcdeaebc4e81679dc331e3f195ecd1c42"
url: "https://github.com/cph-cachet/flutter-plugins.git"
source: git
version: "1.0.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -320,6 +329,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.3.0"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
url: "https://pub.dev"
source: hosted
version: "11.3.1"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: "71bbecfee799e65aff7c744761a57e817e73b738fedf62ab7afd5593da21f9f1"
url: "https://pub.dev"
source: hosted
version: "12.0.13"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0
url: "https://pub.dev"
source: hosted
version: "9.4.5"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
url: "https://pub.dev"
source: hosted
version: "0.1.3+5"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: e9c8eadee926c4532d0305dff94b85bf961f16759c3af791486613152af4b4f9
url: "https://pub.dev"
source: hosted
version: "4.2.3"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
platform: platform:
dependency: transitive dependency: transitive
description: description:

View file

@ -14,6 +14,12 @@ dependencies:
shared_preferences: ^2.3.4 shared_preferences: ^2.3.4
file_picker: ^8.1.6 file_picker: ^8.1.6
audioplayers: ^6.1.0 audioplayers: ^6.1.0
esense_flutter:
git:
url: https://github.com/cph-cachet/flutter-plugins.git
ref: master
path: packages/esense_flutter/
permission_handler: ^11.3.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: