diff --git a/CHANGELOG.md b/CHANGELOG.md index dfc9b66..e34bc35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ -### 2.7.0 (2025-10-07) +### 3.0.0 (2025-10-08) - SwiftControl now supports iOS! - Note that you can't run SwiftControl and your trainer app on the same iPhone due to iOS limitations but...: - You can now use SwiftControl as "remote control" for other devices, such as an iPad. Example scenario: - - your phone (Android/iOS) runs SwiftControl and connects to your Zwift devices + - your phone (Android/iOS) runs SwiftControl and connects to your Click devices - your iPad or other tablet runs e.g. MyWhoosh (does not need to have SwiftControl installed) - after pairing SwiftControl to your iPad / tablet via Bluetooth your phone will send the button presses to your iPad / tablet diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index a1c705a..9b19d43 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -1,18 +1,18 @@ -## Zwift device cannot be found +## Click device cannot be found You may need to update the firmware in Zwift Companion app. -## Zwift device does not send any data +## Click device does not send any data You may need to update the firmware in Zwift Companion app. -## My Zwift Click v2 disconnects after a minute +## My Click v2 disconnects after a minute Check [this](https://github.com/jonasbark/swiftcontrol/issues/68) discussion. -To make your Zwift Click V2 work best you should connect it in the Zwift app once each day. +To make your Click V2 work best you should connect it in the Zwift app once each day. If you don't do that SwiftControl will need to reconnect every minute. 1. Open Zwift app (not the Companion) 2. Log in (subscription not required) and open the device connection screen -3. Connect your Trainer, then connect the Zwift Click V2 +3. Connect your Trainer, then connect the Click V2 4. Close the Zwift app again and connect again in SwiftControl ## Remote control is not working - nothing happens diff --git a/lib/main.dart b/lib/main.dart index a4a5337..ed97790 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,6 +20,7 @@ late BaseActions actionHandler; final accessibilityHandler = Accessibility(); final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); final settings = Settings(); +const screenshotMode = false; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -28,6 +29,7 @@ void main() async { if (actionHandler is DesktopActions) { // Must add this line. await windowManager.ensureInitialized(); + windowManager.setSize(Size(1280, 800)); } runApp(const SwiftPlayApp()); diff --git a/lib/pages/device.dart b/lib/pages/device.dart index bd3f03b..4579135 100644 --- a/lib/pages/device.dart +++ b/lib/pages/device.dart @@ -91,7 +91,7 @@ class _DevicePageState extends State { connection.devices.joinToString( separator: '\n', transform: (it) { - return """${it.device.name ?? it.runtimeType}: ${it.isConnected ? 'Connected' : 'Not connected'} + return """${it.device.name?.screenshot ?? it.runtimeType}: ${it.isConnected ? 'Connected' : 'Not connected'} ${it.batteryLevel != null ? ' - Battery Level: ${it.batteryLevel}%' : ''} ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : ''}""".trim(); }, @@ -229,3 +229,7 @@ ${it.firmwareVersion != null ? ' - Firmware Version: ${it.firmwareVersion}' : '' ); } } + +extension Screenshot on String { + String get screenshot => screenshotMode ? replaceAll('Zwift ', '') : this; +} diff --git a/lib/pages/touch_area.dart b/lib/pages/touch_area.dart index 67a33b9..303e3ed 100644 --- a/lib/pages/touch_area.dart +++ b/lib/pages/touch_area.dart @@ -362,7 +362,7 @@ class _TouchAreaSetupPageState extends State { Text('''1. Create an in-game screenshot of your app (e.g. within MyWhoosh) in landscape orientation 2. Load the screenshot with the button below 3. The app is automatically set to landscape orientation for accurate mapping -4. Press a button on your Zwift device to create a touch area +4. Press a button on your Click device to create a touch area 5. Drag the touch areas to the desired position on the screenshot 6. Save and close this screen'''), ElevatedButton( diff --git a/lib/utils/requirements/multi.dart b/lib/utils/requirements/multi.dart index c85f2d4..f2136db 100644 --- a/lib/utils/requirements/multi.dart +++ b/lib/utils/requirements/multi.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:keypress_simulator/keypress_simulator.dart'; +import 'package:swift_control/main.dart'; import 'package:swift_control/pages/scan.dart'; import 'package:swift_control/utils/requirements/platform.dart'; import 'package:swift_control/utils/requirements/remote.dart'; @@ -38,7 +39,7 @@ class BluetoothTurnedOn extends PlatformRequirement { @override Future getStatus() async { final currentState = await UniversalBle.getBluetoothAvailabilityState(); - status = currentState == AvailabilityState.poweredOn; + status = currentState == AvailabilityState.poweredOn || screenshotMode; } } @@ -55,7 +56,7 @@ class UnsupportedPlatform extends PlatformRequirement { } class BluetoothScanning extends PlatformRequirement { - BluetoothScanning() : super('Finding your Zwift® controller...') { + BluetoothScanning() : super('Finding your Controller...') { status = false; } diff --git a/lib/utils/requirements/remote.dart b/lib/utils/requirements/remote.dart index 477d63a..1c060ae 100644 --- a/lib/utils/requirements/remote.dart +++ b/lib/utils/requirements/remote.dart @@ -62,7 +62,8 @@ class RemoteRequirement extends PlatformRequirement { return; } } - while (peripheralManager.state != BluetoothLowEnergyState.poweredOn) { + while (peripheralManager.state != BluetoothLowEnergyState.poweredOn && + peripheralManager.state != BluetoothLowEnergyState.unknown) { print('Waiting for peripheral manager to be powered on...'); await Future.delayed(Duration(seconds: 1)); } @@ -259,7 +260,7 @@ class RemoteRequirement extends PlatformRequirement { child: Text(_isAdvertising ? 'Stop Pairing' : 'Start Pairing'), ), if (_isAdvertising) SizedBox(height: 20, width: 20, child: CircularProgressIndicator()), - if (kDebugMode) + if (kDebugMode && !screenshotMode) ElevatedButton( onPressed: () { (actionHandler as RemoteActions).sendAbsMouseReport(0, 90, 90); @@ -291,6 +292,6 @@ class RemoteRequirement extends PlatformRequirement { @override Future getStatus() async { - status = (actionHandler as RemoteActions).isConnected; + status = (actionHandler as RemoteActions).isConnected || screenshotMode; } } diff --git a/lib/widgets/custom_keymap_selector.dart b/lib/widgets/custom_keymap_selector.dart index 500df19..4d3d1bb 100644 --- a/lib/widgets/custom_keymap_selector.dart +++ b/lib/widgets/custom_keymap_selector.dart @@ -86,7 +86,7 @@ class _HotKeyListenerState extends State { return AlertDialog( content: _pressedButton == null - ? Text('Press a button on your Zwift device') + ? Text('Press a button on your Click device') : KeyboardListener( focusNode: _focusNode, autofocus: true, diff --git a/lib/widgets/keymap_explanation.dart b/lib/widgets/keymap_explanation.dart index cbc5219..1ad6dd0 100644 --- a/lib/widgets/keymap_explanation.dart +++ b/lib/widgets/keymap_explanation.dart @@ -1,6 +1,7 @@ import 'package:dartx/dartx.dart'; import 'package:flutter/material.dart'; import 'package:swift_control/main.dart'; +import 'package:swift_control/pages/device.dart'; import 'package:swift_control/utils/keymap/keymap.dart'; import '../pages/touch_area.dart'; @@ -41,7 +42,7 @@ class KeymapExplanation extends StatelessWidget { Padding( padding: const EdgeInsets.all(6), child: Text( - 'Button on your ${connectedDevice?.device.name ?? connectedDevice?.runtimeType}', + 'Button on your ${connectedDevice?.device.name?.screenshot ?? connectedDevice?.runtimeType}', style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 0499a56..d6f9601 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.7.0+14 +version: 3.0.0+17 environment: sdk: ^3.7.0