Compare commits

..

4 Commits

Author SHA1 Message Date
Jonas Bark
6a7922cf17 version++ 2025-03-31 21:00:37 +02:00
Jonas Bark
8e23de2718 version update check => internet permission is required 2025-03-31 20:58:27 +02:00
Jonas Bark
11aec5fba1 Zwift Ride: add buttonPowerDown to shift gears
Zwift Play: Fix buttonShift assignment
Android: fix Media next button
2025-03-31 20:20:47 +02:00
Jonas Bark
c98f213e2e add some comments 2025-03-30 21:34:29 +02:00
19 changed files with 190 additions and 57 deletions

View File

@@ -1,3 +1,9 @@
### 1.1.6 (2025-03-31)
- Zwift Ride: add buttonPowerDown to shift gears
- Zwift Play: Fix buttonShift assignment
- Android: fix action to go to next song
- App now checks if you run the latest available version
### 1.1.5 (2025-03-30)
- fix bluetooth connection #6, also add missing entitlement on macOS

View File

@@ -11,14 +11,11 @@ import android.os.Bundle
import android.provider.Settings
import androidx.core.content.ContextCompat.startActivity
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
/** AccessibilityPlugin */
class AccessibilityPlugin: FlutterPlugin, MethodCallHandler, Accessibility {
class AccessibilityPlugin: FlutterPlugin, Accessibility {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
@@ -38,14 +35,6 @@ class AccessibilityPlugin: FlutterPlugin, MethodCallHandler, Accessibility {
Observable.fromService = eventHandler
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
@@ -72,7 +61,10 @@ class AccessibilityPlugin: FlutterPlugin, MethodCallHandler, Accessibility {
audioService.dispatchMediaKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE))
audioService.dispatchMediaKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_UP, android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE))
}
MediaAction.NEXT -> audioService.dispatchMediaKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_MEDIA_NEXT))
MediaAction.NEXT -> {
audioService.dispatchMediaKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_MEDIA_NEXT))
audioService.dispatchMediaKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_UP, android.view.KeyEvent.KEYCODE_MEDIA_NEXT))
}
MediaAction.VOLUME_DOWN -> audioService.adjustVolume(android.media.AudioManager.ADJUST_LOWER, android.media.AudioManager.FLAG_SHOW_UI)
MediaAction.VOLUME_UP -> audioService.adjustVolume(android.media.AudioManager.ADJUST_RAISE, android.media.AudioManager.FLAG_SHOW_UI)
}

View File

@@ -19,6 +19,9 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<!-- to check if you have the latest version -->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="SwiftControl"
android:name="${applicationName}"

View File

