mirror of
https://github.com/jonasbark/swiftcontrol.git
synced 2026-02-18 00:17:40 +01:00
cleanup, fixes
This commit is contained in:
@@ -160,9 +160,6 @@ class Connection {
|
||||
if (existing != null) {
|
||||
existing.isConnected = true;
|
||||
signalChange(existing);
|
||||
} else {
|
||||
final linkDevice = LinkDevice(socket.remoteAddress.address);
|
||||
_addDevices([linkDevice]);
|
||||
}
|
||||
},
|
||||
onDisconnected: (socket) {
|
||||
|
||||
@@ -27,30 +27,42 @@ class LinkDevice extends BaseDevice {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('MyWhoosh Link: ${isConnected ? 'Connected' : 'Not connected'}'),
|
||||
if (isConnected)
|
||||
PopupMenuButton(
|
||||
itemBuilder: (c) => [
|
||||
PopupMenuItem(
|
||||
child: Text('Disconnect'),
|
||||
onTap: () {
|
||||
connection.disconnect(this, forget: true);
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
LoadingWidget(
|
||||
futureCallback: () => connection.startMyWhooshServer(),
|
||||
renderChild: (isLoading, tap) => ValueListenableBuilder(
|
||||
valueListenable: whooshLink.isConnected,
|
||||
builder: (c, isConnected, _) => TextButton(
|
||||
onPressed: !isConnected ? tap : null,
|
||||
child: isLoading || (!isConnected && whooshLink.isStarted.value)
|
||||
? SmallProgressIndicator()
|
||||
: Text('Connect'),
|
||||
Row(
|
||||
children: [
|
||||
if (!isConnected)
|
||||
LoadingWidget(
|
||||
futureCallback: () => connection.startMyWhooshServer(),
|
||||
renderChild: (isLoading, tap) => ValueListenableBuilder(
|
||||
valueListenable: whooshLink.isConnected,
|
||||
builder: (c, isConnected, _) => TextButton(
|
||||
onPressed: !isConnected ? tap : null,
|
||||
child: isLoading || (!isConnected && whooshLink.isStarted.value)
|
||||
? SmallProgressIndicator()
|
||||
: Text('Connect'),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
PopupMenuButton(
|
||||
itemBuilder: (c) => [
|
||||
if (isConnected)
|
||||
PopupMenuItem(
|
||||
child: Text('Disconnect'),
|
||||
onTap: () {
|
||||
connection.disconnect(this, forget: true);
|
||||
},
|
||||
)
|
||||
else
|
||||
PopupMenuItem(
|
||||
child: Text('Stop'),
|
||||
onTap: () {
|
||||
whooshLink.stopServer();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:swift_control/bluetooth/devices/zwift/constants.dart';
|
||||
import 'package:swift_control/bluetooth/devices/zwift/protocol/zp.pbenum.dart';
|
||||
import 'package:swift_control/bluetooth/devices/zwift/zwift_ride.dart';
|
||||
import 'package:swift_control/pages/markdown.dart';
|
||||
import 'package:swift_control/widgets/warning.dart';
|
||||
|
||||
class ZwiftClickV2 extends ZwiftRide {
|
||||
ZwiftClickV2(super.scanResult) : super(isBeta: true);
|
||||
@@ -19,6 +21,58 @@ class ZwiftClickV2 extends ZwiftRide {
|
||||
await sendCommandBuffer(Uint8List.fromList([0xFF, 0x04, 0x00]));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget showInformation(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
super.showInformation(context),
|
||||
|
||||
if (isConnected)
|
||||
Warning(
|
||||
children: [
|
||||
Text(
|
||||
'''To make your Zwift Click V2 work best you should connect it in the Zwift app once each day.\nIf you don't do that SwiftControl will need to reconnect every minute.
|
||||
|
||||
1. Open Zwift app
|
||||
2. Log in (subscription not required) and open the device connection screen
|
||||
3. Connect your Trainer, then connect the Zwift Click V2
|
||||
4. Close the Zwift app again and connect again in SwiftControl''',
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
sendCommand(Opcode.RESET, null);
|
||||
},
|
||||
child: Text('Reset now'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => MarkdownPage(assetPath: 'TROUBLESHOOTING.md'),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text('Troubleshooting'),
|
||||
),
|
||||
if (kDebugMode)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
test();
|
||||
},
|
||||
child: Text('Test'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> test() async {
|
||||
await sendCommand(Opcode.RESET, null);
|
||||
//await sendCommand(Opcode.GET, Get(dataObjectId: VendorDO.PAGE_DEVICE_PAIRING.value)); // 0008 82E0 03
|
||||
|
||||
@@ -5,15 +5,14 @@ import 'package:device_auto_rotate_checker/device_auto_rotate_checker.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:swift_control/bluetooth/devices/zwift/protocol/zp.pbenum.dart';
|
||||
import 'package:swift_control/bluetooth/devices/zwift/zwift_clickv2.dart';
|
||||
import 'package:swift_control/bluetooth/devices/link/link_device.dart';
|
||||
import 'package:swift_control/main.dart';
|
||||
import 'package:swift_control/pages/markdown.dart';
|
||||
import 'package:swift_control/utils/actions/desktop.dart';
|
||||
import 'package:swift_control/utils/keymap/manager.dart';
|
||||
import 'package:swift_control/widgets/keymap_explanation.dart';
|
||||
import 'package:swift_control/widgets/logviewer.dart';
|
||||
import 'package:swift_control/widgets/scan.dart';
|
||||
import 'package:swift_control/widgets/small_progress_indicator.dart';
|
||||
import 'package:swift_control/widgets/testbed.dart';
|
||||
import 'package:swift_control/widgets/title.dart';
|
||||
import 'package:swift_control/widgets/warning.dart';
|
||||
@@ -54,12 +53,16 @@ class _DevicePageState extends State<DevicePage> with WidgetsBindingObserver {
|
||||
_checkAndShowChangelog();
|
||||
});
|
||||
|
||||
if (actionHandler is RemoteActions && !kIsWeb && Platform.isIOS) {
|
||||
whooshLink.isStarted.addListener(() {
|
||||
if (mounted) setState(() {});
|
||||
});
|
||||
|
||||
if (actionHandler is RemoteActions && !kIsWeb && Platform.isIOS && (actionHandler as RemoteActions).isConnected) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// show snackbar to inform user that the app needs to stay in foreground
|
||||
_snackBarMessengerKey.currentState?.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('To keep working properly the app needs to stay in the foreground.'),
|
||||
content: Text('To simulate touches the app needs to stay in the foreground.'),
|
||||
duration: Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
@@ -98,14 +101,14 @@ class _DevicePageState extends State<DevicePage> with WidgetsBindingObserver {
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
if (actionHandler is RemoteActions && Platform.isIOS) {
|
||||
if (actionHandler is RemoteActions && Platform.isIOS && (actionHandler as RemoteActions).isConnected) {
|
||||
UniversalBle.getBluetoothAvailabilityState().then((state) {
|
||||
if (state == AvailabilityState.poweredOn) {
|
||||
final requirement = RemoteRequirement();
|
||||
requirement.reconnect();
|
||||
_snackBarMessengerKey.currentState?.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('To keep working properly the app needs to stay in the foreground.'),
|
||||
content: Text('To simulate touches the app needs to stay in the foreground.'),
|
||||
duration: Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
@@ -191,32 +194,40 @@ class _DevicePageState extends State<DevicePage> with WidgetsBindingObserver {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (connection.controllerDevices.isEmpty)
|
||||
ScanWidget()
|
||||
else
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 8.0),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
'Connected Controllers',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 8.0),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
),
|
||||
),
|
||||
...connection.controllerDevices.map(
|
||||
(device) => device.showInformation(context),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Connected Controllers',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
if (connection.controllerDevices.isEmpty) SmallProgressIndicator(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (connection.controllerDevices.isEmpty)
|
||||
ScanWidget()
|
||||
else
|
||||
...connection.controllerDevices.map(
|
||||
(device) => device.showInformation(context),
|
||||
),
|
||||
|
||||
if (connection.remoteDevices.isNotEmpty || actionHandler is RemoteActions)
|
||||
if (connection.remoteDevices.isNotEmpty ||
|
||||
actionHandler is RemoteActions ||
|
||||
whooshLink.isStarted.value)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 8.0),
|
||||
width: double.infinity,
|
||||
@@ -230,7 +241,7 @@ class _DevicePageState extends State<DevicePage> with WidgetsBindingObserver {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Text(
|
||||
'Remote Devices',
|
||||
'Remote Connections',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
@@ -239,6 +250,8 @@ class _DevicePageState extends State<DevicePage> with WidgetsBindingObserver {
|
||||
(device) => device.showInformation(context),
|
||||
),
|
||||
|
||||
if (whooshLink.isStarted.value) LinkDevice('').showInformation(context),
|
||||
|
||||
if (actionHandler is RemoteActions)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -259,53 +272,6 @@ class _DevicePageState extends State<DevicePage> with WidgetsBindingObserver {
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
if (connection.devices.any((device) => (device is ZwiftClickV2) && device.isConnected))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Warning(
|
||||
children: [
|
||||
Text(
|
||||
'''To make your Zwift Click V2 work best you should connect it in the Zwift app once each day.\nIf you don't do that SwiftControl will need to reconnect every minute.
|
||||
|
||||
1. Open Zwift app
|
||||
2. Log in (subscription not required) and open the device connection screen
|
||||
3. Connect your Trainer, then connect the Zwift Click V2
|
||||
4. Close the Zwift app again and connect again in SwiftControl''',
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
connection.devices.whereType<ZwiftClickV2>().forEach(
|
||||
(device) => device.sendCommand(Opcode.RESET, null),
|
||||
);
|
||||
},
|
||||
child: Text('Reset now'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => MarkdownPage(assetPath: 'TROUBLESHOOTING.md'),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text('Troubleshooting'),
|
||||
),
|
||||
if (kDebugMode)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
(connection.bluetoothDevices.first as ZwiftClickV2).test();
|
||||
},
|
||||
child: Text('Test'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -84,7 +84,9 @@ class _RequirementsPageState extends State<RequirementsPage> with WidgetsBinding
|
||||
if (_requirements[step].status && _requirements[step] is! TargetRequirement) {
|
||||
return;
|
||||
}
|
||||
final hasEarlierIncomplete = _requirements.indexWhere((req) => !req.status) < step;
|
||||
final hasEarlierIncomplete =
|
||||
_requirements.indexWhere((req) => !req.status) != -1 &&
|
||||
_requirements.indexWhere((req) => !req.status) < step;
|
||||
if (hasEarlierIncomplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class AndroidActions extends BaseActions {
|
||||
try {
|
||||
await accessibilityHandler.performTouch(point.dx, point.dy, isKeyDown: isKeyDown, isKeyUp: isKeyUp);
|
||||
} on PlatformException catch (e) {
|
||||
return "Failed to perform touch action. Please get in contact with Jonas.\n${e.message}";
|
||||
return "Accessibility Service not working. Follow instructions at https://dontkillmyapp.com/";
|
||||
}
|
||||
return "Touch performed at: ${point.dx.toInt()}, ${point.dy.toInt()} -> ${isKeyDown && isKeyUp
|
||||
? "click"
|
||||
|
||||
@@ -30,7 +30,7 @@ class RemoteActions extends BaseActions {
|
||||
if (keyPair.inGameAction != null && whooshLink.isConnected.value) {
|
||||
return whooshLink.sendAction(keyPair.inGameAction!, keyPair.inGameActionValue);
|
||||
} else if (!(actionHandler as RemoteActions).isConnected) {
|
||||
return 'Not connected to a device';
|
||||
return 'Not connected to a ${settings.getLastTarget()?.name ?? 'remote'} device';
|
||||
}
|
||||
|
||||
if (keyPair.physicalKey != null && keyPair.touchPosition == Offset.zero) {
|
||||
|
||||
@@ -89,25 +89,24 @@ enum Target {
|
||||
),
|
||||
iPad(
|
||||
title: 'iPad',
|
||||
description: 'Remotely control any trainer app on an iPad by acting as a Mouse',
|
||||
description: 'Remotely control any trainer app on an iPad by acting as a Mouse, or directly via MyWhoosh Link',
|
||||
icon: Icons.settings_remote_outlined,
|
||||
isBeta: true,
|
||||
),
|
||||
android(
|
||||
title: 'Android Device',
|
||||
description: 'Remotely control any trainer app on an Android device',
|
||||
description: 'Remotely control any trainer app on another Android device, or directly via MyWhoosh Link',
|
||||
icon: Icons.settings_remote_outlined,
|
||||
isBeta: true,
|
||||
),
|
||||
macOS(
|
||||
title: 'Mac',
|
||||
description: 'Remotely control any trainer app on a Mac',
|
||||
description: 'Remotely control any trainer app on another Mac, or directly via MyWhoosh Link',
|
||||
icon: Icons.settings_remote_outlined,
|
||||
isBeta: true,
|
||||
),
|
||||
windows(
|
||||
title: 'Windows PC',
|
||||
description: 'Remotely control any trainer app on a Windows PC',
|
||||
description: 'Remotely control any trainer app on another Windows PC, or directly via MyWhoosh Link',
|
||||
icon: Icons.settings_remote_outlined,
|
||||
isBeta: true,
|
||||
);
|
||||
@@ -183,7 +182,7 @@ class TargetRequirement extends PlatformRequirement {
|
||||
Row(
|
||||
children: [
|
||||
Text(target.title, style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
if (target.isBeta) BetaPill(),
|
||||
if (target.isBeta || (!Platform.isIOS && target == Target.iPad)) BetaPill(),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart' hide ConnectionState;
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:swift_control/main.dart';
|
||||
import 'package:swift_control/pages/device.dart';
|
||||
import 'package:swift_control/utils/actions/remote.dart';
|
||||
import 'package:swift_control/utils/requirements/multi.dart';
|
||||
import 'package:swift_control/utils/requirements/platform.dart';
|
||||
@@ -92,6 +93,11 @@ class RemoteRequirement extends PlatformRequirement {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (kDebugMode) {
|
||||
print('Continuing');
|
||||
return;
|
||||
}
|
||||
|
||||
while (peripheralManager.state != BluetoothLowEnergyState.poweredOn) {
|
||||
print('Waiting for peripheral manager to be powered on...');
|
||||
if (settings.getLastTarget() == Target.thisDevice) {
|
||||
@@ -99,7 +105,6 @@ class RemoteRequirement extends PlatformRequirement {
|
||||
}
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
}
|
||||
|
||||
if (!_isServiceAdded) {
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
final reportMapDataAbsolute = Uint8List.fromList([
|
||||
@@ -318,6 +323,30 @@ class _PairWidgetState extends State<_PairWidget> {
|
||||
if (_isAdvertising || _isLoading) SizedBox(height: 20, width: 20, child: SmallProgressIndicator()),
|
||||
],
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (c) => DevicePage(),
|
||||
settings: RouteSettings(name: '/device'),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Use MyWhoosh Link only'),
|
||||
Text(
|
||||
'No pairing required, connect directly via MyWhoosh Link.',
|
||||
style: TextStyle(fontSize: 10, color: Colors.black87),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_isAdvertising) ...[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
|
||||
@@ -36,7 +36,7 @@ class ChangelogDialog extends StatelessWidget {
|
||||
|
||||
static Future<void> showIfNeeded(BuildContext context, String currentVersion, String? lastSeenVersion) async {
|
||||
// Show dialog if this is a new version
|
||||
if (lastSeenVersion != currentVersion || true) {
|
||||
if (lastSeenVersion != currentVersion) {
|
||||
try {
|
||||
final entry = await rootBundle.loadString('CHANGELOG.md');
|
||||
if (context.mounted) {
|
||||
|
||||
@@ -94,27 +94,33 @@ class _KeymapExplanationState extends State<KeymapExplanation> {
|
||||
for (final keyPair in availableKeypairs) ...[
|
||||
TableRow(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (actionHandler.supportedApp is! CustomApp)
|
||||
if (keyPair.buttons.filter((b) => allAvailableButtons.contains(b)).isEmpty)
|
||||
Text('No button assigned for your connected device')
|
||||
TableCell(
|
||||
verticalAlignment: TableCellVerticalAlignment.middle,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (actionHandler.supportedApp is! CustomApp)
|
||||
if (keyPair.buttons.filter((b) => allAvailableButtons.contains(b)).isEmpty)
|
||||
Text('No button assigned for your connected device')
|
||||
else
|
||||
for (final button in keyPair.buttons.filter((b) => allAvailableButtons.contains(b)))
|
||||
IntrinsicWidth(child: ButtonWidget(button: button))
|
||||
else
|
||||
for (final button in keyPair.buttons.filter((b) => allAvailableButtons.contains(b)))
|
||||
IntrinsicWidth(child: ButtonWidget(button: button))
|
||||
else
|
||||
for (final button in keyPair.buttons) IntrinsicWidth(child: ButtonWidget(button: button)),
|
||||
],
|
||||
for (final button in keyPair.buttons) IntrinsicWidth(child: ButtonWidget(button: button)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: _ButtonEditor(keyPair: keyPair, onUpdate: widget.onUpdate),
|
||||
TableCell(
|
||||
verticalAlignment: TableCellVerticalAlignment.middle,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: _ButtonEditor(keyPair: keyPair, onUpdate: widget.onUpdate),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -296,43 +302,39 @@ class _ButtonEditor extends StatelessWidget {
|
||||
),
|
||||
];
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (keyPair.buttons.isNotEmpty &&
|
||||
(keyPair.physicalKey != null || keyPair.touchPosition != Offset.zero || keyPair.inGameAction != null))
|
||||
Expanded(
|
||||
child: KeypairExplanation(
|
||||
keyPair: keyPair,
|
||||
),
|
||||
)
|
||||
else
|
||||
Expanded(child: Text('No action assigned')),
|
||||
return Container(
|
||||
constraints: BoxConstraints(minHeight: kMinInteractiveDimension - 6),
|
||||
padding: EdgeInsets.only(right: actionHandler.supportedApp is CustomApp ? 4 : 0),
|
||||
child: PopupMenuButton(
|
||||
itemBuilder: (c) => actions,
|
||||
enabled: actionHandler.supportedApp is CustomApp,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (keyPair.buttons.isNotEmpty &&
|
||||
(keyPair.physicalKey != null || keyPair.touchPosition != Offset.zero || keyPair.inGameAction != null))
|
||||
Expanded(
|
||||
child: KeypairExplanation(
|
||||
keyPair: keyPair,
|
||||
),
|
||||
)
|
||||
else
|
||||
Expanded(child: Text('No action assigned')),
|
||||
|
||||
if (actionHandler.supportedApp is CustomApp)
|
||||
PopupMenuButton<PhysicalKeyboardKey>(
|
||||
enabled: true,
|
||||
itemBuilder: (context) => [
|
||||
if (actions.length > 1) ...actions,
|
||||
],
|
||||
onSelected: (key) {
|
||||
keyPair.physicalKey = key;
|
||||
keyPair.logicalKey = null;
|
||||
|
||||
onUpdate();
|
||||
},
|
||||
icon: Icon(Icons.edit),
|
||||
)
|
||||
else
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
final currentProfile = actionHandler.supportedApp!.name;
|
||||
await KeymapManager().duplicate(context, currentProfile);
|
||||
onUpdate();
|
||||
},
|
||||
icon: Icon(Icons.edit),
|
||||
),
|
||||
],
|
||||
if (actionHandler.supportedApp is! CustomApp)
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
final currentProfile = actionHandler.supportedApp!.name;
|
||||
await KeymapManager().duplicate(context, currentProfile);
|
||||
onUpdate();
|
||||
},
|
||||
icon: Icon(Icons.edit),
|
||||
)
|
||||
else
|
||||
Icon(Icons.edit, size: 14),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:swift_control/main.dart';
|
||||
import 'package:swift_control/pages/markdown.dart';
|
||||
import 'package:swift_control/widgets/small_progress_indicator.dart';
|
||||
|
||||
class ScanWidget extends StatefulWidget {
|
||||
const ScanWidget({super.key});
|
||||
@@ -67,7 +66,6 @@ class _ScanWidgetState extends State<ScanWidget> {
|
||||
},
|
||||
child: const Text("Show Troubleshooting Guide"),
|
||||
),
|
||||
SmallProgressIndicator(),
|
||||
SizedBox(),
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user