Compare commits

..

4 Commits

Author SHA1 Message Date
Jonas Bark
f83defb37b introduce workaround for Zwift Click V2 (reset every minute) 2025-10-01 16:17:20 +02:00
Jonas Bark
5c8db11536 Merge branch 'web' 2025-10-01 15:42:43 +02:00
Jonas Bark
30aa5b33a3 fix issue #81 2025-10-01 15:42:20 +02:00
Jonas Bark
ca41e69a17 fix issue #81 2025-10-01 15:41:19 +02:00
9 changed files with 53 additions and 35 deletions

View File

View File

@@ -1,3 +1,7 @@
### 2.6.1 (2025-10-01)
- fix a few issues with the new touch placement feature
- add a workaround for Zwift Click V2 which resets the device when button events are no longer sent
### 2.6.0 (2025-09-30)
- refactor touch placements: show touches on screen, fix misplaced coordinates - should fix #64
- show firmware version of connected device

View File

@@ -1,9 +1,9 @@
import 'dart:typed_data';
import 'package:swift_control/bluetooth/devices/zwift_ride.dart';
import 'package:swift_control/bluetooth/protocol/zp.pb.dart';
import '../ble.dart';
import '../protocol/zp.pbenum.dart';
class ZwiftClickV2 extends ZwiftRide {
ZwiftClickV2(super.scanResult);
@@ -44,27 +44,27 @@ class ZwiftClickV2 extends ZwiftRide {
0x00,
0x0A,
0x15,
0x40,
0xE9,
0xD9,
0xC9,
0x6B,
0x74,
0x63,
0xC2,
0x7F,
0x1B,
0x4E,
0x4D,
0x9F,
0x1C,
0xB1,
0x20,
0x5D,
0x88,
0x2E,
0xD7,
0xCE,
0x63,
0x24,
0x0A,
0x31,
0xD6,
0xC6,
0xB8,
0x1F,
0xC1,
0x29,
0xD6,
0xA4,
0xE9,
0x9D,
0xFF,
0xFC,
0xB9,
0xFC,
0x41,
0x8D,
]),
);*/
}

View File

@@ -2,6 +2,7 @@ import 'package:dartx/dartx.dart';
import 'package:flutter/foundation.dart';
import 'package:protobuf/protobuf.dart' as $pb;
import 'package:swift_control/bluetooth/devices/base_device.dart';
import 'package:swift_control/bluetooth/devices/zwift_clickv2.dart';
import 'package:swift_control/bluetooth/messages/ride_notification.dart';
import 'package:swift_control/bluetooth/protocol/zp_vendor.pb.dart';
import 'package:swift_control/utils/keymap/buttons.dart';
@@ -77,10 +78,15 @@ class ZwiftRide extends BaseDevice {
);
}
if (bytes.startsWith(Constants.RESPONSE_STOPPED_CLICK_V2)) {
if (bytes.startsWith(Constants.RESPONSE_STOPPED_CLICK_V2) && this is ZwiftClickV2) {
actionStreamInternal.add(
LogNotification('Your Zwift Click V2 no longer sends events. Connect it in the Zwift app once per day.'),
LogNotification(
'Your Zwift Click V2 no longer sends events. Connect it in the Zwift app once per day. Resetting the device now.',
),
);
if (!kDebugMode) {
sendCommand(Opcode.RESET, null);
}
}
switch (opcode) {

View File

@@ -78,10 +78,12 @@ class _DevicePageState extends State<DevicePage> {
),
padding: const EdgeInsets.all(8),
child: Text(
'''To make your Zwift Click V2 work properly you need to connect it to with in the Zwift app once each day:
'''To make your Zwift Click V2 work best you should connect it in the Zwift app once each day.\nIf you don't do that SwiftControl will need to reconnect every minute.
1. Open Zwift app
2. After logging in (subscription not required) find it in the device connection screen and connect it
3. Close the Zwift app again and connect again in SwiftControl''',
2. Log in (subscription not required) and open the device connection screen
3. Connect your Trainer, then connect the Zwift Click V2
4. Close the Zwift app again and connect again in SwiftControl''',
),
),
Text(
@@ -201,12 +203,13 @@ ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : ''
setState(() {});
},
),
if (connection.devices.any((device) => (device is ZwiftClickV2) && device.isConnected))
if (kDebugMode &&
connection.devices.any((device) => (device is ZwiftClickV2) && device.isConnected))
ElevatedButton(
onPressed: () {
(connection.devices.first as ZwiftClickV2).test();
},
child: Text('Reset'),
child: Text('Test'),
),
],
),

View File

@@ -74,7 +74,10 @@ class _TouchAreaSetupPageState extends State<TouchAreaSetupPage> {
// Force landscape orientation during keymap editing
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: []);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: []).then((_) {
// this will make sure the buttons are placed correctly after the transition
setState(() {});
});
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
windowManager.setFullScreen(true);
}
@@ -128,9 +131,11 @@ class _TouchAreaSetupPageState extends State<TouchAreaSetupPage> {
}) {
final flutterView = WidgetsBinding.instance.platformDispatcher.views.first;
// figure out notch height for e.g. macOS
// figure out notch height for e.g. macOS. On Windows the display size is not available (0,0).
final differenceInHeight =
(flutterView.display.size.height - flutterView.physicalSize.height) / flutterView.devicePixelRatio;
(flutterView.display.size.height > 0)
? (flutterView.display.size.height - flutterView.physicalSize.height) / flutterView.devicePixelRatio
: 0.0;
if (kDebugMode) {
print('Display Size: ${flutterView.display.size}');

View File

@@ -59,7 +59,7 @@ class DesktopActions extends BaseActions {
final point = supportedApp!.resolveTouchPosition(action: action, windowInfo: null);
await keyPressSimulator.simulateMouseClickDown(point);
await keyPressSimulator.simulateMouseClickUp(point);
return 'Mouse clicked at: $point';
return 'Mouse clicked at: ${point.dx} ${point.dy}';
}
}
}

View File

@@ -20,10 +20,10 @@ class KeymapExplanation extends StatelessWidget {
final keyboardGroups = availableKeypairs
.filter((e) => e.physicalKey != null)
.groupBy((element) => '${element.physicalKey}-${element.isLongPress}');
.groupBy((element) => '${element.physicalKey?.usbHidUsage}-${element.isLongPress}');
final touchGroups = availableKeypairs
.filter((e) => e.physicalKey == null && e.touchPosition != Offset.zero)
.groupBy((element) => '${element.touchPosition}-${element.isLongPress}');
.groupBy((element) => '${element.touchPosition.dx}-${element.touchPosition.dy}-${element.isLongPress}');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -1,7 +1,7 @@
name: swift_control
description: "SwiftControl - Control your virtual riding"
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 2.6.0+6
version: 2.6.1+7
environment:
sdk: ^3.7.0