@@ -28,7 +28,7 @@ abstract class BaseDevice {
String get customServiceId => BleUuid.ZWIFT_CUSTOM_SERVICE_UUID;
static BaseDevice? fromScanResult(BleDevice scanResult) {
// Use the name first, probably safest method on all platforms
// Use the name first as the "System Devices" and Web (android sometimes Windows) don't have manufacturer data
final device = switch (scanResult.name) {
'Zwift Ride' => ZwiftRide(scanResult),
'Zwift Play' => ZwiftPlay(scanResult),
@@ -39,8 +39,7 @@ abstract class BaseDevice {
if (device != null) {
return device;
} else {
// otherwise use the manufacturer data, which doesn't exist on Web and "System Devices"
// otherwise use the manufacturer data to identify the device
final manufacturerData = scanResult.manufacturerDataList;
final data = manufacturerData.firstOrNullWhere((e) => e.companyId == Constants.ZWIFT_MANUFACTURER_ID)?.payload;

View File

@@ -24,12 +24,15 @@ class ZwiftRide extends BaseDevice {
_lastControllerNotification = clickNotification;
actionStreamInternal.add(clickNotification);
if (clickNotification.buttonShiftDownLeft || clickNotification.buttonShiftUpLeft || clickNotification.buttonZ) {
if (clickNotification.buttonShiftDownLeft ||
clickNotification.buttonShiftUpLeft ||
clickNotification.buttonOnOffLeft ||
clickNotification.buttonPowerDownLeft) {
actionHandler.decreaseGear();
} else if (clickNotification.buttonShiftUpRight ||
clickNotification.buttonShiftDownRight ||
clickNotification.buttonOnOffLeft) {
// TODO remove buttonZ once the assignment is fixed for real
clickNotification.buttonOnOffRight ||
clickNotification.buttonPowerUpLeft) {
actionHandler.increaseGear();
}
/*if (clickNotification.buttonA) {

View File

@@ -4,15 +4,13 @@ import '../protocol/zwift.pb.dart';
import 'notification.dart';
class ClickNotification extends BaseNotification {
static const int BTN_PRESSED = 0;
bool buttonUp = false;
bool buttonDown = false;
ClickNotification(Uint8List message) {
final status = ClickKeyPadStatus.fromBuffer(message);
buttonUp = status.buttonPlus.value == BTN_PRESSED;
buttonDown = status.buttonMinus.value == BTN_PRESSED;
buttonUp = status.buttonPlus == PlayButtonStatus.ON;
buttonDown = status.buttonMinus == PlayButtonStatus.ON;
}
@override

View File

@@ -4,21 +4,19 @@ import 'package:swift_control/bluetooth/messages/notification.dart';
import 'package:swift_control/bluetooth/protocol/zwift.pb.dart';
class PlayNotification extends BaseNotification {
static const int BTN_PRESSED = 0;
late bool rightPad, buttonY, buttonZ, buttonA, buttonB, buttonOn, buttonShift;
late int analogLR, analogUD;
PlayNotification(Uint8List message) {
final status = PlayKeyPadStatus.fromBuffer(message);
rightPad = status.rightPad.value == BTN_PRESSED;
buttonY = status.buttonYUp.value == BTN_PRESSED;
buttonZ = status.buttonZLeft.value == BTN_PRESSED;
buttonA = status.buttonARight.value == BTN_PRESSED;
buttonB = status.buttonBDown.value == BTN_PRESSED;
buttonOn = status.buttonOn.value == BTN_PRESSED;
buttonShift = status.buttonShift.value == BTN_PRESSED;
rightPad = status.rightPad == PlayButtonStatus.ON;
buttonY = status.buttonYUp == PlayButtonStatus.ON;
buttonZ = status.buttonZLeft == PlayButtonStatus.ON;
buttonA = status.buttonARight == PlayButtonStatus.ON;
buttonB = status.buttonBDown == PlayButtonStatus.ON;
buttonOn = status.buttonOn == PlayButtonStatus.ON;
buttonShift = status.buttonShift == PlayButtonStatus.ON;
analogLR = status.analogLR;
analogUD = status.analogUD;
}

View File

@@ -25,8 +25,8 @@ class PlayKeyPadStatus extends $pb.GeneratedMessage {
PlayButtonStatus? buttonZLeft,
PlayButtonStatus? buttonARight,
PlayButtonStatus? buttonBDown,
PlayButtonStatus? buttonOn,
PlayButtonStatus? buttonShift,
PlayButtonStatus? buttonOn,
$core.int? analogLR,
$core.int? analogUD,
}) {
@@ -46,12 +46,12 @@ class PlayKeyPadStatus extends $pb.GeneratedMessage {
if (buttonBDown != null) {
$result.buttonBDown = buttonBDown;
}
if (buttonOn != null) {
$result.buttonOn = buttonOn;
}
if (buttonShift != null) {
$result.buttonShift = buttonShift;
}
if (buttonOn != null) {
$result.buttonOn = buttonOn;
}
if (analogLR != null) {
$result.analogLR = analogLR;
}
@@ -70,8 +70,8 @@ class PlayKeyPadStatus extends $pb.GeneratedMessage {
..e<PlayButtonStatus>(3, _omitFieldNames ? '' : 'ButtonZLeft', $pb.PbFieldType.OE, protoName: 'Button_Z_Left', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..e<PlayButtonStatus>(4, _omitFieldNames ? '' : 'ButtonARight', $pb.PbFieldType.OE, protoName: 'Button_A_Right', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..e<PlayButtonStatus>(5, _omitFieldNames ? '' : 'ButtonBDown', $pb.PbFieldType.OE, protoName: 'Button_B_Down', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..e<PlayButtonStatus>(6, _omitFieldNames ? '' : 'ButtonOn', $pb.PbFieldType.OE, protoName: 'Button_On', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..e<PlayButtonStatus>(7, _omitFieldNames ? '' : 'ButtonShift', $pb.PbFieldType.OE, protoName: 'Button_Shift', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..e<PlayButtonStatus>(6, _omitFieldNames ? '' : 'ButtonShift', $pb.PbFieldType.OE, protoName: 'Button_Shift', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..e<PlayButtonStatus>(7, _omitFieldNames ? '' : 'ButtonOn', $pb.PbFieldType.OE, protoName: 'Button_On', defaultOrMaker: PlayButtonStatus.ON, valueOf: PlayButtonStatus.valueOf, enumValues: PlayButtonStatus.values)
..a<$core.int>(8, _omitFieldNames ? '' : 'AnalogLR', $pb.PbFieldType.OS3, protoName: 'Analog_LR')
..a<$core.int>(9, _omitFieldNames ? '' : 'AnalogUD', $pb.PbFieldType.OS3, protoName: 'Analog_UD')
..hasRequiredFields = false
@@ -144,22 +144,22 @@ class PlayKeyPadStatus extends $pb.GeneratedMessage {
void clearButtonBDown() => clearField(5);
@$pb.TagNumber(6)
PlayButtonStatus get buttonOn => $_getN(5);
PlayButtonStatus get buttonShift => $_getN(5);
@$pb.TagNumber(6)
set buttonOn(PlayButtonStatus v) { setField(6, v); }
set buttonShift(PlayButtonStatus v) { setField(6, v); }
@$pb.TagNumber(6)
$core.bool hasButtonOn() => $_has(5);
$core.bool hasButtonShift() => $_has(5);
@$pb.TagNumber(6)
void clearButtonOn() => clearField(6);
void clearButtonShift() => clearField(6);
@$pb.TagNumber(7)
PlayButtonStatus get buttonShift => $_getN(6);
PlayButtonStatus get buttonOn => $_getN(6);
@$pb.TagNumber(7)
set buttonShift(PlayButtonStatus v) { setField(7, v); }
set buttonOn(PlayButtonStatus v) { setField(7, v); }
@$pb.TagNumber(7)
$core.bool hasButtonShift() => $_has(6);
$core.bool hasButtonOn() => $_has(6);
@$pb.TagNumber(7)
void clearButtonShift() => clearField(7);
void clearButtonOn() => clearField(7);
@$pb.TagNumber(8)
$core.int get analogLR => $_getIZ(7);

View File

@@ -82,8 +82,8 @@ const PlayKeyPadStatus$json = {
{'1': 'Button_Z_Left', '3': 3, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonZLeft'},
{'1': 'Button_A_Right', '3': 4, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonARight'},
{'1': 'Button_B_Down', '3': 5, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonBDown'},
{'1': 'Button_On', '3': 6, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonOn'},
{'1': 'Button_Shift', '3': 7, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonShift'},
{'1': 'Button_Shift', '3': 6, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonShift'},
{'1': 'Button_On', '3': 7, '4': 1, '5': 14, '6': '.de.jonasbark.PlayButtonStatus', '10': 'ButtonOn'},
{'1': 'Analog_LR', '3': 8, '4': 1, '5': 17, '10': 'AnalogLR'},
{'1': 'Analog_UD', '3': 9, '4': 1, '5': 17, '10': 'AnalogUD'},
],
@@ -97,9 +97,9 @@ final $typed_data.Uint8List playKeyPadStatusDescriptor = $convert.base64Decode(
'4uZGUuam9uYXNiYXJrLlBsYXlCdXR0b25TdGF0dXNSC0J1dHRvblpMZWZ0EkQKDkJ1dHRvbl9B'
'X1JpZ2h0GAQgASgOMh4uZGUuam9uYXNiYXJrLlBsYXlCdXR0b25TdGF0dXNSDEJ1dHRvbkFSaW'
'dodBJCCg1CdXR0b25fQl9Eb3duGAUgASgOMh4uZGUuam9uYXNiYXJrLlBsYXlCdXR0b25TdGF0'
'dXNSC0J1dHRvbkJEb3duEjsKCUJ1dHRvbl9PbhgGIAEoDjIeLmRlLmpvbmFzYmFyay5QbGF5Qn'
'V0dG9uU3RhdHVzUghCdXR0b25PbhJBCgxCdXR0b25fU2hpZnQYByABKA4yHi5kZS5qb25hc2Jh'
'cmsuUGxheUJ1dHRvblN0YXR1c1ILQnV0dG9uU2hpZnQSGwoJQW5hbG9nX0xSGAggASgRUghBbm'
'dXNSC0J1dHRvbkJEb3duEkEKDEJ1dHRvbl9TaGlmdBgGIAEoDjIeLmRlLmpvbmFzYmFyay5QbG'
'F5QnV0dG9uU3RhdHVzUgtCdXR0b25TaGlmdBI7CglCdXR0b25fT24YByABKA4yHi5kZS5qb25h'
'c2JhcmsuUGxheUJ1dHRvblN0YXR1c1IIQnV0dG9uT24SGwoJQW5hbG9nX0xSGAggASgRUghBbm'
'Fsb2dMUhIbCglBbmFsb2dfVUQYCSABKBFSCEFuYWxvZ1VE');
@$core.Deprecated('Use playCommandParametersDescriptor instead')

View File

@@ -16,8 +16,8 @@ message PlayKeyPadStatus {
optional PlayButtonStatus Button_Z_Left = 3;
optional PlayButtonStatus Button_A_Right = 4;
optional PlayButtonStatus Button_B_Down = 5;
optional PlayButtonStatus Button_On = 6;
optional PlayButtonStatus Button_Shift = 7;
optional PlayButtonStatus Button_Shift = 6;
optional PlayButtonStatus Button_On = 7;
optional sint32 Analog_LR = 8;
optional sint32 Analog_UD = 9;
}

View File

@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:swift_control/main.dart';
import 'package:swift_control/pages/touch_area.dart';
import 'package:swift_control/widgets/logviewer.dart';
import 'package:swift_control/widgets/title.dart';
import '../bluetooth/devices/base_device.dart';
import '../widgets/menu.dart';
@@ -48,7 +49,7 @@ class _DevicePageState extends State<DevicePage> {
},
child: Scaffold(
appBar: AppBar(
title: Text('SwiftControl'),
title: AppTitle(),
actions: buildMenuButtons(),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),

View File

@@ -7,6 +7,7 @@ import 'package:swift_control/main.dart';
import 'package:swift_control/utils/requirements/multi.dart';
import 'package:swift_control/utils/requirements/platform.dart';
import 'package:swift_control/widgets/menu.dart';
import 'package:swift_control/widgets/title.dart';
import 'device.dart';
@@ -65,7 +66,7 @@ class _RequirementsPageState extends State<RequirementsPage> with WidgetsBinding
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SwiftControl'),
title: AppTitle(),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
actions: buildMenuButtons(),
),

94
lib/widgets/title.dart Normal file
View File

@@ -0,0 +1,94 @@
import 'dart:convert';
import 'dart:io';
import 'package:dartx/dartx.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:package_info_plus/package_info_plus.dart';
import 'package:swift_control/widgets/small_progress_indicator.dart';
import 'package:url_launcher/url_launcher_string.dart';
String? _latestVersionUrlValue;
PackageInfo? _packageInfoValue;
class AppTitle extends StatefulWidget {
const AppTitle({super.key});
@override
State<AppTitle> createState() => _AppTitleState();
}
class _AppTitleState extends State<AppTitle> {
Future<String?> getLatestVersionUrlIfNewer() async {
final response = await http.get(Uri.parse('https://api.github.com/repos/jonasbark/swiftcontrol/releases/latest'));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final latestVersion = data['tag_name'].split('+').first;
final currentVersion = 'v${_packageInfoValue!.version}';
if (latestVersion != null && latestVersion != currentVersion) {
final assets = data['assets'] as List;
if (Platform.isAndroid) {
final apkUrl = assets.firstOrNullWhere((asset) => asset['name'].endsWith('.apk'))['browser_download_url'];
return apkUrl;
} else if (Platform.isMacOS) {
final dmgUrl =
assets.firstOrNullWhere((asset) => asset['name'].endsWith('.macos.zip'))['browser_download_url'];
return dmgUrl;
} else if (Platform.isWindows) {
final appImageUrl =
assets.firstOrNullWhere((asset) => asset['name'].endsWith('.windows.zip'))['browser_download_url'];
return appImageUrl;
}
}
}
return null;
}
@override
void initState() {
super.initState();
if (_packageInfoValue == null) {
PackageInfo.fromPlatform().then((value) {
setState(() {
_packageInfoValue = value;
});
_loadLatestVersionUrl();
});
} else {
_loadLatestVersionUrl();
}
}
void _loadLatestVersionUrl() async {
if (_latestVersionUrlValue == null && !kIsWeb) {
final url = await getLatestVersionUrlIfNewer();
if (url != null && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('New version available: ${url.split("/").takeLast(2).first.split('%').first}'),
duration: Duration(seconds: 1337),
action: SnackBarAction(
label: 'Download',
onPressed: () {
launchUrlString(url);
},
),
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Row(
spacing: 8,
children: [
Text('SwiftControl'),
if (_packageInfoValue != null) Text('v${_packageInfoValue!.version}') else SmallProgressIndicator(),
],
);
}
}

View File

@@ -8,6 +8,7 @@ import Foundation
import file_selector_macos
import flutter_local_notifications
import keypress_simulator_macos
import package_info_plus
import shared_preferences_foundation
import universal_ble
import url_launcher_macos
@@ -16,6 +17,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
KeypressSimulatorMacosPlugin.register(with: registry.registrar(forPlugin: "KeypressSimulatorMacosPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))

View File

@@ -6,6 +6,8 @@ PODS:
- FlutterMacOS (1.0.0)
- keypress_simulator_macos (0.0.1):
- FlutterMacOS
- package_info_plus (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
@@ -20,6 +22,7 @@ DEPENDENCIES:
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- keypress_simulator_macos (from `Flutter/ephemeral/.symlinks/plugins/keypress_simulator_macos/macos`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
@@ -33,6 +36,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
keypress_simulator_macos:
:path: Flutter/ephemeral/.symlinks/plugins/keypress_simulator_macos/macos
package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
universal_ble:
@@ -45,6 +50,7 @@ SPEC CHECKSUMS:
flutter_local_notifications: 4ccab5b7a22835214a6672e3f9c5e8ae207dab36
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
keypress_simulator_macos: f8556f9101f9f2f175652e0bceddf0fe82a4c6b2
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404

View File

@@ -12,5 +12,7 @@
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

View File

@@ -4,5 +4,7 @@
<dict>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>

View File

@@ -288,7 +288,7 @@ packages:
source: sdk
version: "0.0.0"
http:
dependency: transitive
dependency: "direct main"
description:
name: http
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
@@ -487,6 +487,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191"
url: "https://pub.dev"
source: hosted
version: "8.3.0"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
path:
dependency: transitive
description:
@@ -852,6 +868,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
win32:
dependency: transitive
description:
name: win32
sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f
url: "https://pub.dev"
source: hosted
version: "5.12.0"
xdg_directories:
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.1.5+0
version: 1.1.6+0
environment:
sdk: ^3.7.0
@@ -21,8 +21,10 @@ dependencies:
keypress_simulator: ^0.2.0
shared_preferences: ^2.5.3
flex_color_scheme: ^8.2.0
package_info_plus: ^8.3.0
accessibility:
path: accessibility
http: ^1.3.0
dev_dependencies:
flutter_test: