From 22a39406ffdeba7795cd0c107ca9b8daf926211c Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Sat, 29 Nov 2025 13:51:36 +0000 Subject: [PATCH 1/5] fix wrong check --- lib/pages/device.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/device.dart b/lib/pages/device.dart index 8534d29..b9363f0 100644 --- a/lib/pages/device.dart +++ b/lib/pages/device.dart @@ -78,7 +78,7 @@ class _DevicePageState extends State with WidgetsBindingObserver { if (mounted) setState(() {}); }); - if (settings.getZwiftEmulatorEnabled() && actionHandler.supportedApp?.supportsZwiftEmulation == true) { + if (settings.getZwiftEmulatorEnabled() && settings.getTrainerApp()?.supportsZwiftEmulation == true) { zwiftEmulator.startAdvertising(() { if (mounted) setState(() {}); }); From 978325ceffd9b43e94d33cc2ffaf1a7295f1408f Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Sat, 29 Nov 2025 19:36:35 +0000 Subject: [PATCH 2/5] attempt to support Wahoo Kickr Bike Pro #195 --- lib/bluetooth/devices/bluetooth_device.dart | 3 +++ lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart | 5 +++++ lib/bluetooth/devices/zwift/zwift_device.dart | 8 +++++--- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart diff --git a/lib/bluetooth/devices/bluetooth_device.dart b/lib/bluetooth/devices/bluetooth_device.dart index 3e56be5..11e5633 100644 --- a/lib/bluetooth/devices/bluetooth_device.dart +++ b/lib/bluetooth/devices/bluetooth_device.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:swift_control/bluetooth/ble.dart'; import 'package:swift_control/bluetooth/devices/base_device.dart'; import 'package:swift_control/bluetooth/devices/shimano/shimano_di2.dart'; +import 'package:swift_control/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart'; import 'package:swift_control/bluetooth/devices/wahoo/wahoo_kickr_bike_shift.dart'; import 'package:swift_control/bluetooth/devices/zwift/constants.dart'; import 'package:swift_control/bluetooth/devices/zwift/zwift_click.dart'; @@ -56,6 +57,7 @@ abstract class BluetoothDevice extends BaseDevice { null => null, _ when scanResult.name!.toUpperCase().startsWith('STERZO') => EliteSterzo(scanResult), _ when scanResult.name!.toUpperCase().startsWith('KICKR BIKE SHIFT') => WahooKickrBikeShift(scanResult), + _ when scanResult.name!.toUpperCase().startsWith('KICKR BIKE PRO') => WahooKickrBikePro(scanResult), _ when scanResult.name!.toUpperCase().startsWith('CYCPLUS') && scanResult.name!.toUpperCase().contains('BC2') => CycplusBc2(scanResult), _ when scanResult.name!.toUpperCase().startsWith('RDR') => ShimanoDi2(scanResult), @@ -71,6 +73,7 @@ abstract class BluetoothDevice extends BaseDevice { _ when scanResult.name!.toUpperCase().startsWith('SQUARE') => EliteSquare(scanResult), _ when scanResult.name!.toUpperCase().startsWith('STERZO') => EliteSterzo(scanResult), _ when scanResult.name!.toUpperCase().contains('KICKR BIKE SHIFT') => WahooKickrBikeShift(scanResult), + _ when scanResult.name!.toUpperCase().startsWith('KICKR BIKE PRO') => WahooKickrBikePro(scanResult), _ when scanResult.name!.toUpperCase().startsWith('CYCPLUS') && scanResult.name!.toUpperCase().contains('BC2') => CycplusBc2(scanResult), _ when scanResult.services.contains(CycplusBc2Constants.SERVICE_UUID.toLowerCase()) => CycplusBc2(scanResult), diff --git a/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart b/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart new file mode 100644 index 0000000..21fdffb --- /dev/null +++ b/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart @@ -0,0 +1,5 @@ +import 'package:swift_control/bluetooth/devices/zwift/zwift_play.dart'; + +class WahooKickrBikePro extends ZwiftPlay { + WahooKickrBikePro(super.scanResult) : super(); +} diff --git a/lib/bluetooth/devices/zwift/zwift_device.dart b/lib/bluetooth/devices/zwift/zwift_device.dart index 749eb67..d83ceee 100644 --- a/lib/bluetooth/devices/zwift/zwift_device.dart +++ b/lib/bluetooth/devices/zwift/zwift_device.dart @@ -72,9 +72,11 @@ abstract class ZwiftDevice extends BluetoothDevice { @override Future processCharacteristic(String characteristic, Uint8List bytes) async { - if (kDebugMode) { - print( - "${DateTime.now().toString().split(" ").last} Received data on $characteristic: ${bytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ')}", + if (kDebugMode || kIsWeb) { + actionStreamInternal.add( + LogNotification( + "${DateTime.now().toString().split(" ").last} Received data on $characteristic: ${bytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ')}", + ), ); } if (bytes.isEmpty) { From ca5648fec4be0e9a78180c55d6c9154db4281e24 Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Sat, 29 Nov 2025 19:40:32 +0000 Subject: [PATCH 3/5] attempt to support Wahoo Kickr Bike Pro #195 --- lib/bluetooth/devices/zwift/zwift_device.dart | 3 ++- lib/main.dart | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/bluetooth/devices/zwift/zwift_device.dart b/lib/bluetooth/devices/zwift/zwift_device.dart index d83ceee..8fa719c 100644 --- a/lib/bluetooth/devices/zwift/zwift_device.dart +++ b/lib/bluetooth/devices/zwift/zwift_device.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:dartx/dartx.dart'; import 'package:flutter/foundation.dart'; import 'package:swift_control/bluetooth/devices/bluetooth_device.dart'; +import 'package:swift_control/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart'; import 'package:swift_control/bluetooth/devices/zwift/constants.dart'; import 'package:swift_control/bluetooth/messages/notification.dart'; import 'package:swift_control/main.dart'; @@ -72,7 +73,7 @@ abstract class ZwiftDevice extends BluetoothDevice { @override Future processCharacteristic(String characteristic, Uint8List bytes) async { - if (kDebugMode || kIsWeb) { + if (kDebugMode || this is WahooKickrBikePro) { actionStreamInternal.add( LogNotification( "${DateTime.now().toString().split(" ").last} Received data on $characteristic: ${bytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ')}", diff --git a/lib/main.dart b/lib/main.dart index 62354eb..9e7412f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,14 +29,16 @@ void main() async { // setup crash reporting // Catch errors that happen in other isolates - Isolate.current.addErrorListener( - RawReceivePort((dynamic pair) { - final List errorAndStack = pair as List; - final error = errorAndStack.first; - final stack = errorAndStack.last as StackTrace?; - _recordError(error, stack, context: 'Isolate'); - }).sendPort, - ); + if (!kIsWeb) { + Isolate.current.addErrorListener( + RawReceivePort((dynamic pair) { + final List errorAndStack = pair as List; + final error = errorAndStack.first; + final stack = errorAndStack.last as StackTrace?; + _recordError(error, stack, context: 'Isolate'); + }).sendPort, + ); + } runZonedGuarded>( () async { From bdd7c75ebd5f20c462a85affdae66d0ae5d0817b Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Sat, 29 Nov 2025 21:54:24 +0000 Subject: [PATCH 4/5] attempt to support Wahoo Kickr Bike Pro #195 --- .../devices/wahoo/wahoo_kickr_bike_pro.dart | 9 +- lib/widgets/logviewer.dart | 96 +++++++++++-------- 2 files changed, 65 insertions(+), 40 deletions(-) diff --git a/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart b/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart index 21fdffb..21f5f5a 100644 --- a/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart +++ b/lib/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart @@ -1,5 +1,10 @@ -import 'package:swift_control/bluetooth/devices/zwift/zwift_play.dart'; +import 'package:swift_control/bluetooth/devices/zwift/zwift_ride.dart'; -class WahooKickrBikePro extends ZwiftPlay { +import '../zwift/constants.dart'; + +class WahooKickrBikePro extends ZwiftRide { WahooKickrBikePro(super.scanResult) : super(); + + @override + String get customServiceId => ZwiftConstants.ZWIFT_CUSTOM_SERVICE_UUID; } diff --git a/lib/widgets/logviewer.dart b/lib/widgets/logviewer.dart index 196b36c..0eed657 100644 --- a/lib/widgets/logviewer.dart +++ b/lib/widgets/logviewer.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:dartx/dartx.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import '../bluetooth/messages/notification.dart'; import '../main.dart'; @@ -62,47 +63,66 @@ class _LogviewerState extends State { child: Card( child: Padding( padding: const EdgeInsets.all(8), - child: SelectionArea( - child: GestureDetector( - onLongPress: () { - setState(() { - _actions = []; - }); - }, - child: ListView( - physics: const NeverScrollableScrollPhysics(), - controller: _scrollController, - shrinkWrap: true, - reverse: true, - children: _actions - .map( - (action) => Text.rich( - TextSpan( - children: [ + child: Stack( + children: [ + SelectionArea( + child: GestureDetector( + onLongPress: () { + setState(() { + _actions = []; + }); + }, + child: ListView( + physics: const NeverScrollableScrollPhysics(), + controller: _scrollController, + shrinkWrap: true, + reverse: true, + children: _actions + .map( + (action) => Text.rich( TextSpan( - text: action.date.toString().split(" ").last, - style: TextStyle( - fontSize: 12, - fontFeatures: [FontFeature.tabularFigures()], - fontFamily: "monospace", - fontFamilyFallback: ["Courier"], - ), + children: [ + TextSpan( + text: action.date.toString().split(" ").last, + style: TextStyle( + fontSize: 12, + fontFeatures: [FontFeature.tabularFigures()], + fontFamily: "monospace", + fontFamilyFallback: ["Courier"], + ), + ), + TextSpan( + text: " ${action.entry}", + style: TextStyle( + fontSize: 12, + fontFeatures: [FontFeature.tabularFigures()], + fontWeight: FontWeight.bold, + ), + ), + ], ), - TextSpan( - text: " ${action.entry}", - style: TextStyle( - fontSize: 12, - fontFeatures: [FontFeature.tabularFigures()], - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ) - .toList(), + ), + ) + .toList(), + ), + ), ), - ), + Align( + alignment: Alignment.topRight, + child: IconButton( + onPressed: () { + final logText = _actions + .map((e) => "${e.date.toString().split(" ").last} ${e.entry}") + .join("\n"); + Clipboard.setData(ClipboardData(text: logText)); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Log copied to clipboard')), + ); + }, + icon: Icon(Icons.copy), + ), + ), + ], ), ), ), From eadcd17bbb653e0b3f57b9985f7fe81ca4ca9626 Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Sun, 30 Nov 2025 01:08:25 +0000 Subject: [PATCH 5/5] less noise --- lib/bluetooth/devices/zwift/zwift_device.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/bluetooth/devices/zwift/zwift_device.dart b/lib/bluetooth/devices/zwift/zwift_device.dart index 8fa719c..be6aabf 100644 --- a/lib/bluetooth/devices/zwift/zwift_device.dart +++ b/lib/bluetooth/devices/zwift/zwift_device.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:dartx/dartx.dart'; import 'package:flutter/foundation.dart'; import 'package:swift_control/bluetooth/devices/bluetooth_device.dart'; -import 'package:swift_control/bluetooth/devices/wahoo/wahoo_kickr_bike_pro.dart'; import 'package:swift_control/bluetooth/devices/zwift/constants.dart'; import 'package:swift_control/bluetooth/messages/notification.dart'; import 'package:swift_control/main.dart'; @@ -73,7 +72,7 @@ abstract class ZwiftDevice extends BluetoothDevice { @override Future processCharacteristic(String characteristic, Uint8List bytes) async { - if (kDebugMode || this is WahooKickrBikePro) { + if (kDebugMode) { actionStreamInternal.add( LogNotification( "${DateTime.now().toString().split(" ").last} Received data on $characteristic: ${bytes.map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ')}",