Skip to content

Commit

Permalink
[Untested] EarGear Mic Trigger
Browse files Browse the repository at this point in the history
  • Loading branch information
Codel1417 committed Feb 29, 2024
1 parent b190208 commit 19442e5
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
78 changes: 78 additions & 0 deletions lib/Backend/Sensors.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_android_volume_keydown/flutter_android_volume_keydown.dart';
import 'package:flutter_nearby_connections/flutter_nearby_connections.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive/hive.dart';
import 'package:logging_flutter/logging_flutter.dart';
Expand All @@ -14,6 +17,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:sentry_hive/sentry_hive.dart';
import 'package:shake/shake.dart';
import 'package:tail_app/Backend/ActionRegistry.dart';
import 'package:tail_app/Backend/Bluetooth/btMessage.dart';

import '../Frontend/intnDefs.dart';
import 'Bluetooth/BluetoothManager.dart';
Expand Down Expand Up @@ -214,6 +218,80 @@ class CoverTriggerDefinition extends TriggerDefinition {
}
}

class EarMicTriggerDefinition extends TriggerDefinition {
List<StreamSubscription<List<int>>?> rxSubscriptions = [];
ProviderSubscription<Map<String, BaseStatefulDevice>>? deviceRefSubscription;

EarMicTriggerDefinition(super.ref) {
super.name = triggerEarMicTitle();
super.description = triggerEarMicDescription();
super.icon = const Icon(Icons.mic);
super.requiredPermission = null;
super.actionTypes = [
TriggerActionDef("Sound", triggerEarMicSound(), "839d8978-7b77-4ccb-b23f-28144bf95453"),
];
}

@override
Future<void> onDisable() async {
deviceRefSubscription?.close();
ref.read(knownDevicesProvider).values.where((element) => element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.deviceConnectionState.removeListener(onDeviceConnected);
});
for (var element in rxSubscriptions) {
element?.cancel();
}
ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == DeviceConnectionState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.commandQueue.addCommand(BluetoothMessage.response("ENDLISTEN", element, Priority.normal, "LISTEN OFF"));
});
}

@override
Future<void> onEnable(Set<TriggerAction> actions, Set<DeviceType> deviceType) async {
ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == DeviceConnectionState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.commandQueue.addCommand(BluetoothMessage("LISTEN FULL", element, Priority.normal));
});
//add listeners on new device paired
deviceRefSubscription = ref.listen(knownDevicesProvider, (previous, next) {
onDeviceConnected();
});
}

Future<void> onDeviceConnected() async {
ref.read(knownDevicesProvider).values.where((element) => element.baseDeviceDefinition.deviceType == DeviceType.ears).map((e) {
e.deviceConnectionState.removeListener(onDeviceConnected);
e.deviceConnectionState.addListener(onDeviceConnected);
});
listen();
}

Future<void> listen() async {
//cancel old subscriptions
if (rxSubscriptions.isNotEmpty) {
for (var element in rxSubscriptions) {
element?.cancel();
}
}
//Store the current streams to keep them open
rxSubscriptions = ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == DeviceConnectionState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).map(
(element) {
element.commandQueue.addCommand(BluetoothMessage("LISTEN FULL", element, Priority.normal));
return element.rxCharacteristicStream?.listen(
(event) {
String msg = const Utf8Decoder().convert(event);
if (msg.contains("LISTEN_FULL BANG")) {
// we don't store the actions in class as multiple Triggers can exist, so go get them. This is only necessary when the action is dependent on gear being available
ref.read(triggerListProvider).where((element) => element.triggerDefinition == this && element.enabled).map((e) => e.actions).flattened.where((e) => actionTypes.firstWhere((element) => element.name == "Sound").uuid == e.uuid).forEach(
(element) => sendCommands(ref.read(triggerListProvider).where((element) => element.triggerDefinition == this && element.enabled).map((e) => e.deviceType).flattened.toSet(), element.action, ref),
);
}
},
);
},
).toList();
}
}

class VolumeButtonTriggerDefinition extends TriggerDefinition {
StreamSubscription<HardwareButton>? subscription;

Expand Down
6 changes: 6 additions & 0 deletions lib/Frontend/intnDefs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,9 @@ String triggerProximityTitle() => Intl.message("Nearby Gear", name: 'triggerProx
String triggerProximityDescription() => Intl.message("Trigger an action if gear is nearby", name: 'triggerProximityDescription', desc: 'Proximity trigger description');

String triggerActionNotSet() => Intl.message("No Action Set", name: 'triggerActionNotSet', desc: 'Trigger action label when no action set');

String triggerEarMicTitle() => Intl.message("EarGear Mic", name: 'triggerEarMicTitle', desc: 'EarGear internal mic trigger title');

String triggerEarMicDescription() => Intl.message("Trigger an action when EarGear detects sound", name: 'triggerEarMicDescription', desc: 'EarGear internal mic trigger description');

String triggerEarMicSound() => Intl.message("Sound Detected", name: 'triggerEarMicSound', desc: 'EarGear internal mic trigger sound detected action label');

0 comments on commit 19442e5

Please sign in to comment.