Compare commits

...

8 Commits

15 changed files with 144 additions and 20 deletions

View File

@@ -71,6 +71,11 @@ jobs:
env:
DEVELOPER_ID_APPLICATION_SIGNING_IDENTITY: ${{ secrets.DEVELOPER_ID_APPLICATION_SIGNING_IDENTITY }}
- name: Decode Keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > android/android.keystore;
echo "${{ secrets.KEYSTORE_PROPERTIES }}" > android/keystore.properties;
#6 Building APK
- name: Build APK
run: flutter build apk --release

2
.gitignore vendored
View File

@@ -12,6 +12,8 @@
.swiftpm/
migrate_working_dir/
android/keystore.properties
# IntelliJ related
*.iml
*.ipr

View File

@@ -1,5 +1,10 @@
### 1.0.5 (2025-03-29)
- Zwift Ride: remap the shifter buttons to the correct values
### 1.0.0+4 (2025-03-29)
- Zwift Ride: attempt to fix button parsing
- Android: fix missing permissions
- Windows: potential fix for key press issues
### 1.0.0+3 (2025-03-29)

View File

@@ -9,8 +9,6 @@ import android.os.Build
import android.util.Log
import android.view.ViewConfiguration
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED
import android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED
import android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
@@ -30,7 +28,6 @@ class AccessibilityService : AccessibilityService(), Listener {
private val ignorePackages = listOf("com.android.systemui", "com.android.launcher", "com.android.settings")
override fun onAccessibilityEvent(event: AccessibilityEvent) {
Log.w("Acc", "onAccessibilityEvent: ${event.packageName} ${event.eventType} ${event.contentChangeTypes}")
if (event.packageName == null || rootInActiveWindow == null) {
return
}

View File

@@ -1,3 +1,6 @@
import java.io.FileInputStream
import java.util.*
plugins {
id("com.android.application")
id("kotlin-android")
@@ -5,6 +8,11 @@ plugins {
id("dev.flutter.flutter-gradle-plugin")
}
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
android {
namespace = "de.jonasbark.swift_play"
compileSdk = flutter.compileSdkVersion
@@ -33,11 +41,18 @@ android {
versionName = flutter.versionName
}
signingConfigs {
create("config") {
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
storeFile = file("../${keystoreProperties["storeFile"] as String}")
storePassword = keystoreProperties["storePassword"] as String
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
signingConfig = signingConfigs.getByName("config")
}
}
}

View File

@@ -8,13 +8,16 @@ import 'package:swift_control/utils/keymap/keymap.dart';
class AndroidActions extends BaseActions {
static const MYWHOOSH_APP_PACKAGE = "com.mywhoosh.whooshgame";
static const TRAININGPEAKS_APP_PACKAGE = "com.indieVelo.client";
static const validPackageNames = [MYWHOOSH_APP_PACKAGE, TRAININGPEAKS_APP_PACKAGE];
WindowEvent? windowInfo;
@override
void init(Keymap? keymap) {
streamEvents().listen((windowEvent) {
windowInfo = windowEvent;
if (validPackageNames.contains(windowEvent.packageName)) {
windowInfo = windowEvent;
}
});
}

View File

@@ -19,7 +19,9 @@ class DesktopActions extends BaseActions {
if (keymap == null) {
throw Exception('Keymap is not set');
}
keyPressSimulator.simulateKeyDown(_keymap!.decrease);
keyPressSimulator.simulateKeyDown(_keymap!.decrease).then((_) {
keyPressSimulator.simulateKeyUp(_keymap!.decrease);
});
}
@override
@@ -27,6 +29,8 @@ class DesktopActions extends BaseActions {
if (keymap == null) {
throw Exception('Keymap is not set');
}
keyPressSimulator.simulateKeyDown(_keymap!.increase);
keyPressSimulator.simulateKeyDown(_keymap!.increase).then((_) {
keyPressSimulator.simulateKeyUp(_keymap!.increase);
});
}
}

View File

@@ -1,6 +1,5 @@
import 'dart:typed_data';
import 'package:accessibility/accessibility.dart';
import 'package:swift_control/main.dart';
import 'package:swift_control/utils/devices/zwift_click.dart';
import 'package:swift_control/utils/messages/ride_notification.dart';
@@ -25,12 +24,15 @@ class ZwiftRide extends ZwiftClick {
_lastControllerNotification = clickNotification;
actionStreamInternal.add(clickNotification);
if (clickNotification.analogLR.abs() == 100) {
actionHandler.increaseGear();
} else if (clickNotification.analogUD.abs() == 100) {
if (clickNotification.buttonShiftDownLeft || clickNotification.buttonShiftUpLeft || clickNotification.buttonZ) {
actionHandler.decreaseGear();
} else if (clickNotification.buttonShiftUpRight ||
clickNotification.buttonShiftDownRight ||
clickNotification.buttonOnOffLeft) {
// TODO remove buttonZ once the assignment is fixed for real
actionHandler.increaseGear();
}
if (clickNotification.buttonA) {
/*if (clickNotification.buttonA) {
actionHandler.controlMedia(MediaAction.next);
} else if (clickNotification.buttonY) {
actionHandler.controlMedia(MediaAction.volumeUp);
@@ -38,7 +40,7 @@ class ZwiftRide extends ZwiftClick {
actionHandler.controlMedia(MediaAction.volumeDown);
} else if (clickNotification.buttonZ) {
actionHandler.controlMedia(MediaAction.playPause);
}
}*/
}
}
}

View File

@@ -39,7 +39,7 @@ class RideNotification extends BaseNotification {
late bool buttonPowerUpLeft, buttonPowerDownLeft;
late bool buttonOnOffLeft, buttonOnOffRight;
late int analogLR, analogUD;
int analogLR = 0, analogUD = 0;
RideNotification(Uint8List message) {
final status = RideKeyPadStatus.fromBuffer(message);
@@ -62,9 +62,9 @@ class RideNotification extends BaseNotification {
buttonOnOffRight = status.buttonMap & _RideButtonMask.ONOFF_R_BTN.mask == BTN_PRESSED;
for (final analogue in status.analogButtons.groupStatus) {
if (analogue.location == RideAnalogLocation.LEFT) {
if (analogue.location == RideAnalogLocation.LEFT || analogue.location == RideAnalogLocation.RIGHT) {
analogLR = analogue.analogValue;
} else if (analogue.location == RideAnalogLocation.DOWN) {
} else if (analogue.location == RideAnalogLocation.DOWN || analogue.location == RideAnalogLocation.UP) {
analogUD = analogue.analogValue;
}
}

View File

@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:swift_control/main.dart';
import 'package:swift_control/utils/requirements/platform.dart';
@@ -18,6 +19,36 @@ class AccessibilityRequirement extends PlatformRequirement {
}
}
class BluetoothScanRequirement extends PlatformRequirement {
BluetoothScanRequirement() : super('Allow Bluetooth Scan');
@override
Future<void> call() async {
await Permission.bluetoothScan.request();
}
@override
Future<void> getStatus() async {
final state = await Permission.bluetoothScan.status;
status = state.isGranted || state.isLimited;
}
}
class BluetoothConnectRequirement extends PlatformRequirement {
BluetoothConnectRequirement() : super('Allow Bluetooth Connections');
@override
Future<void> call() async {
await Permission.bluetoothConnect.request();
}
@override
Future<void> getStatus() async {
final state = await Permission.bluetoothConnect.status;
status = state.isGranted || state.isLimited;
}
}
class NotificationRequirement extends PlatformRequirement {
NotificationRequirement() : super('Allow adding persistent Notification');

View File

@@ -29,7 +29,14 @@ Future<List<PlatformRequirement>> getRequirements() async {
} else if (Platform.isWindows) {
list = [BluetoothTurnedOn(), KeyboardRequirement(), KeymapRequirement(), BluetoothScanning()];
} else if (Platform.isAndroid) {
list = [BluetoothTurnedOn(), AccessibilityRequirement(), NotificationRequirement(), BluetoothScanning()];
list = [
BluetoothTurnedOn(),
AccessibilityRequirement(),
NotificationRequirement(),
BluetoothScanRequirement(),
BluetoothConnectRequirement(),
BluetoothScanning(),
];
} else {
list = [UnsupportedPlatform()];
}

View File

@@ -367,6 +367,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
url: "https://pub.dev"
source: hosted
version: "11.4.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
url: "https://pub.dev"
source: hosted
version: "12.1.0"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: f84a188e79a35c687c132a0a0556c254747a08561e99ab933f12f6ca71ef3c98
url: "https://pub.dev"
source: hosted
version: "9.4.6"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
url: "https://pub.dev"
source: hosted
version: "0.1.3+5"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
url: "https://pub.dev"
source: hosted
version: "4.3.0"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
petitparser:
dependency: transitive
description:

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: 1.0.0+4
version: 1.0.5+0
environment:
sdk: ^3.7.0
@@ -14,6 +14,7 @@ dependencies:
flutter_local_notifications: ^19.0.0
universal_ble: any
protobuf: ^3.1.0
permission_handler: ^11.4.0
dartx: any
pointycastle: any
keypress_simulator: ^0.2.0

View File

@@ -7,12 +7,15 @@
#include "generated_plugin_registrant.h"
#include <keypress_simulator_windows/keypress_simulator_windows_plugin_c_api.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <universal_ble/universal_ble_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
KeypressSimulatorWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("KeypressSimulatorWindowsPluginCApi"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UniversalBlePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UniversalBlePluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(

View File

@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
keypress_simulator_windows
permission_handler_windows
universal_ble
url_launcher_windows
)