diff options
| -rw-r--r-- | android/app/src/main/AndroidManifest.xml | 13 | ||||
| -rw-r--r-- | lib/level_selection.dart | 122 | ||||
| -rw-r--r-- | pubspec.lock | 57 | ||||
| -rw-r--r-- | pubspec.yaml | 6 | 
4 files changed, 197 insertions, 1 deletions
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 56d0153..1499c1a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,17 @@  <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          android:label="sense_the_rhythm"          android:name="${applicationName}" diff --git a/lib/level_selection.dart b/lib/level_selection.dart index e2cdcbe..5ba7a21 100644 --- a/lib/level_selection.dart +++ b/lib/level_selection.dart @@ -1,7 +1,9 @@  import 'dart:io'; +import 'package:esense_flutter/esense.dart';  import 'package:file_picker/file_picker.dart';  import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart';  import 'package:shared_preferences/shared_preferences.dart';  import 'level.dart'; @@ -17,12 +19,85 @@ class _LevelSelectionState extends State<LevelSelection> {    String? stepmaniaCoursesPath;    List<FileSystemEntity> stepmaniaCoursesFolders = []; +  ESenseManager? eSenseManager; +  String _deviceStatus = ''; +  String eSenseDeviceName = ''; +  bool connected = false; +  bool sampling = false; +    @override    void initState() {      super.initState();      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 {      SharedPreferences prefs = await SharedPreferences.getInstance();      final String? stepmaniaCoursesPathSetting = @@ -68,7 +143,52 @@ class _LevelSelectionState extends State<LevelSelection> {    @override    Widget build(BuildContext context) {      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) {          if (stepmaniaCoursesPath == null) {            return Text('Add a Directory with Stepmania Songs on \'+\''); diff --git a/pubspec.lock b/pubspec.lock index 553fa2e..62488a6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -121,6 +121,15 @@ packages:        url: "https://pub.dev"      source: hosted      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:      dependency: transitive      description: @@ -320,6 +329,54 @@ packages:        url: "https://pub.dev"      source: hosted      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:      dependency: transitive      description: diff --git a/pubspec.yaml b/pubspec.yaml index c42d0a3..77e9319 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,6 +14,12 @@ dependencies:    shared_preferences: ^2.3.4    file_picker: ^8.1.6    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:    flutter_test:  | 
