Compare commits

..

3 Commits
login ... main

Author SHA1 Message Date
Jonas Bark
02c038daaa additional fixes 2026-02-16 18:32:31 +01:00
Jonas Bark
05352d7118 additional fixes 2026-02-16 18:22:16 +01:00
Jonas Bark
5c7e8b923b fix shimano di2 implementation 2026-02-16 17:58:10 +01:00
30 changed files with 108 additions and 886 deletions

View File

@@ -51,13 +51,6 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with YOUR_SCHEME://YOUR_HOST -->
<data android:scheme="bikecontrol" />
</intent-filter>
</activity>
<receiver

View File

@@ -20,5 +20,7 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
</dict>
</plist>

View File

@@ -1,16 +1,4 @@
PODS:
- app_links (6.4.1):
- Flutter
- AppAuth (2.0.0):
- AppAuth/Core (= 2.0.0)
- AppAuth/ExternalUserAgent (= 2.0.0)
- AppAuth/Core (2.0.0)
- AppAuth/ExternalUserAgent (2.0.0):
- AppAuth/Core
- AppCheckCore (11.2.0):
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- audio_session (0.0.1):
- Flutter
- bluetooth_low_energy_darwin (0.0.1):
@@ -28,33 +16,6 @@ PODS:
- Flutter
- gamepads_ios (0.1.1):
- Flutter
- google_sign_in_ios (0.0.1):
- Flutter
- FlutterMacOS
- GoogleSignIn (~> 9.0)
- GTMSessionFetcher (>= 3.4.0)
- GoogleSignIn (9.1.0):
- AppAuth (~> 2.0)
- AppCheckCore (~> 11.0)
- GTMAppAuth (~> 5.0)
- GTMSessionFetcher/Core (~> 3.3)
- GoogleUtilities/Environment (8.1.0):
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.1.0)
- GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMAppAuth (5.0.0):
- AppAuth/Core (~> 2.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3)
- GTMSessionFetcher (3.5.0):
- GTMSessionFetcher/Full (= 3.5.0)
- GTMSessionFetcher/Core (3.5.0)
- GTMSessionFetcher/Full (3.5.0):
- GTMSessionFetcher/Core
- image_picker_ios (0.0.1):
- Flutter
- in_app_purchase_storekit (0.0.1):
@@ -77,7 +38,6 @@ PODS:
- Flutter
- permission_handler_apple (9.3.0):
- Flutter
- PromisesObjC (2.4.0)
- purchases_flutter (9.10.6):
- Flutter
- PurchasesHybridCommon (= 17.27.1)
@@ -99,8 +59,6 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- Flutter
- universal_ble (0.0.1):
- Flutter
- FlutterMacOS
@@ -110,7 +68,6 @@ PODS:
- Flutter
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- bluetooth_low_energy_darwin (from `.symlinks/plugins/bluetooth_low_energy_darwin/darwin`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
@@ -119,7 +76,6 @@ DEPENDENCIES:
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
- gamepads_ios (from `.symlinks/plugins/gamepads_ios/ios`)
- google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
@@ -135,28 +91,18 @@ DEPENDENCIES:
- restart_app (from `.symlinks/plugins/restart_app/ios`)
- sensors_plus (from `.symlinks/plugins/sensors_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- universal_ble (from `.symlinks/plugins/universal_ble/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS:
trunk:
- AppAuth
- AppCheckCore
- GoogleSignIn
- GoogleUtilities
- GTMAppAuth
- GTMSessionFetcher
- PromisesObjC
- PurchasesHybridCommon
- PurchasesHybridCommonUI
- RevenueCat
- RevenueCatUI
EXTERNAL SOURCES:
app_links:
:path: ".symlinks/plugins/app_links/ios"
audio_session:
:path: ".symlinks/plugins/audio_session/ios"
bluetooth_low_energy_darwin:
@@ -173,8 +119,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_volume_controller/ios"
gamepads_ios:
:path: ".symlinks/plugins/gamepads_ios/ios"
google_sign_in_ios:
:path: ".symlinks/plugins/google_sign_in_ios/darwin"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
in_app_purchase_storekit:
@@ -205,8 +149,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sensors_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sign_in_with_apple:
:path: ".symlinks/plugins/sign_in_with_apple/ios"
universal_ble:
:path: ".symlinks/plugins/universal_ble/darwin"
url_launcher_ios:
@@ -215,9 +157,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
app_links: 585674be3c6661708e6cd794ab4f39fb9d8356f9
AppAuth: 1c1a8afa7e12f2ec3a294d9882dfa5ab7d3cb063
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe
bluetooth_low_energy_darwin: 50bc79258e60586e4c4bed5948bd31d925f37fac
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
@@ -226,11 +165,6 @@ SPEC CHECKSUMS:
flutter_secure_storage_darwin: 557817588b80e60213cbecb573c45c76b788018d
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
gamepads_ios: 1d2930c7a4450a9a1b57444ebf305a6a6cbeea0b
google_sign_in_ios: 7336a3372ea93ea56a21e126a0055ffca3723601
GoogleSignIn: fcee2257188d5eda57a5e2b6a715550ffff9206d
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
GTMAppAuth: 217a876b249c3c585a54fd6f73e6b58c4f5c4238
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b
in_app_purchase_storekit: 2342c0a5da86593124d08dd13d920f39a52b273a
in_app_review: 436034b18594851a7328d7f1c2ed5ec235b79cfc
@@ -241,7 +175,6 @@ SPEC CHECKSUMS:
nsd_ios: 8c37babdc6538e3350dbed3a52674d2edde98173
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
purchases_flutter: b3c0792197f69cd7af4c2449b71df6ac6378aace
purchases_ui_flutter: caae6d62ea23c6fe964992a28353211cc74b244a
PurchasesHybridCommon: 027f03312519c51056457eb2e4f7ee1c91b61b8f
@@ -251,7 +184,6 @@ SPEC CHECKSUMS:
RevenueCatUI: ac7492873928e9e7f297e5e27a7c4f23f9008326
sensors_plus: 7229095999f30740798f0eeef5cd120357a8f4f2
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa
wakelock_plus: 76957ab028e12bfa4e66813c99e46637f367fc7e

View File

@@ -280,10 +280,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@@ -372,10 +376,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";

View File

@@ -22,19 +22,6 @@
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.709945926587-0iierajthibf4vhqf85fc7bbpgbdgua2</string>
</array>
</dict>
</array>
<key>GIDClientID</key>
<string>709945926587-0iierajthibf4vhqf85fc7bbpgbdgua2.apps.googleusercontent.com</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>ITSAppUsesNonExemptEncryption</key>

View File

@@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>keychain-access-groups</key>
<array/>
</dict>

View File

@@ -7,7 +7,6 @@ import 'package:bike_control/bluetooth/devices/trainer_connection.dart';
import 'package:bike_control/bluetooth/messages/notification.dart' show AlertNotification, LogNotification;
import 'package:bike_control/utils/actions/base_actions.dart';
import 'package:bike_control/utils/core.dart';
import 'package:bike_control/utils/keymap/apps/training_peaks.dart';
import 'package:bike_control/utils/keymap/buttons.dart';
import 'package:bike_control/utils/keymap/keymap.dart';
import 'package:bike_control/widgets/title.dart';
@@ -111,7 +110,7 @@ class OpenBikeControlBluetoothEmulator extends TrainerConnection {
_peripheralManager.characteristicWriteRequested.forEach((eventArgs) async {
final characteristic = eventArgs.characteristic;
final request = eventArgs.request;
var value = request.value;
final value = request.value;
if (kDebugMode) {
print('Write request for characteristic: ${characteristic.uuid}: ${bytesToReadableHex(value)}');
}
@@ -119,15 +118,12 @@ class OpenBikeControlBluetoothEmulator extends TrainerConnection {
switch (eventArgs.characteristic.uuid.toString().toLowerCase()) {
case OpenBikeControlConstants.APPINFO_CHARACTERISTIC_UUID:
try {
if (core.settings.getTrainerApp() is TrainingPeaks) {
if (firstAppInfoMessage == null) {
firstAppInfoMessage = value;
return;
} else {
value = Uint8List.fromList([...firstAppInfoMessage!, ...value]);
}
}
final appInfo = OpenBikeProtocolParser.parseAppInfo(value);
// use this fallback if first message is incomplete (e.g. TrainingPeaks on macOS)
AppInfo appInfo = OpenBikeProtocolParser.parseAppInfo(
Uint8List.fromList([...?firstAppInfoMessage, ...value]),
);
firstAppInfoMessage = null;
isConnected.value = true;
connectedApp.value = appInfo;
supportedActions = appInfo.supportedButtons.mapNotNull((b) => b.action).toList();
@@ -137,6 +133,10 @@ class OpenBikeControlBluetoothEmulator extends TrainerConnection {
core.connection.signalNotification(LogNotification('Parsed App Info: $appInfo'));
} catch (e) {
core.connection.signalNotification(LogNotification('Error parsing App Info ${bytesToHex(value)}: $e'));
if (firstAppInfoMessage == null) {
firstAppInfoMessage = value;
return;
}
}
break;
default:

View File

@@ -87,29 +87,57 @@ class ShimanoDi2 extends BluetoothDevice {
});
if (actualChange) {
final buttonsToTrigger = _lastButtons.entries
.where((entry) {
final type = entry.value.type;
return type != _Di2State.released;
})
.map((entry) => availableButtons.firstWhere((button) => button.name == 'D-Fly Channel ${entry.key + 1}'))
.toList();
final Map<_Di2State, List<ControllerButton>> mapped = _lastButtons.entries.groupBy((e) => e.value.type).map((
key,
value,
) {
final buttons = value
.map((entry) => availableButtons.firstWhere((button) => button.name == 'D-Fly Channel ${entry.key + 1}'))
.toList();
return MapEntry(key, buttons);
});
Logger.debug('Buttons to trigger: ${buttonsToTrigger.map((b) => b.name).join(', ')}');
handleButtonsClicked(buttonsToTrigger);
final shortPress = [...?mapped[_Di2State.shortPress], ...?mapped[_Di2State.doublePress]];
if (shortPress.isNotEmpty) {
Logger.debug('Short Press Buttons to trigger: ${shortPress.map((b) => b.name).join(', ')}');
handleButtonsClicked(shortPress);
handleButtonsClicked([]);
_resetButtonsForState([_Di2State.shortPress]);
}
final doublePress = _lastButtons.entries
.filter((entry) => entry.value.type == _Di2State.doublePress)
.map((entry) => availableButtons.firstWhere((button) => button.name == 'D-Fly Channel ${entry.key + 1}'))
.toList();
final longPress = mapped[_Di2State.longPress] ?? [];
if (longPress.isNotEmpty) {
Logger.debug('Long Press Buttons to trigger: ${longPress.map((b) => b.name).join(', ')}');
handleButtonsClicked(longPress);
}
final released = mapped[_Di2State.released] ?? [];
final keepPress = mapped[_Di2State.longPress] ?? [];
if (released.isNotEmpty && keepPress.isEmpty) {
Logger.debug('Releasing all Buttons');
handleButtonsClicked([]);
}
final doublePress = mapped[_Di2State.doublePress] ?? [];
if (doublePress.isNotEmpty) {
Logger.debug('Buttons to still trigger: ${doublePress.map((b) => b.name).join(', ')}');
handleButtonsClicked(doublePress);
handleButtonsClicked([]);
_resetButtonsForState([_Di2State.doublePress]);
}
}
}
}
void _resetButtonsForState(List<_Di2State> list) {
_lastButtons.forEach((key, value) {
if (list.contains(value.type)) {
_lastButtons[key] = (value: value.value, type: _Di2State.released);
}
});
}
@override
Widget showInformation(BuildContext context) {
return Column(

View File

@@ -1,131 +0,0 @@
import 'dart:convert';
import 'dart:io';
import 'package:bike_control/utils/requirements/windows.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/foundation.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:sign_in_button/sign_in_button.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import '../utils/core.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
const Text('Please sign in to continue'),
const SizedBox(height: 16),
SignInButton(
Buttons.google,
onPressed: _nativeGoogleSignIn,
),
SignInButton(
Buttons.apple,
onPressed: _signInWithApple,
),
Button.secondary(
child: Text('Logout'),
onPressed: () {
core.supabase.auth.signOut();
},
),
if (kDebugMode && Platform.isWindows)
Button.secondary(
child: Text("Register"),
onPressed: () {
WindowsProtocolHandler().register("bikecontrol");
},
),
],
),
);
}
Future<AuthResponse?> _nativeGoogleSignIn() async {
if (Platform.isAndroid || Platform.isIOS) {
/// Web Client ID that you registered with Google Cloud.
const webClientId = '709945926587-bgk7j9qc86t7nuemu100ngvl9c7irv9k.apps.googleusercontent.com';
/// iOS Client ID that you registered with Google Cloud.
const iosClientId = '709945926587-0iierajthibf4vhqf85fc7bbpgbdgua2.apps.googleusercontent.com';
final scopes = ['email'];
final googleSignIn = GoogleSignIn.instance;
await googleSignIn.initialize(
serverClientId: webClientId,
clientId: iosClientId,
);
GoogleSignInAccount? googleUser = await googleSignIn.attemptLightweightAuthentication(reportAllExceptions: true);
googleUser ??= await googleSignIn.authenticate();
/// Authorization is required to obtain the access token with the appropriate scopes for Supabase authentication,
/// while also granting permission to access user information.
final authorization =
await googleUser.authorizationClient.authorizationForScopes(scopes) ??
await googleUser.authorizationClient.authorizeScopes(scopes);
final idToken = googleUser.authentication.idToken;
if (idToken == null) {
throw AuthException('No ID Token found.');
}
final response = await core.supabase.auth.signInWithIdToken(
provider: OAuthProvider.google,
idToken: idToken,
accessToken: authorization.accessToken,
);
return response;
} else {
await core.supabase.auth.signInWithOAuth(
OAuthProvider.google,
redirectTo: kIsWeb ? null : 'bikecontrol://login/',
authScreenLaunchMode: kIsWeb
? LaunchMode.platformDefault
: LaunchMode.externalApplication, // Launch the auth screen in a new webview on mobile.
);
return null;
}
}
/// Performs Apple sign in on iOS or macOS
Future<AuthResponse?> _signInWithApple() async {
if (Platform.isIOS || Platform.isMacOS) {
final rawNonce = core.supabase.auth.generateRawNonce();
final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString();
final credential = await SignInWithApple.getAppleIDCredential(
scopes: [AppleIDAuthorizationScopes.email],
nonce: hashedNonce,
);
final idToken = credential.identityToken;
if (idToken == null) {
throw const AuthException('Could not find ID Token from generated credential.');
}
final authResponse = await core.supabase.auth.signInWithIdToken(
provider: OAuthProvider.apple,
idToken: idToken,
nonce: rawNonce,
);
return authResponse;
} else {
await core.supabase.auth.signInWithOAuth(
OAuthProvider.apple,
redirectTo: kIsWeb ? null : 'bikecontrol://login/',
authScreenLaunchMode: kIsWeb ? LaunchMode.platformDefault : LaunchMode.externalApplication,
);
return null;
}
}
}

View File

@@ -22,7 +22,6 @@ import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:prop/prop.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:universal_ble/universal_ble.dart';
import '../bluetooth/connection.dart';
@@ -40,7 +39,6 @@ class Core {
final settings = Settings();
final connection = Connection();
late final supabase = Supabase.instance.client;
late final whooshLink = WhooshLink();
late final zwiftEmulator = ZwiftEmulator();
late final zwiftMdnsEmulator = FtmsMdnsEmulator();

View File

@@ -10,11 +10,9 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:prop/prop.dart' as zp;
import 'package:prop/prop.dart' hide LogLevel;
import 'package:purchases_flutter/purchases_flutter.dart';
import 'package:purchases_ui_flutter/purchases_ui_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:version/version.dart';
/// RevenueCat-based IAP service for iOS, macOS, and Android
@@ -41,8 +39,6 @@ class RevenueCatService {
int? _dailyCommandCount;
StreamSubscription<CustomerInfo>? _customerInfoSubscription;
late final StreamSubscription<AuthState> _authSubscription;
RevenueCatService(
this._prefs, {
required this.isPurchasedNotifier,
@@ -124,34 +120,6 @@ class RevenueCatService {
if (!isTrialExpired && Platform.isAndroid) {
setDailyCommandLimit(80);
}
_authSubscription = core.supabase.auth.onAuthStateChange.listen((data) {
final AuthChangeEvent event = data.event;
final Session? session = data.session;
Logger.info('event: $event, session: ${session?.user.id} via ${session?.user.email}');
switch (event) {
case AuthChangeEvent.initialSession:
setAttributes();
case AuthChangeEvent.signedIn:
setAttributes();
// handle signed in
case AuthChangeEvent.signedOut:
setAttributes();
// handle signed out
case AuthChangeEvent.passwordRecovery:
// handle password recovery
case AuthChangeEvent.tokenRefreshed:
// handle token refreshed
case AuthChangeEvent.userUpdated:
// handle user updated
case AuthChangeEvent.userDeleted:
// handle user deleted
case AuthChangeEvent.mfaChallengeVerified:
// handle mfa challenge verified
}
});
} catch (e, s) {
recordError(e, s, context: 'Initializing RevenueCat Service');
core.connection.signalNotification(
@@ -402,11 +370,8 @@ class RevenueCatService {
}
Future<void> setAttributes() async {
final Session? session = core.supabase.auth.currentSession;
// attributes are fully anonymous
await Purchases.setAttributes({
if (session?.user.id != null) "bikecontrol_user": session!.user.id,
"bikecontrol_trainer": core.settings.getTrainerApp()?.name ?? '-',
"bikecontrol_target": core.settings.getLastTarget()?.name ?? '-',
if (core.connection.controllerDevices.isNotEmpty)

View File

@@ -8,9 +8,6 @@ import 'package:bike_control/utils/windows_store_environment.dart';
import 'package:bike_control/widgets/ui/toast.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:gotrue/src/types/auth_state.dart';
import 'package:prop/prop.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:windows_iap/windows_iap.dart';
/// Windows-specific IAP service
@@ -47,32 +44,6 @@ class WindowsIAPService {
_lastCommandDate = await _prefs.read(key: _lastCommandDateKey);
_dailyCommandCount = int.tryParse(await _prefs.read(key: _dailyCommandCountKey) ?? '0');
_isInitialized = true;
_authSubscription = core.supabase.auth.onAuthStateChange.listen((data) {
final AuthChangeEvent event = data.event;
final Session? session = data.session;
Logger.info('event: $event, session: ${session?.user.id} via ${session?.user.email}');
switch (event) {
case AuthChangeEvent.initialSession:
case AuthChangeEvent.signedIn:
// handle signed in
case AuthChangeEvent.signedOut:
// handle signed out
case AuthChangeEvent.passwordRecovery:
// handle password recovery
case AuthChangeEvent.tokenRefreshed:
// handle token refreshed
case AuthChangeEvent.userUpdated:
// handle user updated
case AuthChangeEvent.userDeleted:
// handle user deleted
case AuthChangeEvent.mfaChallengeVerified:
// handle mfa challenge verified
}
});
} catch (e, s) {
recordError(e, s, context: 'Initializing');
debugPrint('Failed to initialize Windows IAP: $e');
@@ -137,8 +108,6 @@ class WindowsIAPService {
/// Get the number of days remaining in the trial
int trialDaysRemaining = 0;
late final StreamSubscription<AuthState> _authSubscription;
/// Check if the trial has expired
bool get isTrialExpired {
return !IAPManager.instance.isPurchased.value && hasTrialStarted && trialDaysRemaining <= 0;

View File

@@ -1,70 +0,0 @@
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:win32/win32.dart';
const _hive = HKEY_CURRENT_USER;
class WindowsProtocolHandler {
List<String> getArguments(List<String>? arguments) {
if (arguments == null) return ['%s'];
if (arguments.isEmpty && !arguments.any((e) => e.contains('%s'))) {
throw ArgumentError('arguments must contain at least 1 instance of "%s"');
}
return arguments;
}
void register(String scheme, {String? executable, List<String>? arguments}) {
if (defaultTargetPlatform != TargetPlatform.windows) return;
final prefix = _regPrefix(scheme);
final capitalized = scheme[0].toUpperCase() + scheme.substring(1);
final args = getArguments(arguments).map((a) => _sanitize(a));
final cmd = '${executable ?? Platform.resolvedExecutable} ${args.join(' ')}';
_regCreateStringKey(_hive, prefix, '', 'URL:$capitalized');
_regCreateStringKey(_hive, prefix, 'URL Protocol', '');
_regCreateStringKey(_hive, '$prefix\\shell\\open\\command', '', cmd);
}
void unregister(String scheme) {
if (defaultTargetPlatform != TargetPlatform.windows) return;
final txtKey = TEXT(_regPrefix(scheme));
try {
RegDeleteTree(HKEY_CURRENT_USER, txtKey);
} finally {
free(txtKey);
}
}
String _regPrefix(String scheme) => 'SOFTWARE\\Classes\\$scheme';
int _regCreateStringKey(int hKey, String key, String valueName, String data) {
final txtKey = TEXT(key);
final txtValue = TEXT(valueName);
final txtData = TEXT(data);
try {
return RegSetKeyValue(
hKey,
txtKey,
txtValue,
REG_SZ,
txtData,
txtData.length * 2 + 2,
);
} finally {
free(txtKey);
free(txtValue);
free(txtData);
}
}
String _sanitize(String value) {
value = value.replaceAll(r'%s', '%1').replaceAll(r'"', '\\"');
return '"$value"';
}
}

View File

@@ -14,7 +14,6 @@ import 'package:path_provider_windows/path_provider_windows.dart';
import 'package:prop/emulators/prefs.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shared_preferences_windows/shared_preferences_windows.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:window_manager/window_manager.dart';
import '../../main.dart';
@@ -50,15 +49,6 @@ class Settings {
final app = getKeyMap();
core.actionHandler.init(app);
try {
await Supabase.initialize(
url: 'https://pikrcyynovdvogrldfnw.supabase.co',
anonKey: const String.fromEnvironment('SUPABASE_ANON_KEY'),
);
} catch (e, s) {
recordError(e, s, context: 'Supabase initialization');
}
// Initialize IAP manager
await IAPManager.instance.initialize();

View File

@@ -1,7 +1,6 @@
import 'dart:io';
import 'package:bike_control/bluetooth/devices/zwift/zwift_clickv2.dart';
import 'package:bike_control/pages/login.dart';
import 'package:bike_control/pages/markdown.dart';
import 'package:bike_control/pages/navigation.dart';
import 'package:bike_control/utils/core.dart';
@@ -150,16 +149,6 @@ class BKMenuButton extends StatelessWidget {
core.connection.disconnectAll();
},
),
MenuButton(
child: Text('Login'),
onPressed: (c) async {
openDrawer(
context: context,
builder: (c) => LoginPage(),
position: OverlayPosition.bottom,
);
},
),
MenuDivider(),
],
if (currentPage == BCPage.logs) ...[

View File

@@ -237,7 +237,7 @@ class _ConnectionMethodState extends State<ConnectionMethod> with WidgetsBinding
Future.wait(widget.requirements.map((e) => e.getStatus())).then((result) {
final allDone = result.every((e) => e);
if (context.mounted) {
if (context.mounted && widget.isEnabled != allDone) {
widget.onChange(allDone);
}
});

View File

@@ -14,6 +14,7 @@ void buildToast({
Duration? duration,
}) {
if (navigatorKey.currentContext?.mounted ?? false) {
final isMobile = MediaQuery.sizeOf(navigatorKey.currentContext!).width < 600;
showToast(
context: navigatorKey.currentContext!,
location: location,
@@ -24,34 +25,37 @@ void buildToast({
LogLevel.LOGLEVEL_ERROR => duration ?? const Duration(seconds: 7),
_ => duration ?? const Duration(seconds: 3),
},
builder: (context, overlay) => SurfaceCard(
filled: switch (level) {
LogLevel.LOGLEVEL_WARNING => true,
LogLevel.LOGLEVEL_ERROR => true,
_ => false,
},
fillColor: switch (level) {
LogLevel.LOGLEVEL_DEBUG => null,
LogLevel.LOGLEVEL_INFO => null,
LogLevel.LOGLEVEL_WARNING => Theme.of(context).colorScheme.chart1,
LogLevel.LOGLEVEL_ERROR => Theme.of(context).colorScheme.destructive,
_ => null,
},
child: Basic(
title: titleWidget ?? Text(title ?? ''),
subtitle: subtitle != null ? Text(subtitle) : null,
trailing: titleWidget is ButtonWidget
? null
: PrimaryButton(
size: ButtonSize.small,
onPressed: () {
// Close the toast programmatically when clicking Undo.
overlay.close();
onClose?.call();
},
child: Text(closeTitle),
),
trailingAlignment: Alignment.center,
builder: (context, overlay) => Container(
margin: EdgeInsets.only(bottom: isMobile ? 50 : 0),
child: SurfaceCard(
filled: switch (level) {
LogLevel.LOGLEVEL_WARNING => true,
LogLevel.LOGLEVEL_ERROR => true,
_ => false,
},
fillColor: switch (level) {
LogLevel.LOGLEVEL_DEBUG => null,
LogLevel.LOGLEVEL_INFO => null,
LogLevel.LOGLEVEL_WARNING => Theme.of(context).colorScheme.chart1,
LogLevel.LOGLEVEL_ERROR => Theme.of(context).colorScheme.destructive,
_ => null,
},
child: Basic(
title: titleWidget ?? Text(title ?? ''),
subtitle: subtitle != null ? Text(subtitle) : null,
trailing: titleWidget is ButtonWidget
? null
: PrimaryButton(
size: ButtonSize.small,
onPressed: () {
// Close the toast programmatically when clicking Undo.
overlay.close();
onClose?.call();
},
child: Text(closeTitle),
),
trailingAlignment: Alignment.center,
),
),
),
);

View File

@@ -5,7 +5,6 @@
import FlutterMacOS
import Foundation
import app_links
import audio_session
import bluetooth_low_energy_darwin
import device_info_plus
@@ -14,7 +13,6 @@ import flutter_local_notifications
import flutter_secure_storage_darwin
import flutter_volume_controller
import gamepads_darwin
import google_sign_in_ios
import in_app_purchase_storekit
import in_app_review
import ios_receipt
@@ -26,14 +24,12 @@ import package_info_plus
import purchases_flutter
import screen_retriever_macos
import shared_preferences_foundation
import sign_in_with_apple
import universal_ble
import url_launcher_macos
import wakelock_plus
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
BluetoothLowEnergyDarwinPlugin.register(with: registry.registrar(forPlugin: "BluetoothLowEnergyDarwinPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
@@ -42,7 +38,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
FlutterVolumeControllerPlugin.register(with: registry.registrar(forPlugin: "FlutterVolumeControllerPlugin"))
GamepadsDarwinPlugin.register(with: registry.registrar(forPlugin: "GamepadsDarwinPlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
InAppPurchasePlugin.register(with: registry.registrar(forPlugin: "InAppPurchasePlugin"))
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
IosReceiptPlugin.register(with: registry.registrar(forPlugin: "IosReceiptPlugin"))
@@ -54,7 +49,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PurchasesFlutterPlugin.register(with: registry.registrar(forPlugin: "PurchasesFlutterPlugin"))
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
UniversalBlePlugin.register(with: registry.registrar(forPlugin: "UniversalBlePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))

View File

@@ -1,16 +1,4 @@
PODS:
- app_links (6.4.1):
- FlutterMacOS
- AppAuth (2.0.0):
- AppAuth/Core (= 2.0.0)
- AppAuth/ExternalUserAgent (= 2.0.0)
- AppAuth/Core (2.0.0)
- AppAuth/ExternalUserAgent (2.0.0):
- AppAuth/Core
- AppCheckCore (11.2.0):
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- audio_session (0.0.1):
- FlutterMacOS
- bluetooth_low_energy_darwin (0.0.1):
@@ -30,33 +18,6 @@ PODS:
- FlutterMacOS (1.0.0)
- gamepads_darwin (0.1.1):
- FlutterMacOS
- google_sign_in_ios (0.0.1):
- Flutter
- FlutterMacOS
- GoogleSignIn (~> 9.0)
- GTMSessionFetcher (>= 3.4.0)
- GoogleSignIn (9.1.0):
- AppAuth (~> 2.0)
- AppCheckCore (~> 11.0)
- GTMAppAuth (~> 5.0)
- GTMSessionFetcher/Core (~> 3.3)
- GoogleUtilities/Environment (8.1.0):
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.1.0)
- GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMAppAuth (5.0.0):
- AppAuth/Core (~> 2.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3)
- GTMSessionFetcher (3.5.0):
- GTMSessionFetcher/Full (= 3.5.0)
- GTMSessionFetcher/Core (3.5.0)
- GTMSessionFetcher/Full (3.5.0):
- GTMSessionFetcher/Core
- in_app_purchase_storekit (0.0.1):
- Flutter
- FlutterMacOS
@@ -75,7 +36,6 @@ PODS:
- FlutterMacOS
- package_info_plus (0.0.1):
- FlutterMacOS
- PromisesObjC (2.4.0)
- purchases_flutter (9.10.6):
- FlutterMacOS
- PurchasesHybridCommon (= 17.27.1)
@@ -87,8 +47,6 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sign_in_with_apple (0.0.1):
- FlutterMacOS
- universal_ble (0.0.1):
- Flutter
- FlutterMacOS
@@ -100,7 +58,6 @@ PODS:
- FlutterMacOS
DEPENDENCIES:
- app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`)
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
- bluetooth_low_energy_darwin (from `Flutter/ephemeral/.symlinks/plugins/bluetooth_low_energy_darwin/darwin`)
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
@@ -110,7 +67,6 @@ DEPENDENCIES:
- flutter_volume_controller (from `Flutter/ephemeral/.symlinks/plugins/flutter_volume_controller/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- gamepads_darwin (from `Flutter/ephemeral/.symlinks/plugins/gamepads_darwin/macos`)
- google_sign_in_ios (from `Flutter/ephemeral/.symlinks/plugins/google_sign_in_ios/darwin`)
- in_app_purchase_storekit (from `Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin`)
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
- ios_receipt (from `Flutter/ephemeral/.symlinks/plugins/ios_receipt/macos`)
@@ -122,7 +78,6 @@ DEPENDENCIES:
- purchases_flutter (from `Flutter/ephemeral/.symlinks/plugins/purchases_flutter/macos`)
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos`)
- universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
@@ -130,19 +85,10 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- AppAuth
- AppCheckCore
- GoogleSignIn
- GoogleUtilities
- GTMAppAuth
- GTMSessionFetcher
- PromisesObjC
- PurchasesHybridCommon
- RevenueCat
EXTERNAL SOURCES:
app_links:
:path: Flutter/ephemeral/.symlinks/plugins/app_links/macos
audio_session:
:path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos
bluetooth_low_energy_darwin:
@@ -161,8 +107,6 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
gamepads_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/gamepads_darwin/macos
google_sign_in_ios:
:path: Flutter/ephemeral/.symlinks/plugins/google_sign_in_ios/darwin
in_app_purchase_storekit:
:path: Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin
in_app_review:
@@ -185,8 +129,6 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
sign_in_with_apple:
:path: Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos
universal_ble:
:path: Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin
url_launcher_macos:
@@ -197,9 +139,6 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS:
app_links: c3185399a5cabc2e610ee5ad52fb7269b84ff869
AppAuth: 1c1a8afa7e12f2ec3a294d9882dfa5ab7d3cb063
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
audio_session: 728ae3823d914f809c485d390274861a24b0904e
bluetooth_low_energy_darwin: 50bc79258e60586e4c4bed5948bd31d925f37fac
device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215
@@ -209,11 +148,6 @@ SPEC CHECKSUMS:
flutter_volume_controller: 25d09126b0d695560f11c80b1311d5063fed882f
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
gamepads_darwin: 07af6c60c282902b66574c800e20b2b26e68fda8
google_sign_in_ios: 7336a3372ea93ea56a21e126a0055ffca3723601
GoogleSignIn: fcee2257188d5eda57a5e2b6a715550ffff9206d
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
GTMAppAuth: 217a876b249c3c585a54fd6f73e6b58c4f5c4238
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
in_app_purchase_storekit: 2342c0a5da86593124d08dd13d920f39a52b273a
in_app_review: 866c9b17c87a7b46a395bda43f5d3ca02deb585a
ios_receipt: 8741a75f39e6ca0866313b73c69a5b674cf5c98c
@@ -222,13 +156,11 @@ SPEC CHECKSUMS:
media_key_detector_macos: a93757a483b4b47283ade432b1af9e427c47329f
nsd_macos: 1a38a38a33adbb396b4c6f303bc076073514cadc
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
purchases_flutter: 55ed35144683d8673f0a4b5077e8f4d8291f291e
PurchasesHybridCommon: 027f03312519c51056457eb2e4f7ee1c91b61b8f
RevenueCat: ecbba580fa453b0d4a0475449b904196d74ef678
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
sign_in_with_apple: a9e97e744e8edc36aefc2723111f652102a7a727
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_macos: 175a54c831f4375a6cf895875f716ee5af3888ce
wakelock_plus: 9d63063ffb7af1c215209769067c57103bde719d

View File

@@ -240,7 +240,6 @@
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
416B733CA2212067A6157BC2 /* [CP] Embed Pods Frameworks */,
64E1C1C2337BD399A29F09AF /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -399,23 +398,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
64E1C1C2337BD399A29F09AF /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
DDE99C1FE0195AFA9D281938 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;

View File

@@ -1,23 +1,8 @@
import Cocoa
import FlutterMacOS
import app_links
@main
class AppDelegate: FlutterAppDelegate {
public override func application(_ application: NSApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([any NSUserActivityRestoring]) -> Void) -> Bool {
guard let url = AppLinks.shared.getUniversalLink(userActivity) else {
return false
}
AppLinks.shared.handleLink(link: url.absoluteString)
return false // Returning true will stop the propagation to other packages
}
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}

View File

@@ -2,25 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.google.GIDSignIn</string>
</array>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>keychain-access-groups</key>
<array/>
</dict>
</plist>

View File

@@ -48,19 +48,5 @@
<string>NSApplication</string>
<key>NSAccessibilityUsageDescription</key>
<string>BikeControl needs to send keys to your trainer app.</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.709945926587-0iierajthibf4vhqf85fc7bbpgbdgua2</string>
<string>bikecontrol</string>
</array>
</dict>
</array>
<key>GIDClientID</key>
<string>709945926587-0iierajthibf4vhqf85fc7bbpgbdgua2.apps.googleusercontent.com</string>
</dict>
</plist>

View File

@@ -2,25 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.google.GIDSignIn</string>
</array>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>keychain-access-groups</key>
<array/>
</dict>
</plist>

2
prop

Submodule prop updated: 9f4cefba4a...a154bf1b7c

View File

@@ -16,14 +16,6 @@ packages:
relative: true
source: path
version: "0.0.1"
adaptive_number:
dependency: transitive
description:
name: adaptive_number
sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
analyzer:
dependency: transitive
description:
@@ -56,38 +48,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.2"
app_links:
dependency: transitive
description:
name: app_links
sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8"
url: "https://pub.dev"
source: hosted
version: "6.4.1"
app_links_linux:
dependency: transitive
description:
name: app_links_linux
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
url: "https://pub.dev"
source: hosted
version: "1.0.3"
app_links_platform_interface:
dependency: transitive
description:
name: app_links_platform_interface
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
app_links_web:
dependency: transitive
description:
name: app_links_web
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
url: "https://pub.dev"
source: hosted
version: "1.0.4"
archive:
dependency: transitive
description:
@@ -280,14 +240,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.7"
dart_jsonwebtoken:
dependency: transitive
description:
name: dart_jsonwebtoken
sha256: "0de65691c1d736e9459f22f654ddd6fd8368a271d4e41aa07e53e6301eff5075"
url: "https://pub.dev"
source: hosted
version: "3.3.1"
dart_style:
dependency: transitive
description:
@@ -345,14 +297,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.3"
ed25519_edwards:
dependency: transitive
description:
name: ed25519_edwards
sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
email_validator:
dependency: transitive
description:
@@ -594,27 +538,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
font_awesome_flutter:
dependency: transitive
description:
name: font_awesome_flutter
sha256: b9011df3a1fa02993630b8fb83526368cf2206a711259830325bab2f1d2a4eb0
url: "https://pub.dev"
source: hosted
version: "10.12.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
functions_client:
dependency: transitive
description:
name: functions_client
sha256: "94074d62167ae634127ef6095f536835063a7dc80f2b1aa306d2346ff9023996"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
gamepads:
dependency: "direct main"
description:
@@ -712,62 +640,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.2.0"
google_identity_services_web:
dependency: transitive
description:
name: google_identity_services_web
sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454"
url: "https://pub.dev"
source: hosted
version: "0.3.3+1"
google_sign_in:
dependency: "direct main"
description:
name: google_sign_in
sha256: "521031b65853b4409b8213c0387d57edaad7e2a949ce6dea0d8b2afc9cb29763"
url: "https://pub.dev"
source: hosted
version: "7.2.0"
google_sign_in_android:
dependency: transitive
description:
name: google_sign_in_android
sha256: "5ec98ab35387c68c0050495bb211bd88375873723a80fae7c2e9266ea0bdd8bb"
url: "https://pub.dev"
source: hosted
version: "7.2.7"
google_sign_in_ios:
dependency: transitive
description:
name: google_sign_in_ios
sha256: ac1e4c1205267cb7999d1d81333fccffdfda29e853f434bbaf71525498bb6950
url: "https://pub.dev"
source: hosted
version: "6.3.0"
google_sign_in_platform_interface:
dependency: transitive
description:
name: google_sign_in_platform_interface
sha256: "7f59208c42b415a3cca203571128d6f84f885fead2d5b53eb65a9e27f2965bb5"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
google_sign_in_web:
dependency: transitive
description:
name: google_sign_in_web
sha256: "2fc1f941e6443b2d6984f4056a727a3eaeab15d8ee99ba7125d79029be75a1da"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
gotrue:
dependency: transitive
description:
name: gotrue
sha256: f7b52008311941a7c3e99f9590c4ee32dfc102a5442e43abf1b287d9f8cc39b2
url: "https://pub.dev"
source: hosted
version: "2.18.0"
gsettings:
dependency: transitive
description:
@@ -1028,14 +900,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.4.16"
jwt_decode:
dependency: transitive
description:
name: jwt_decode
sha256: d2e9f68c052b2225130977429d30f187aa1981d789c76ad104a32243cfdebfbb
url: "https://pub.dev"
source: hosted
version: "0.3.1"
keypress_simulator:
dependency: "direct main"
description:
@@ -1442,14 +1306,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
posix:
dependency: transitive
description:
@@ -1458,14 +1314,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.3"
postgrest:
dependency: transitive
description:
name: postgrest
sha256: f4b6bb24b465c47649243ef0140475de8a0ec311dc9c75ebe573b2dcabb10460
url: "https://pub.dev"
source: hosted
version: "2.6.0"
process:
dependency: transitive
description:
@@ -1537,14 +1385,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.2.2"
realtime_client:
dependency: transitive
description:
name: realtime_client
sha256: "5268afc208d02fb9109854d262c1ebf6ece224cd285199ae1d2f92d2ff49dbf1"
url: "https://pub.dev"
source: hosted
version: "2.7.0"
restart_app:
dependency: "direct main"
description:
@@ -1554,14 +1394,6 @@ packages:
url: "https://github.com/maple135790/restart_app.git"
source: git
version: "1.4.0"
retry:
dependency: transitive
description:
name: retry
sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
rxdart:
dependency: transitive
description:
@@ -1699,38 +1531,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.5"
sign_in_button:
dependency: "direct main"
description:
name: sign_in_button
sha256: "7bcd5e3ca5f80578da6a92b8749badf4003cf4dc578b5cb737b9082871354ff8"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
sign_in_with_apple:
dependency: "direct main"
description:
name: sign_in_with_apple
sha256: "8bd875c8e8748272749eb6d25b896f768e7e9d60988446d543fe85a37a2392b8"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
sign_in_with_apple_platform_interface:
dependency: transitive
description:
name: sign_in_with_apple_platform_interface
sha256: "981bca52cf3bb9c3ad7ef44aace2d543e5c468bb713fd8dda4275ff76dfa6659"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
sign_in_with_apple_web:
dependency: transitive
description:
name: sign_in_with_apple_web
sha256: f316400827f52cafcf50d00e1a2e8a0abc534ca1264e856a81c5f06bd5b10fed
url: "https://pub.dev"
source: hosted
version: "3.0.0"
skeletonizer:
dependency: transitive
description:
@@ -1768,14 +1568,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.12.1"
storage_client:
dependency: transitive
description:
name: storage_client
sha256: "1c61b19ed9e78f37fdd1ca8b729ab8484e6c8fe82e15c87e070b861951183657"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
stream_channel:
dependency: transitive
description:
@@ -1792,22 +1584,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
supabase:
dependency: transitive
description:
name: supabase
sha256: cc039f63a3168386b3a4f338f3bff342c860d415a3578f3fbe854024aee6f911
url: "https://pub.dev"
source: hosted
version: "2.10.2"
supabase_flutter:
dependency: "direct main"
description:
name: supabase_flutter
sha256: "92b2416ecb6a5c3ed34cf6e382b35ce6cc8921b64f2a9299d5d28968d42b09bb"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
sync_http:
dependency: transitive
description:
@@ -2009,22 +1785,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webdriver:
dependency: transitive
description:
@@ -2136,14 +1896,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.4"
yet_another_json_isolate:
dependency: transitive
description:
name: yet_another_json_isolate
sha256: fe45897501fa156ccefbfb9359c9462ce5dec092f05e8a56109db30be864f01e
url: "https://pub.dev"
source: hosted
version: "2.1.0"
sdks:
dart: ">=3.10.3 <4.0.0"
flutter: ">=3.38.4"

View File

@@ -30,12 +30,6 @@ dependencies:
flutter_md: ^0.0.7
permission_handler: ^12.0.1
dartx: any
supabase_flutter: ^2.12.0
sign_in_button: ^4.0.1
google_sign_in: ^7.2.0
sign_in_with_apple: ^7.0.1
nsd: ^4.0.3
image_picker: ^1.1.2
in_app_review: ^2.0.11
@@ -127,5 +121,4 @@ msix_config:
store: true
logo_path: web/icons/Icon-512.png
build_windows: false
protocol_activation: https, bikecontrol
capabilities: internetClient,bluetooth,inputInjectionBrokered

View File

@@ -6,7 +6,6 @@
#include "generated_plugin_registrant.h"
#include <app_links/app_links_plugin_c_api.h>
#include <bluetooth_low_energy_windows/bluetooth_low_energy_windows_plugin_c_api.h>
#include <file_selector_windows/file_selector_windows.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
@@ -23,8 +22,6 @@
#include <windows_iap/windows_iap_plugin_c_api.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
AppLinksPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
BluetoothLowEnergyWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("BluetoothLowEnergyWindowsPluginCApi"));
FileSelectorWindowsRegisterWithRegistrar(

View File

@@ -3,7 +3,6 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
app_links
bluetooth_low_energy_windows
file_selector_windows
flutter_secure_storage_windows

View File

@@ -7,7 +7,6 @@
#include <flutter/method_channel.h>
#include <flutter/standard_method_codec.h>
#include "app_links/app_links_plugin_c_api.h"
namespace
{
@@ -45,54 +44,9 @@ namespace
} // namespace
bool SendAppLinkToInstance(const std::wstring &title)
{
// Find our exact window
HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", title.c_str());
if (hwnd)
{
// Dispatch new link to current window
SendAppLink(hwnd);
// (Optional) Restore our window to front in same state
WINDOWPLACEMENT place = {sizeof(WINDOWPLACEMENT)};
GetWindowPlacement(hwnd, &place);
switch (place.showCmd)
{
case SW_SHOWMAXIMIZED:
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
break;
case SW_SHOWMINIMIZED:
ShowWindow(hwnd, SW_RESTORE);
break;
default:
ShowWindow(hwnd, SW_NORMAL);
break;
}
SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(hwnd);
// END (Optional) Restore
// Window has been found, don't create another one.
return true;
}
return false;
}
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command)
{
// Replace "example" with the generated title found as parameter of `window.Create` in this file.
// You may ignore the result if you need to create another window.
if (SendAppLinkToInstance(L"BikeControl"))
{
return EXIT_SUCCESS;
}
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent())