Files
swiftcontrol/lib/pages/customize.dart
Jonas Bark b0f3dffc3c screenshots
2025-12-20 10:13:20 +01:00

166 lines
6.1 KiB
Dart

import 'package:bike_control/main.dart';
import 'package:bike_control/utils/core.dart';
import 'package:bike_control/utils/i18n_extension.dart';
import 'package:bike_control/utils/iap/iap_manager.dart';
import 'package:bike_control/utils/keymap/apps/custom_app.dart';
import 'package:bike_control/utils/keymap/apps/supported_app.dart';
import 'package:bike_control/utils/keymap/manager.dart';
import 'package:bike_control/widgets/iap_status_widget.dart';
import 'package:bike_control/widgets/keymap_explanation.dart';
import 'package:bike_control/widgets/ui/beta_pill.dart';
import 'package:bike_control/widgets/ui/colored_title.dart';
import 'package:bike_control/widgets/ui/warning.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
class CustomizePage extends StatefulWidget {
const CustomizePage({super.key});
@override
State<CustomizePage> createState() => _CustomizeState();
}
class _CustomizeState extends State<CustomizePage> {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
spacing: 12,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ValueListenableBuilder(
valueListenable: IAPManager.instance.isPurchased,
builder: (context, value, child) => value ? SizedBox.shrink() : IAPStatusWidget(small: true),
),
Container(
margin: const EdgeInsets.only(bottom: 8.0),
padding: const EdgeInsets.symmetric(vertical: 8.0),
width: double.infinity,
child: ColoredTitle(
text: context.i18n.customizeControllerButtons(
screenshotMode ? 'Trainer app' : (core.settings.getTrainerApp()?.name ?? ''),
),
),
),
Select<SupportedApp?>(
constraints: BoxConstraints(minWidth: 300),
value: core.actionHandler.supportedApp,
popup: SelectPopup(
items: SelectItemList(
children: [
..._getAllApps().map(
(a) => SelectItemButton(
value: a,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(a.name)),
if (a is CustomApp)
BetaPill(text: 'CUSTOM')
else if (a.supportsOpenBikeProtocol)
Icon(Icons.star, size: 16),
],
),
),
),
SelectItemButton(
value: CustomApp(profileName: 'New'),
child: Row(
spacing: 6,
children: [
Icon(Icons.add, color: Theme.of(context).colorScheme.mutedForeground),
Expanded(child: Text(context.i18n.createNewKeymap).normal.muted),
],
),
),
],
),
).call,
itemBuilder: (c, app) => Row(
spacing: 8,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(child: Text(screenshotMode ? 'Trainer app' : app!.name)),
if (app is CustomApp) BetaPill(text: 'CUSTOM'),
],
),
placeholder: Text(context.i18n.selectKeymap),
onChanged: (app) async {
if (app == null) {
return;
} else if (app.name == 'New') {
final profileName = await KeymapManager().showNewProfileDialog(context);
if (profileName != null && profileName.isNotEmpty) {
final customApp = CustomApp(profileName: profileName);
core.actionHandler.init(customApp);
await core.settings.setKeyMap(customApp);
setState(() {});
}
} else {
core.actionHandler.init(app);
await core.settings.setKeyMap(app);
setState(() {});
}
},
),
KeymapManager().getManageProfileDialog(
context,
core.actionHandler.supportedApp is CustomApp ? core.actionHandler.supportedApp?.name : null,
onDone: () {
setState(() {});
},
),
if (core.actionHandler.supportedApp is! CustomApp)
Text(
context.i18n.customizeKeymapHint,
style: TextStyle(fontSize: 12),
),
Gap(12),
if (core.actionHandler.supportedApp != null && core.connection.controllerDevices.isNotEmpty)
KeymapExplanation(
key: Key(core.actionHandler.supportedApp!.keymap.runtimeType.toString()),
keymap: core.actionHandler.supportedApp!.keymap,
onUpdate: () {
setState(() {});
if (core.actionHandler.supportedApp is CustomApp) {
core.settings.setKeyMap(core.actionHandler.supportedApp!);
}
},
)
else if (core.connection.controllerDevices.isEmpty)
Warning(
children: [Text(context.i18n.connectControllerToPreview).small],
),
],
),
);
}
List<SupportedApp> _getAllApps() {
final baseApp = core.settings.getTrainerApp();
final customProfiles = core.settings.getCustomAppProfiles();
final customApps = customProfiles.map((profile) {
final customApp = CustomApp(profileName: profile);
final savedKeymap = core.settings.getCustomAppKeymap(profile);
if (savedKeymap != null) {
customApp.decodeKeymap(savedKeymap);
}
return customApp;
}).toList();
// If no custom profiles exist, add the default "Custom" one
if (customApps.isEmpty) {
customApps.add(CustomApp());
}
return [if (baseApp != null) baseApp, ...customApps];
}
}