Skip to content

Commit

Permalink
Initial animations, more localization,
Browse files Browse the repository at this point in the history
lock dev menu behind dev build
  • Loading branch information
Codel1417 committed Jan 28, 2024
1 parent fd335d0 commit 03b9ae5
Show file tree
Hide file tree
Showing 25 changed files with 838 additions and 356 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
android {
compileSdkVersion 33
compileSdkVersion 34
ndkVersion flutter.ndkVersion

compileOptions {
Expand Down
22 changes: 22 additions & 0 deletions lib/Backend/ActionRegistry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,25 @@ Map<ActionCategory, Set<BaseAction>> getAvailableActions(GetAvailableActionsRef
}
return sortedActions;
}

@Riverpod(dependencies: [KnownDevices])
Map<ActionCategory, Set<BaseAction>> getAllActions(GetAllActionsRef ref, Set<DeviceType> deviceType) {
Map<ActionCategory, Set<BaseAction>> sortedActions = {};
for (BaseAction baseAction in List.from(ActionRegistry.allCommands)..addAll(ref.read(moveListsProvider))) {
Set<BaseAction>? baseActions = {};
// check if command matches device type
if (baseAction.deviceCategory.intersection(deviceType).isNotEmpty) {
// get category if it exists
if (sortedActions.containsKey(baseAction.actionCategory)) {
baseActions = sortedActions[baseAction.actionCategory];
}
// add action to category
baseActions?.add(baseAction);
}
// store result
if (baseActions != null && baseActions.isNotEmpty) {
sortedActions[baseAction.actionCategory] = baseActions;
}
}
return sortedActions;
}
2 changes: 1 addition & 1 deletion lib/Backend/AutoMove.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:tail_app/Backend/Bluetooth/btMessage.dart';
import 'package:tail_app/Backend/Definitions/Device/BaseDeviceDefinition.dart';
import 'package:tail_app/Backend/btMessage.dart';

//TODO: call on device connect
void ChangeAutoMove(BaseStatefulDevice device) {
Expand Down
14 changes: 7 additions & 7 deletions lib/Backend/Bluetooth/BluetoothManager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';

import 'package:awesome_snackbar_content/awesome_snackbar_content.dart';
import 'package:collection/collection.dart';
import 'package:cross_platform/cross_platform.dart';
import 'package:flutter_foreground_service/flutter_foreground_service.dart';
Expand All @@ -9,11 +10,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging_flutter/logging_flutter.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:tail_app/Frontend/Widgets/snack_bar_overlay.dart';

import '../../main.dart';
import '../Definitions/Device/BaseDeviceDefinition.dart';
import '../DeviceRegistry.dart';
import '../btMessage.dart';
import 'btMessage.dart';

part 'BluetoothManager.g.dart';

Expand Down Expand Up @@ -145,14 +147,12 @@ class KnownDevices extends _$KnownDevices {
}

@Riverpod(keepAlive: true, dependencies: [reactiveBLE])
StreamSubscription<BleStatus> btStatus(BtStatusRef ref) {
return ref.read(reactiveBLEProvider).statusStream.listen((BleStatus event) {
Flogger.i("BluetoothState::$event"); //TODO: Do something with this
});
Stream<BleStatus> btStatus(BtStatusRef ref) {
return ref.read(reactiveBLEProvider).statusStream;
}

@Riverpod(keepAlive: true, dependencies: [reactiveBLE, KnownDevices])
StreamSubscription<ConnectionStateUpdate> btConnectStatus(BtConnectStatusRef ref) {
StreamSubscription<ConnectionStateUpdate> btConnectStateHandler(BtConnectStateHandlerRef ref) {
return ref.read(reactiveBLEProvider).connectedDeviceStream.listen((ConnectionStateUpdate event) {
Flogger.i("ConnectedDevice::$event");
Map<String, BaseStatefulDevice> knownDevices = ref.watch(knownDevicesProvider);
Expand All @@ -169,7 +169,7 @@ StreamSubscription<ConnectionStateUpdate> btConnectStatus(BtConnectStatusRef ref
knownDevices[event.deviceId]?.rxCharacteristicStream = null;
knownDevices[event.deviceId]?.keepAliveStream = null;
knownDevices[event.deviceId]?.battery.value = 0;

ref.read(snackbarStreamProvider.notifier).add(AwesomeSnackbarContent(title: "Disconnected", message: "Disconnected from ${knownDevices[event.deviceId]?.baseStoredDevice.name}", contentType: ContentType.warning));
//remove foreground service if no devices connected
if (Platform.isAndroid && knownDevices.values.where((element) => element.deviceConnectionState.value == DeviceConnectionState.connected).isEmpty) {
ForegroundService().stop();
Expand Down
File renamed without changes.
91 changes: 46 additions & 45 deletions lib/Backend/Sensors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:proximity_sensor/proximity_sensor.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shake/shake.dart';

import '../Frontend/intnDefs.dart';
import '../main.dart';
import 'Bluetooth/BluetoothManager.dart';
import 'Definitions/Action/BaseAction.dart';
Expand Down Expand Up @@ -67,15 +68,15 @@ class Trigger {
}
}

List<TriggerAction> actions = [];
Map<String, TriggerAction> actions = {}; //TODO: Store action as a string, and find on demand

Trigger(this.triggerDef) {
//actions.addAll(triggerDefinition?.actionTypes.map((e) => TriggerAction(e)));
}

Trigger.trigDef(this.triggerDefinition) {
triggerDef = triggerDefinition!.name;
actions.addAll(triggerDefinition!.actionTypes.map((e) => TriggerAction(e)));
actions.addAll(triggerDefinition!.actionTypes.map((e, f) => MapEntry(e, TriggerAction(f))));
}

factory Trigger.fromJson(Map<String, dynamic> json) => _$TriggerFromJson(json);
Expand All @@ -89,12 +90,12 @@ abstract class TriggerDefinition implements Comparable<TriggerDefinition> {
late Widget icon;
Ref ref;

Future<void> onEnable(List<TriggerAction> actions, Set<DeviceType> deviceType);
Future<void> onEnable(Map<String, TriggerAction> actions, Set<DeviceType> deviceType);

Future<void> onDisable();

Permission? requiredPermission;
late List<String> actionTypes;
late Map<String, String> actionTypes;

TriggerDefinition(this.ref);

Expand All @@ -121,11 +122,11 @@ class WalkingTriggerDefinition extends TriggerDefinition {
Stream<StepCount>? stepCountStream;

WalkingTriggerDefinition(super.ref) {
super.name = "Walking";
super.description = "Trigger an action on walking";
super.name = triggerWalkingTitle();
super.description = triggerWalkingDescription();
super.icon = const Icon(Icons.directions_walk);
super.requiredPermission = Permission.activityRecognition;
super.actionTypes = ["Walking", "Stopped", "Even Step", "Odd Step", "Step"];
super.actionTypes = {"Walking": triggerWalkingTitle(), "Stopped": triggerWalkingStopped(), "Even Step": triggerWalkingEvenStep(), "Odd Step": triggerWalkingOddStep(), "Step": triggerWalkingStep()};
}

@override
Expand All @@ -135,29 +136,29 @@ class WalkingTriggerDefinition extends TriggerDefinition {
}

@override
Future<void> onEnable(List<TriggerAction> actions, Set<DeviceType> deviceType) async {
Future<void> onEnable(Map<String, TriggerAction> actions, Set<DeviceType> deviceType) async {
pedestrianStatusStream = Pedometer.pedestrianStatusStream;
stepCountStream = Pedometer.stepCountStream;
pedestrianStatusStream?.listen((PedestrianStatus event) {
Flogger.i("PedestrianStatus:: ${event.status}");
if (event.status == "Walking") {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Walking");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Walking"];
sendCommands(deviceType, action?.action, ref);
} else if (event.status == "Stopped") {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Stopped");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Stopped"];
sendCommands(deviceType, action?.action, ref);
}
});
stepCountStream?.listen((StepCount event) {
Flogger.d("StepCount:: ${event.steps}");
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Step");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Step"];
sendCommands(deviceType, action?.action, ref);
if (event.steps.isEven) {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Even Step");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Even Step"];
sendCommands(deviceType, action?.action, ref);
} else {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Odd Step");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Odd Step"];
sendCommands(deviceType, action?.action, ref);
}
});
}
Expand All @@ -167,11 +168,11 @@ class CoverTriggerDefinition extends TriggerDefinition {
Stream<int>? proximityStream;

CoverTriggerDefinition(super.ref) {
super.name = "Cover";
super.description = "Trigger an action by covering the proximity sensor";
super.name = triggerCoverTitle();
super.description = triggerCoverDescription();
super.icon = const Icon(Icons.sensors);
super.requiredPermission = null;
super.actionTypes = ["Near", "Far"];
super.actionTypes = {"Near": triggerCoverNear(), "Far": triggerCoverFar()};
}

@override
Expand All @@ -180,16 +181,16 @@ class CoverTriggerDefinition extends TriggerDefinition {
}

@override
Future<void> onEnable(List<TriggerAction> actions, Set<DeviceType> deviceType) async {
Future<void> onEnable(Map<String, TriggerAction> actions, Set<DeviceType> deviceType) async {
proximityStream = ProximitySensor.events;
proximityStream?.listen((int event) {
Flogger.d("CoverEvent:: $event");
if (event >= 1) {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Near");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Near"];
sendCommands(deviceType, action?.action, ref);
} else if (event == 0) {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Far");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Far"];
sendCommands(deviceType, action?.action, ref);
}
});
}
Expand All @@ -199,11 +200,11 @@ class VolumeButtonTriggerDefinition extends TriggerDefinition {
StreamSubscription<HardwareButton>? subscription;

VolumeButtonTriggerDefinition(super.ref) {
super.name = "Volume Buttons";
super.description = "Trigger an action by pressing the volume button";
super.name = triggerVolumeButtonTitle();
super.description = triggerVolumeButtonDescription();
super.icon = const Icon(Icons.volume_up);
super.requiredPermission = null;
super.actionTypes = ["Volume Up", "Volume Down"];
super.actionTypes = {"Volume Up": triggerVolumeButtonVolumeUp(), "Volume Down": triggerVolumeButtonVolumeDown()};
}

@override
Expand All @@ -215,15 +216,15 @@ class VolumeButtonTriggerDefinition extends TriggerDefinition {
}

@override
Future<void> onEnable(List<TriggerAction> actions, Set<DeviceType> deviceType) async {
Future<void> onEnable(Map<String, TriggerAction> actions, Set<DeviceType> deviceType) async {
subscription = FlutterAndroidVolumeKeydown.stream.listen((event) {
Flogger.d("Volume press detected:${event.name}");
if (event == HardwareButton.volume_down) {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Volume Up");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Volume Up"];
sendCommands(deviceType, action?.action, ref);
} else if (event == HardwareButton.volume_up) {
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Volume Down");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Volume Down"];
sendCommands(deviceType, action?.action, ref);
}
});
}
Expand All @@ -233,11 +234,11 @@ class ShakeTriggerDefinition extends TriggerDefinition {
ShakeDetector? detector;

ShakeTriggerDefinition(super.ref) {
super.name = "Shake";
super.name = triggerShakeTitle();
super.description = "Trigger an action by shaking your device";
super.icon = const Icon(Icons.vibration);
super.requiredPermission = null;
super.actionTypes = ["Shake"];
super.actionTypes = {"Shake": triggerShakeTitle()};
}

@override
Expand All @@ -247,11 +248,11 @@ class ShakeTriggerDefinition extends TriggerDefinition {
}

@override
Future<void> onEnable(List<TriggerAction> actions, Set<DeviceType> deviceType) async {
Future<void> onEnable(Map<String, TriggerAction> actions, Set<DeviceType> deviceType) async {
detector = ShakeDetector.waitForStart(onPhoneShake: () {
Flogger.d("Shake Detected");
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Shake");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Shake"];
sendCommands(deviceType, action?.action, ref);
});
detector?.startListening();
}
Expand All @@ -261,11 +262,11 @@ class TailProximityTriggerDefinition extends TriggerDefinition {
Stream<DiscoveredDevice>? btStream;

TailProximityTriggerDefinition(super.ref) {
super.name = "Proximity";
super.description = "Trigger an action if gear is nearby";
super.name = triggerProximityTitle();
super.description = triggerProximityDescription();
super.icon = const Icon(Icons.bluetooth_connected);
super.requiredPermission = Permission.bluetoothScan;
super.actionTypes = ["Nearby Gear"];
super.actionTypes = {"Nearby Gear": triggerProximityTitle()};
}

@override
Expand All @@ -274,12 +275,12 @@ class TailProximityTriggerDefinition extends TriggerDefinition {
}

@override
Future<void> onEnable(List<TriggerAction> actions, Set<DeviceType> deviceType) async {
Future<void> onEnable(Map<String, TriggerAction> actions, Set<DeviceType> deviceType) async {
btStream = ref.read(reactiveBLEProvider).scanForDevices(withServices: DeviceRegistry.getAllIds()).where((event) => !ref.read(knownDevicesProvider).keys.contains(event.id));
btStream?.listen((DiscoveredDevice device) {
Flogger.d("TailProximityTriggerDefinition:: $device");
TriggerAction action = actions.firstWhere((TriggerAction element) => element.name == "Nearby Gear");
sendCommands(deviceType, action.action, ref);
TriggerAction? action = actions["Nearby Gear"];
sendCommands(deviceType, action?.action, ref);
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/moveLists.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:logging_flutter/logging_flutter.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:tail_app/Backend/Bluetooth/btMessage.dart';
import 'package:tail_app/Backend/Definitions/Action/BaseAction.dart';
import 'package:tail_app/Backend/Definitions/Device/BaseDeviceDefinition.dart';
import 'package:tail_app/Backend/btMessage.dart';
import 'package:tail_app/Frontend/intnDefs.dart';

import '../main.dart';
Expand Down
Loading

0 comments on commit 03b9ae5

Please sign in to comment.