mirror of
https://github.com/jonasbark/swiftcontrol.git
synced 2026-02-18 00:17:40 +01:00
Compare commits
3 Commits
login
...
02c038daaa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02c038daaa | ||
|
|
05352d7118 | ||
|
|
5c7e8b923b |
@@ -7,7 +7,6 @@ import 'package:bike_control/bluetooth/devices/trainer_connection.dart';
|
||||
import 'package:bike_control/bluetooth/messages/notification.dart' show AlertNotification, LogNotification;
|
||||
import 'package:bike_control/utils/actions/base_actions.dart';
|
||||
import 'package:bike_control/utils/core.dart';
|
||||
import 'package:bike_control/utils/keymap/apps/training_peaks.dart';
|
||||
import 'package:bike_control/utils/keymap/buttons.dart';
|
||||
import 'package:bike_control/utils/keymap/keymap.dart';
|
||||
import 'package:bike_control/widgets/title.dart';
|
||||
@@ -111,7 +110,7 @@ class OpenBikeControlBluetoothEmulator extends TrainerConnection {
|
||||
_peripheralManager.characteristicWriteRequested.forEach((eventArgs) async {
|
||||
final characteristic = eventArgs.characteristic;
|
||||
final request = eventArgs.request;
|
||||
var value = request.value;
|
||||
final value = request.value;
|
||||
if (kDebugMode) {
|
||||
print('Write request for characteristic: ${characteristic.uuid}: ${bytesToReadableHex(value)}');
|
||||
}
|
||||
@@ -119,15 +118,12 @@ class OpenBikeControlBluetoothEmulator extends TrainerConnection {
|
||||
switch (eventArgs.characteristic.uuid.toString().toLowerCase()) {
|
||||
case OpenBikeControlConstants.APPINFO_CHARACTERISTIC_UUID:
|
||||
try {
|
||||
if (core.settings.getTrainerApp() is TrainingPeaks) {
|
||||
if (firstAppInfoMessage == null) {
|
||||
firstAppInfoMessage = value;
|
||||
return;
|
||||
} else {
|
||||
value = Uint8List.fromList([...firstAppInfoMessage!, ...value]);
|
||||
}
|
||||
}
|
||||
final appInfo = OpenBikeProtocolParser.parseAppInfo(value);
|
||||
// use this fallback if first message is incomplete (e.g. TrainingPeaks on macOS)
|
||||
|
||||
AppInfo appInfo = OpenBikeProtocolParser.parseAppInfo(
|
||||
Uint8List.fromList([...?firstAppInfoMessage, ...value]),
|
||||
);
|
||||
firstAppInfoMessage = null;
|
||||
isConnected.value = true;
|
||||
connectedApp.value = appInfo;
|
||||
supportedActions = appInfo.supportedButtons.mapNotNull((b) => b.action).toList();
|
||||
@@ -137,6 +133,10 @@ class OpenBikeControlBluetoothEmulator extends TrainerConnection {
|
||||
core.connection.signalNotification(LogNotification('Parsed App Info: $appInfo'));
|
||||
} catch (e) {
|
||||
core.connection.signalNotification(LogNotification('Error parsing App Info ${bytesToHex(value)}: $e'));
|
||||
if (firstAppInfoMessage == null) {
|
||||
firstAppInfoMessage = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -87,29 +87,57 @@ class ShimanoDi2 extends BluetoothDevice {
|
||||
});
|
||||
|
||||
if (actualChange) {
|
||||
final buttonsToTrigger = _lastButtons.entries
|
||||
.where((entry) {
|
||||
final type = entry.value.type;
|
||||
return type != _Di2State.released;
|
||||
})
|
||||
.map((entry) => availableButtons.firstWhere((button) => button.name == 'D-Fly Channel ${entry.key + 1}'))
|
||||
.toList();
|
||||
final Map<_Di2State, List<ControllerButton>> mapped = _lastButtons.entries.groupBy((e) => e.value.type).map((
|
||||
key,
|
||||
value,
|
||||
) {
|
||||
final buttons = value
|
||||
.map((entry) => availableButtons.firstWhere((button) => button.name == 'D-Fly Channel ${entry.key + 1}'))
|
||||
.toList();
|
||||
return MapEntry(key, buttons);
|
||||
});
|
||||
|
||||
Logger.debug('Buttons to trigger: ${buttonsToTrigger.map((b) => b.name).join(', ')}');
|
||||
handleButtonsClicked(buttonsToTrigger);
|
||||
final shortPress = [...?mapped[_Di2State.shortPress], ...?mapped[_Di2State.doublePress]];
|
||||
if (shortPress.isNotEmpty) {
|
||||
Logger.debug('Short Press Buttons to trigger: ${shortPress.map((b) => b.name).join(', ')}');
|
||||
handleButtonsClicked(shortPress);
|
||||
handleButtonsClicked([]);
|
||||
_resetButtonsForState([_Di2State.shortPress]);
|
||||
}
|
||||
|
||||
final doublePress = _lastButtons.entries
|
||||
.filter((entry) => entry.value.type == _Di2State.doublePress)
|
||||
.map((entry) => availableButtons.firstWhere((button) => button.name == 'D-Fly Channel ${entry.key + 1}'))
|
||||
.toList();
|
||||
final longPress = mapped[_Di2State.longPress] ?? [];
|
||||
if (longPress.isNotEmpty) {
|
||||
Logger.debug('Long Press Buttons to trigger: ${longPress.map((b) => b.name).join(', ')}');
|
||||
handleButtonsClicked(longPress);
|
||||
}
|
||||
|
||||
final released = mapped[_Di2State.released] ?? [];
|
||||
final keepPress = mapped[_Di2State.longPress] ?? [];
|
||||
|
||||
if (released.isNotEmpty && keepPress.isEmpty) {
|
||||
Logger.debug('Releasing all Buttons');
|
||||
handleButtonsClicked([]);
|
||||
}
|
||||
|
||||
final doublePress = mapped[_Di2State.doublePress] ?? [];
|
||||
if (doublePress.isNotEmpty) {
|
||||
Logger.debug('Buttons to still trigger: ${doublePress.map((b) => b.name).join(', ')}');
|
||||
handleButtonsClicked(doublePress);
|
||||
handleButtonsClicked([]);
|
||||
_resetButtonsForState([_Di2State.doublePress]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _resetButtonsForState(List<_Di2State> list) {
|
||||
_lastButtons.forEach((key, value) {
|
||||
if (list.contains(value.type)) {
|
||||
_lastButtons[key] = (value: value.value, type: _Di2State.released);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget showInformation(BuildContext context) {
|
||||
return Column(
|
||||
|
||||
@@ -237,7 +237,7 @@ class _ConnectionMethodState extends State<ConnectionMethod> with WidgetsBinding
|
||||
Future.wait(widget.requirements.map((e) => e.getStatus())).then((result) {
|
||||
final allDone = result.every((e) => e);
|
||||
|
||||
if (context.mounted) {
|
||||
if (context.mounted && widget.isEnabled != allDone) {
|
||||
widget.onChange(allDone);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ void buildToast({
|
||||
Duration? duration,
|
||||
}) {
|
||||
if (navigatorKey.currentContext?.mounted ?? false) {
|
||||
final isMobile = MediaQuery.sizeOf(navigatorKey.currentContext!).width < 600;
|
||||
showToast(
|
||||
context: navigatorKey.currentContext!,
|
||||
location: location,
|
||||
@@ -24,34 +25,37 @@ void buildToast({
|
||||
LogLevel.LOGLEVEL_ERROR => duration ?? const Duration(seconds: 7),
|
||||
_ => duration ?? const Duration(seconds: 3),
|
||||
},
|
||||
builder: (context, overlay) => SurfaceCard(
|
||||
filled: switch (level) {
|
||||
LogLevel.LOGLEVEL_WARNING => true,
|
||||
LogLevel.LOGLEVEL_ERROR => true,
|
||||
_ => false,
|
||||
},
|
||||
fillColor: switch (level) {
|
||||
LogLevel.LOGLEVEL_DEBUG => null,
|
||||
LogLevel.LOGLEVEL_INFO => null,
|
||||
LogLevel.LOGLEVEL_WARNING => Theme.of(context).colorScheme.chart1,
|
||||
LogLevel.LOGLEVEL_ERROR => Theme.of(context).colorScheme.destructive,
|
||||
_ => null,
|
||||
},
|
||||
child: Basic(
|
||||
title: titleWidget ?? Text(title ?? ''),
|
||||
subtitle: subtitle != null ? Text(subtitle) : null,
|
||||
trailing: titleWidget is ButtonWidget
|
||||
? null
|
||||
: PrimaryButton(
|
||||
size: ButtonSize.small,
|
||||
onPressed: () {
|
||||
// Close the toast programmatically when clicking Undo.
|
||||
overlay.close();
|
||||
onClose?.call();
|
||||
},
|
||||
child: Text(closeTitle),
|
||||
),
|
||||
trailingAlignment: Alignment.center,
|
||||
builder: (context, overlay) => Container(
|
||||
margin: EdgeInsets.only(bottom: isMobile ? 50 : 0),
|
||||
child: SurfaceCard(
|
||||
filled: switch (level) {
|
||||
LogLevel.LOGLEVEL_WARNING => true,
|
||||
LogLevel.LOGLEVEL_ERROR => true,
|
||||
_ => false,
|
||||
},
|
||||
fillColor: switch (level) {
|
||||
LogLevel.LOGLEVEL_DEBUG => null,
|
||||
LogLevel.LOGLEVEL_INFO => null,
|
||||
LogLevel.LOGLEVEL_WARNING => Theme.of(context).colorScheme.chart1,
|
||||
LogLevel.LOGLEVEL_ERROR => Theme.of(context).colorScheme.destructive,
|
||||
_ => null,
|
||||
},
|
||||
child: Basic(
|
||||
title: titleWidget ?? Text(title ?? ''),
|
||||
subtitle: subtitle != null ? Text(subtitle) : null,
|
||||
trailing: titleWidget is ButtonWidget
|
||||
? null
|
||||
: PrimaryButton(
|
||||
size: ButtonSize.small,
|
||||
onPressed: () {
|
||||
// Close the toast programmatically when clicking Undo.
|
||||
overlay.close();
|
||||
onClose?.call();
|
||||
},
|
||||
child: Text(closeTitle),
|
||||
),
|
||||
trailingAlignment: Alignment.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user