mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 03:02:22 +01:00
320 lines
10 KiB
Dart
320 lines
10 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:fluent_ui/fluent_ui.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
|
import 'package:reboot_launcher/src/dialog/snackbar.dart';
|
|
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
|
import 'package:reboot_launcher/src/dialog/add_local_version.dart';
|
|
import 'package:reboot_launcher/src/widget/shared/smart_check_box.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
import '../../dialog/add_server_version.dart';
|
|
import '../../util/checks.dart';
|
|
|
|
class VersionSelector extends StatefulWidget {
|
|
const VersionSelector({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
State<VersionSelector> createState() => _VersionSelectorState();
|
|
}
|
|
|
|
class _VersionSelectorState extends State<VersionSelector> {
|
|
final GameController _gameController = Get.find<GameController>();
|
|
final CheckboxController _deleteFilesController = CheckboxController();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return InfoLabel(
|
|
label: "Version",
|
|
child: Align(
|
|
alignment: AlignmentDirectional.centerStart,
|
|
child: Row(
|
|
children: [
|
|
Expanded(child: _createSelector(context)),
|
|
const SizedBox(
|
|
width: 16,
|
|
),
|
|
Tooltip(
|
|
message: "Add a local fortnite build to the versions list",
|
|
child: Button(
|
|
child: const Icon(FluentIcons.open_file),
|
|
onPressed: () => _openAddLocalVersionDialog(context)),
|
|
),
|
|
const SizedBox(
|
|
width: 16,
|
|
),
|
|
Tooltip(
|
|
message: "Download a fortnite build from the archive",
|
|
child: Button(
|
|
child: const Icon(FluentIcons.download),
|
|
onPressed: () => _openDownloadVersionDialog(context)),
|
|
),
|
|
],
|
|
)));
|
|
}
|
|
|
|
Widget _createSelector(BuildContext context) {
|
|
return Tooltip(
|
|
message: "The version of Fortnite to launch",
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: Obx(() => DropDownButton(
|
|
leading: Text(_gameController.selectedVersionObs.value?.name ??
|
|
"Select a version"),
|
|
items: _gameController.hasNoVersions
|
|
? [_createDefaultVersionItem()]
|
|
: _gameController.versions.value
|
|
.map((version) => _createVersionItem(context, version))
|
|
.toList()))
|
|
),
|
|
);
|
|
}
|
|
|
|
MenuFlyoutItem _createVersionItem(
|
|
BuildContext context, FortniteVersion version) {
|
|
return MenuFlyoutItem(
|
|
text: SizedBox(
|
|
width: double.infinity,
|
|
child: Listener(
|
|
onPointerDown: (event) async {
|
|
if (event.kind != PointerDeviceKind.mouse ||
|
|
event.buttons != kSecondaryMouseButton) {
|
|
return;
|
|
}
|
|
|
|
await _openMenu(context, version, event.position);
|
|
},
|
|
child: Text(version.name)
|
|
)
|
|
),
|
|
trailing: const Expanded(child: SizedBox()),
|
|
onPressed: () => _gameController.selectedVersion = version);
|
|
}
|
|
|
|
MenuFlyoutItem _createDefaultVersionItem() {
|
|
return MenuFlyoutItem(
|
|
text: const SizedBox(
|
|
width: double.infinity, child: Text("No versions available")),
|
|
trailing: const Expanded(child: SizedBox()),
|
|
onPressed: () {});
|
|
}
|
|
|
|
void _openDownloadVersionDialog(BuildContext context) async {
|
|
await showDialog<bool>(
|
|
context: context,
|
|
builder: (dialogContext) => const AddServerVersion()
|
|
);
|
|
}
|
|
|
|
void _openAddLocalVersionDialog(BuildContext context) async {
|
|
await showDialog<bool>(
|
|
context: context,
|
|
builder: (context) => AddLocalVersion());
|
|
}
|
|
|
|
Future<void> _openMenu(
|
|
BuildContext context, FortniteVersion version, Offset offset) async {
|
|
var result = await showMenu<ContextualOption>(
|
|
context: context,
|
|
offset: offset,
|
|
builder: (context) => MenuFlyout(
|
|
items: ContextualOption.getValues(version.memoryFix)
|
|
.map((entry) => _createOption(context, entry))
|
|
.toList()
|
|
)
|
|
);
|
|
|
|
switch (result) {
|
|
case ContextualOption.openExplorer:
|
|
if(!mounted){
|
|
return;
|
|
}
|
|
|
|
Navigator.of(context).pop();
|
|
launchUrl(version.location.uri)
|
|
.onError((error, stackTrace) => _onExplorerError());
|
|
break;
|
|
|
|
case ContextualOption.rename:
|
|
if(!mounted){
|
|
return;
|
|
}
|
|
|
|
Navigator.of(context).pop();
|
|
var result = await _openRenameDialog(context, version);
|
|
if(result == null){
|
|
return;
|
|
}
|
|
|
|
_gameController.rename(version, result);
|
|
break;
|
|
|
|
case ContextualOption.delete:
|
|
if(!mounted){
|
|
return;
|
|
}
|
|
|
|
var result = await _openDeleteDialog(context, version) ?? false;
|
|
if(!mounted || !result){
|
|
return;
|
|
}
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
_gameController.removeVersion(version);
|
|
if (_gameController.selectedVersionObs.value?.name == version.name || _gameController.hasNoVersions) {
|
|
_gameController.selectedVersionObs.value = null;
|
|
}
|
|
|
|
if (_deleteFilesController.value && await version.location.exists()) {
|
|
version.location.delete(recursive: true);
|
|
}
|
|
|
|
break;
|
|
case ContextualOption.enableMemoryFix:
|
|
if(!mounted){
|
|
return;
|
|
}
|
|
|
|
version.memoryFix = true;
|
|
Navigator.of(context).pop();
|
|
showMessage("Enabled memory fix");
|
|
break;
|
|
case ContextualOption.disableMemoryFix:
|
|
if(!mounted){
|
|
return;
|
|
}
|
|
|
|
version.memoryFix = false;
|
|
Navigator.of(context).pop();
|
|
showMessage("Disabled memory fix");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
MenuFlyoutItem _createOption(BuildContext context, ContextualOption entry) {
|
|
return MenuFlyoutItem(
|
|
text: Text(entry.name),
|
|
onPressed: () => Navigator.of(context).pop(entry)
|
|
);
|
|
}
|
|
|
|
bool _onExplorerError() {
|
|
showSnackbar(
|
|
context,
|
|
const Snackbar(
|
|
content: Text("This version doesn't exist on the local machine", textAlign: TextAlign.center),
|
|
extended: true
|
|
)
|
|
);
|
|
return false;
|
|
}
|
|
|
|
Future<bool?> _openDeleteDialog(BuildContext context, FortniteVersion version) {
|
|
return showDialog<bool>(
|
|
context: context,
|
|
builder: (context) => ContentDialog(
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const SizedBox(
|
|
width: double.infinity,
|
|
child: Text("Are you sure you want to delete this version?")),
|
|
|
|
const SizedBox(height: 12.0),
|
|
|
|
SmartCheckBox(
|
|
controller: _deleteFilesController,
|
|
content: const Text("Delete version files from disk")
|
|
)
|
|
],
|
|
),
|
|
actions: [
|
|
Button(
|
|
onPressed: () => Navigator.of(context).pop(false),
|
|
child: const Text('Keep'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () => Navigator.of(context).pop(true),
|
|
child: const Text('Delete'),
|
|
)
|
|
],
|
|
)
|
|
);
|
|
}
|
|
|
|
Future<String?> _openRenameDialog(BuildContext context, FortniteVersion version) {
|
|
var controller = TextEditingController(text: version.name);
|
|
return showDialog<String?>(
|
|
context: context,
|
|
builder: (context) => Form(
|
|
child: Builder(
|
|
builder: (context) => ContentDialog(
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
TextFormBox(
|
|
controller: controller,
|
|
header: "Name",
|
|
placeholder: "Type the new version name",
|
|
autofocus: true,
|
|
validator: (text) => checkVersion(text, _gameController.versions.value)
|
|
),
|
|
|
|
const SizedBox(height: 8.0),
|
|
],
|
|
),
|
|
actions: [
|
|
Button(
|
|
onPressed: () => Navigator.of(context).pop(null),
|
|
child: const Text('Close'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () {
|
|
if (!Form.of(context)!.validate()) {
|
|
return;
|
|
}
|
|
|
|
Navigator.of(context).pop(controller.text);
|
|
},
|
|
child: const Text('Save')
|
|
)
|
|
]
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
enum ContextualOption {
|
|
openExplorer,
|
|
rename,
|
|
enableMemoryFix,
|
|
disableMemoryFix,
|
|
delete;
|
|
|
|
static List<ContextualOption> getValues(bool memoryFix){
|
|
return memoryFix
|
|
? [ContextualOption.openExplorer, ContextualOption.rename, ContextualOption.disableMemoryFix, ContextualOption.delete]
|
|
: [ContextualOption.openExplorer, ContextualOption.rename, ContextualOption.enableMemoryFix, ContextualOption.delete];
|
|
}
|
|
|
|
String get name {
|
|
return this == ContextualOption.openExplorer ? "Open in explorer"
|
|
: this == ContextualOption.rename ? "Rename"
|
|
: this == ContextualOption.enableMemoryFix ? "Enable memory leak fix"
|
|
: this == ContextualOption.disableMemoryFix ? "Disable memory leak fix"
|
|
: "Delete";
|
|
}
|
|
}
|