Skip to content

Commit d589b01

Browse files
committed
Split moves by device type, merge EG moves, and add RGB
untested with real hardware
1 parent 803987f commit d589b01

File tree

12 files changed

+807
-1392
lines changed

12 files changed

+807
-1392
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
### V 1.3.1
1+
### V 1.4.0
22

3+
- Split moves by gear type
34
- Rework analytics to be more useful
45
- Add CosHub posts to Home UI
56
- Disabled 'Nearby Gear' trigger as it has been broken for awhile. This will hopefully come back in a future release

lib/Backend/Bluetooth/bluetooth_manager_plus.dart

Lines changed: 35 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ class InitFlutterBluePlus extends _$InitFlutterBluePlus {
9696
ref.invalidate(_rSSIChangedProvider);
9797
ref.invalidate(_onScanResultsProvider);
9898
// Mark all gear disconnected;
99-
ref.read(knownDevicesProvider).forEach(
100-
(key, value) => value.deviceConnectionState.value = ConnectivityState.disconnected,
101-
);
99+
ref.read(knownDevicesProvider).forEach((key, value) => value.deviceConnectionState.value = ConnectivityState.disconnected);
102100
isBluetoothEnabled.value = false;
103101
_didInitFlutterBluePlus = false; // Allow restarting ble stack
104102
});
@@ -113,9 +111,7 @@ class _MTUChanged extends _$MTUChanged {
113111
@override
114112
void build() {
115113
streamSubscription = FlutterBluePlus.events.onMtuChanged.listen(listener);
116-
ref.onDispose(
117-
() => streamSubscription?.cancel(),
118-
);
114+
ref.onDispose(() => streamSubscription?.cancel());
119115
}
120116

121117
void listener(OnMtuChangedEvent event) {
@@ -132,18 +128,14 @@ class _OnDiscoveredServices extends _$OnDiscoveredServices {
132128
@override
133129
void build() {
134130
streamSubscription = FlutterBluePlus.events.onDiscoveredServices.listen(listener, onError: (e) => _bluetoothPlusLogger.warning("Unable to discover services: $e", e));
135-
ref.onDispose(
136-
() => streamSubscription?.cancel(),
137-
);
131+
ref.onDispose(() => streamSubscription?.cancel());
138132
}
139133

140134
Future<void> listener(OnDiscoveredServicesEvent event) async {
141135
//_bluetoothPlusLogger.info('${event.device} ${event.services}');
142136
//Subscribes to all characteristics
143137
for (BluetoothService service in event.services) {
144-
BluetoothUartService? bluetoothUartService = uartServices.firstWhereOrNull(
145-
(element) => element.bleDeviceService.toLowerCase() == service.serviceUuid.str128.toLowerCase(),
146-
);
138+
BluetoothUartService? bluetoothUartService = uartServices.firstWhereOrNull((element) => element.bleDeviceService.toLowerCase() == service.serviceUuid.str128.toLowerCase());
147139
if (bluetoothUartService != null) {
148140
BaseStatefulDevice? statefulDevice = ref.read(knownDevicesProvider)[event.device.remoteId.str];
149141
statefulDevice?.bluetoothUartService.value = bluetoothUartService;
@@ -166,9 +158,7 @@ class _RSSIChanged extends _$RSSIChanged {
166158
@override
167159
void build() {
168160
streamSubscription = FlutterBluePlus.events.onReadRssi.listen(listener, onError: (e) => _bluetoothPlusLogger.warning("Unable to read rssi: $e", e));
169-
ref.onDispose(
170-
() => streamSubscription?.cancel(),
171-
);
161+
ref.onDispose(() => streamSubscription?.cancel());
172162
}
173163

174164
void listener(OnReadRssiEvent event) {
@@ -185,9 +175,7 @@ class _OnConnectionStateChanged extends _$OnConnectionStateChanged {
185175
@override
186176
void build() {
187177
streamSubscription = FlutterBluePlus.events.onConnectionStateChanged.listen(listener);
188-
ref.onDispose(
189-
() => streamSubscription?.cancel(),
190-
);
178+
ref.onDispose(() => streamSubscription?.cancel());
191179
}
192180

193181
Future<void> listener(OnConnectionStateChangedEvent event) async {
@@ -223,9 +211,7 @@ class _OnConnectionStateChanged extends _$OnConnectionStateChanged {
223211
}
224212
statefulDevice.deviceConnectionState.value = event.connectionState == BluetoothConnectionState.connected ? ConnectivityState.connected : ConnectivityState.disconnected;
225213
if (bluetoothConnectionState == BluetoothConnectionState.connected) {
226-
bluetoothDevice.readRssi().catchError((e) => -1).onError(
227-
(error, stackTrace) => -1,
228-
);
214+
bluetoothDevice.readRssi().catchError((e) => -1).onError((error, stackTrace) => -1);
229215
BaseDeviceDefinition? baseDeviceDefinition = DeviceRegistry.getByName(event.device.advName);
230216
if (baseDeviceDefinition == null) {
231217
return;
@@ -250,17 +236,12 @@ class _OnConnectionStateChanged extends _$OnConnectionStateChanged {
250236
priority: NotificationPriority.LOW,
251237
),
252238
iosNotificationOptions: const IOSNotificationOptions(),
253-
foregroundTaskOptions: ForegroundTaskOptions(
254-
eventAction: ForegroundTaskEventAction.repeat(100),
255-
allowWakeLock: true,
256-
),
239+
foregroundTaskOptions: ForegroundTaskOptions(eventAction: ForegroundTaskEventAction.repeat(100), allowWakeLock: true),
257240
);
258241
FlutterForegroundTask.startService(
259242
notificationTitle: "Gear Connected",
260243
notificationText: "Gear is connected to The Tail Company app",
261-
notificationIcon: const NotificationIcon(
262-
metaDataName: 'com.codel1417.tailApp.notificationIcon',
263-
),
244+
notificationIcon: const NotificationIcon(metaDataName: 'com.codel1417.tailApp.notificationIcon'),
264245
);
265246
FlutterForegroundTask.setOnLockScreenVisibility(true);
266247
}
@@ -281,11 +262,9 @@ class _OnConnectionStateChanged extends _$OnConnectionStateChanged {
281262
if (lastDevice) {
282263
_bluetoothPlusLogger.fine('Last gear detected');
283264
// Disable all triggers on last device
284-
ref.read(triggerListProvider).where((element) => element.enabled).forEach(
285-
(element) {
286-
element.enabled = false;
287-
},
288-
);
265+
ref.read(triggerListProvider).where((element) => element.enabled).forEach((element) {
266+
element.enabled = false;
267+
});
289268
_bluetoothPlusLogger.finer('Disabling wakelock');
290269
// stop wakelock if its started
291270
WakelockPlus.disable();
@@ -314,9 +293,7 @@ class _OnCharacteristicReceived extends _$OnCharacteristicReceived {
314293
@override
315294
void build() {
316295
streamSubscription = FlutterBluePlus.events.onCharacteristicReceived.listen(listener);
317-
ref.onDispose(
318-
() => streamSubscription?.cancel(),
319-
);
296+
ref.onDispose(() => streamSubscription?.cancel());
320297
}
321298

322299
Future<void> listener(OnCharacteristicReceivedEvent event) async {
@@ -361,12 +338,7 @@ class _OnCharacteristicReceived extends _$OnCharacteristicReceived {
361338
if (value.startsWith("VER")) {
362339
statefulDevice.fwVersion.value = getVersionSemVer(value.substring(value.indexOf(" ")));
363340
if (statefulDevice.isTailCoNTROL.value == TailControlStatus.tailControl) {
364-
ref.read(commandQueueProvider(statefulDevice).notifier).addCommand(
365-
BluetoothMessage(
366-
message: "READNVS",
367-
timestamp: DateTime.timestamp(),
368-
),
369-
);
341+
ref.read(commandQueueProvider(statefulDevice).notifier).addCommand(BluetoothMessage(message: "READNVS", timestamp: DateTime.timestamp()));
370342
}
371343
// Don't check for updates unless both values are set
372344
if (statefulDevice.hwVersion.value.isNotEmpty && statefulDevice.fwVersion.value != Version()) {
@@ -380,6 +352,13 @@ class _OnCharacteristicReceived extends _$OnCharacteristicReceived {
380352
} else if (substring == 'FALSE') {
381353
statefulDevice.hasGlowtip.value = GlowtipStatus.noGlowtip;
382354
}
355+
} else if (value.startsWith("RGB")) {
356+
String substring = value.substring(value.indexOf(" ")).trim();
357+
if (substring == 'TRUE') {
358+
statefulDevice.hasRGB.value = RGBStatus.rgb;
359+
} else if (substring == 'FALSE') {
360+
statefulDevice.hasRGB.value = RGBStatus.noRGB;
361+
}
383362
} else if (value.contains("BUSY")) {
384363
//statefulDevice.deviceState.value = DeviceState.busy;
385364
statefulDevice.gearReturnedError.value = true;
@@ -416,9 +395,7 @@ class _KeepGearAwake extends _$KeepGearAwake {
416395

417396
@override
418397
void build() {
419-
ref.onDispose(
420-
() => streamSubscription?.cancel(),
421-
);
398+
ref.onDispose(() => streamSubscription?.cancel());
422399
streamSubscription = Stream.periodic(const Duration(seconds: 15)).listen(listener);
423400
}
424401

@@ -433,9 +410,7 @@ class _KeepGearAwake extends _$KeepGearAwake {
433410
if (device.isTailCoNTROL.value != TailControlStatus.tailControl) {
434411
ref.read(commandQueueProvider(device).notifier).addCommand(BluetoothMessage(message: "BATT", priority: Priority.low, type: CommandType.system, timestamp: DateTime.now()));
435412
}
436-
element.readRssi().catchError((e) => -1).onError(
437-
(error, stackTrace) => -1,
438-
);
413+
element.readRssi().catchError((e) => -1).onError((error, stackTrace) => -1);
439414

440415
if (device.fwVersion.value == Version()) {
441416
ref.read(commandQueueProvider(device).notifier).addCommand(BluetoothMessage(message: "VER", priority: Priority.low, type: CommandType.system, timestamp: DateTime.now()));
@@ -454,13 +429,8 @@ class _OnScanResults extends _$OnScanResults {
454429

455430
@override
456431
void build() {
457-
ref.onDispose(
458-
() => streamSubscription?.cancel(),
459-
);
460-
streamSubscription = FlutterBluePlus.onScanResults.listen(
461-
listener,
462-
onError: (e, s) => _bluetoothPlusLogger.severe("", e, s),
463-
);
432+
ref.onDispose(() => streamSubscription?.cancel());
433+
streamSubscription = FlutterBluePlus.onScanResults.listen(listener, onError: (e, s) => _bluetoothPlusLogger.severe("", e, s));
464434
}
465435

466436
Future<void> listener(List<ScanResult> results) async {
@@ -519,7 +489,9 @@ Future<void> connect(String id) async {
519489
} on FlutterBluePlusException catch (e) {
520490
retry = retry + 1;
521491
_bluetoothPlusLogger.warning(
522-
"Failed to connect to ${result.device.advName}. Attempt $retry/${HiveProxy.getOrDefault(settings, gearConnectRetryAttempts, defaultValue: gearConnectRetryAttemptsDefault)}", e);
492+
"Failed to connect to ${result.device.advName}. Attempt $retry/${HiveProxy.getOrDefault(settings, gearConnectRetryAttempts, defaultValue: gearConnectRetryAttemptsDefault)}",
493+
e,
494+
);
523495
await Future.delayed(Duration(milliseconds: 250));
524496
}
525497
}
@@ -543,22 +515,17 @@ class Scan extends _$Scan {
543515
..addListener(isAllGearConnectedListener);
544516

545517
// Has to be delayed so the provider initializes before calling the listener. Otherwise we can't call ref or set state in other methods
546-
Future.delayed(
547-
Duration(milliseconds: 1),
548-
() => isAllGearConnectedListener(),
549-
);
550-
551-
ref.onDispose(
552-
() {
553-
isScanningStreamSubscription?.cancel();
554-
//stopScan();
555-
},
556-
);
518+
Future.delayed(Duration(milliseconds: 1), () => isAllGearConnectedListener());
519+
520+
ref.onDispose(() {
521+
isScanningStreamSubscription?.cancel();
522+
//stopScan();
523+
});
557524
return ScanReason.notScanning;
558525
}
559526

560527
void isAllKnownGearConnectedProviderListener(bool? previous, bool next) {
561-
if (ref.mounted){
528+
if (ref.mounted) {
562529
isAllGearConnectedListener();
563530
}
564531
}

lib/Backend/Definitions/Action/base_action.dart

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,23 @@ part 'base_action.g.dart';
1414
enum ActionCategory {
1515
@HiveField(1)
1616
sequence,
17-
@HiveField(2)
18-
calm,
19-
@HiveField(3)
20-
fast,
21-
@HiveField(4)
22-
tense,
2317
@HiveField(5)
2418
glowtip,
25-
@HiveField(6)
26-
ears,
2719
@HiveField(7)
2820
hidden,
2921
@HiveField(8)
30-
audio
22+
audio,
23+
@HiveField(9)
24+
rgb,
3125
}
3226

3327
extension ActionCategoryExtension on ActionCategory {
3428
String get friendly {
3529
switch (this) {
36-
case ActionCategory.calm:
37-
return actionsCategoryCalm();
38-
case ActionCategory.fast:
39-
return actionsCategoryFast();
40-
case ActionCategory.tense:
41-
return actionsCategoryTense();
4230
case ActionCategory.glowtip:
4331
return actionsCategoryGlowtip();
44-
case ActionCategory.ears:
45-
return "EarGear";
32+
case ActionCategory.rgb:
33+
return actionsCategoryRGB();
4634
case ActionCategory.sequence:
4735
return sequencesPage();
4836
case ActionCategory.hidden:
@@ -58,23 +46,30 @@ abstract class BaseAction {
5846

5947
List<DeviceType> get deviceCategory;
6048

61-
ActionCategory get actionCategory;
49+
ActionCategory? get actionCategory;
6250

6351
String get uuid;
6452

65-
Map<DeviceType, String> get nameAlias;
66-
6753
// Priority is Wings -> Ears -> Tail -> default
6854
String getName(BuiltSet<DeviceType> connectedDeviceTypes) {
69-
if (connectedDeviceTypes.contains(DeviceType.wings) && deviceCategory.contains(DeviceType.wings) && nameAlias.containsKey(DeviceType.wings)) {
70-
return nameAlias[DeviceType.wings]!;
71-
} else if (connectedDeviceTypes.contains(DeviceType.ears) && deviceCategory.contains(DeviceType.ears) && nameAlias.containsKey(DeviceType.ears)) {
72-
return nameAlias[DeviceType.ears]!;
73-
} else if ((connectedDeviceTypes.contains(DeviceType.tail) || connectedDeviceTypes.contains(DeviceType.miniTail)) && (deviceCategory.contains(DeviceType.tail) || deviceCategory.contains(DeviceType.miniTail)) && nameAlias.containsKey(DeviceType.tail)) {
74-
return nameAlias[DeviceType.tail]!;
75-
}
7655
return name;
7756
}
57+
58+
String getCategoryName() {
59+
if (actionCategory != null) {
60+
return actionCategory!.friendly;
61+
} else {
62+
return deviceCategory.first.translatedName;
63+
}
64+
}
65+
66+
String getCategoryNameAnalytics() {
67+
if (actionCategory != null) {
68+
return actionCategory!.name;
69+
} else {
70+
return deviceCategory.first.name;
71+
}
72+
}
7873
}
7974

8075
@unfreezed
@@ -87,12 +82,11 @@ abstract class CommandAction extends BaseAction with _$CommandAction {
8782
required final String name,
8883
required final String uuid,
8984
required final List<DeviceType> deviceCategory,
90-
required final ActionCategory actionCategory,
85+
final ActionCategory? actionCategory,
9186
final String? response,
92-
@Default({}) final Map<DeviceType, String> nameAlias,
87+
final List<Object>? legacyEarCommandMoves,
9388
}) = _CommandAction;
9489

95-
//TODO: Remove with TAILCoNTROL update
9690
factory CommandAction.hiddenEars(String command, String response) {
9791
return CommandAction(command: command, response: response, deviceCategory: [DeviceType.ears], actionCategory: ActionCategory.hidden, uuid: const Uuid().v4(), name: command);
9892
}
@@ -109,8 +103,7 @@ abstract class AudioAction extends BaseAction with _$AudioAction implements Comp
109103
@HiveField(1) required String name,
110104
@HiveField(4) required final String uuid,
111105
@HiveField(2) @Default(DeviceType.values) final List<DeviceType> deviceCategory,
112-
@HiveField(3) @Default(ActionCategory.audio) final ActionCategory actionCategory,
113-
@Default({}) final Map<DeviceType, String> nameAlias,
106+
@HiveField(3) @Default(ActionCategory.audio) final ActionCategory? actionCategory,
114107
}) = _AudioAction;
115108

116109
@override
@@ -129,24 +122,8 @@ abstract class MoveList extends BaseAction with _$MoveList {
129122
@HiveField(1) required String name,
130123
@HiveField(4) required final String uuid,
131124
@HiveField(2) @Default(DeviceType.values) List<DeviceType> deviceCategory,
132-
@HiveField(3) @Default(ActionCategory.sequence) final ActionCategory actionCategory,
125+
@HiveField(3) @Default(ActionCategory.sequence) final ActionCategory? actionCategory,
133126
@HiveField(5) @Default([]) List<Move> moves,
134127
@HiveField(6) @Default(1) double repeat,
135-
@Default({}) final Map<DeviceType, String> nameAlias,
136128
}) = _MoveList;
137129
}
138-
139-
@freezed
140-
abstract class EarsMoveList extends BaseAction with _$EarsMoveList {
141-
EarsMoveList._();
142-
143-
@Implements<BaseAction>()
144-
factory EarsMoveList({
145-
required final String name,
146-
required final String uuid,
147-
required final List<Object> commandMoves,
148-
required final List<DeviceType> deviceCategory,
149-
required final ActionCategory actionCategory,
150-
@Default({}) final Map<DeviceType, String> nameAlias,
151-
}) = _EarsMoveList;
152-
}

0 commit comments

Comments
 (0)