mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 19:22:22 +01:00
Added settings tab
This commit is contained in:
@@ -43,9 +43,7 @@ class GameController extends GetxController {
|
||||
});
|
||||
|
||||
username = TextEditingController(text: _storage.read("${type.value == GameType.client ? 'game' : 'host'}_username") ?? "");
|
||||
username.addListener(() async {
|
||||
await _storage.write("${type.value == GameType.client ? 'game' : 'host'}_username", username.text);
|
||||
});
|
||||
username.addListener(() => _storage.write("${type.value == GameType.client ? 'game' : 'host'}_username", username.text));
|
||||
|
||||
started = RxBool(false);
|
||||
}
|
||||
|
||||
41
lib/src/controller/settings_controller.dart
Normal file
41
lib/src/controller/settings_controller.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/model/game_type.dart';
|
||||
import 'package:reboot_launcher/src/util/binary.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
|
||||
class SettingsController extends GetxController {
|
||||
late final GetStorage _storage;
|
||||
late final String originalDll;
|
||||
late final TextEditingController rebootDll;
|
||||
late final TextEditingController consoleDll;
|
||||
late final TextEditingController craniumDll;
|
||||
late final RxBool autoUpdate;
|
||||
|
||||
SettingsController() {
|
||||
_storage = GetStorage("settings");
|
||||
rebootDll = _createController("reboot", "reboot.dll");
|
||||
consoleDll = _createController("console", "console.dll");
|
||||
craniumDll = _createController("cranium", "cranium.dll");
|
||||
autoUpdate = RxBool(_storage.read("auto_update") ?? true);
|
||||
autoUpdate.listen((value) => _storage.write("auto_update", value));
|
||||
}
|
||||
|
||||
TextEditingController _createController(String key, String name) {
|
||||
var controller = TextEditingController(text: _storage.read(key) ?? "$safeBinariesDirectory\\$name");
|
||||
controller.addListener(() {
|
||||
if(controller.text.isEmpty || !File(controller.text).existsSync()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_storage.write(key, controller.text);
|
||||
});
|
||||
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/page/info_page.dart';
|
||||
import 'package:reboot_launcher/src/page/settings_page.dart';
|
||||
import 'package:reboot_launcher/src/page/launcher_page.dart';
|
||||
import 'package:reboot_launcher/src/page/server_page.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
@@ -54,7 +54,7 @@ class _HomePageState extends State<HomePage> with WindowListener {
|
||||
items: [
|
||||
_createPane("Home", FluentIcons.game),
|
||||
_createPane("Lawin", FluentIcons.server_enviroment),
|
||||
_createPane("Info", FluentIcons.info),
|
||||
_createPane("Settings", FluentIcons.settings)
|
||||
],
|
||||
trailing: WindowTitleBar(focused: _focused)),
|
||||
content: NavigationBody(
|
||||
@@ -62,7 +62,7 @@ class _HomePageState extends State<HomePage> with WindowListener {
|
||||
children: [
|
||||
const LauncherPage(),
|
||||
ServerPage(),
|
||||
const InfoPage()
|
||||
SettingsPage()
|
||||
]
|
||||
)
|
||||
),
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
const String _discordLink = "https://discord.gg/NJU4QjxSMF";
|
||||
|
||||
class InfoPage extends StatelessWidget {
|
||||
const InfoPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
const Expanded(child: SizedBox()),
|
||||
Column(
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
radius: 48,
|
||||
backgroundImage: AssetImage("assets/images/auties.png")),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
const Text("Made by Auties00"),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
),
|
||||
Button(
|
||||
child: const Text("Join the discord"),
|
||||
onPressed: () => launchUrl(Uri.parse(_discordLink))),
|
||||
],
|
||||
),
|
||||
const Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomLeft, child: Text("Version 3.10${kDebugMode ? '-DEBUG' : ''}")))
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import 'package:reboot_launcher/src/widget/username_box.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_selector.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../controller/settings_controller.dart';
|
||||
import '../util/binary.dart';
|
||||
import '../util/reboot.dart';
|
||||
import '../widget/warning_info.dart';
|
||||
@@ -29,10 +30,11 @@ class LauncherPage extends StatefulWidget {
|
||||
class _LauncherPageState extends State<LauncherPage> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final BuildController _buildController = Get.find<BuildController>();
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if(_gameController.updater == null) {
|
||||
if(_gameController.updater == null && _settingsController.autoUpdate.value){
|
||||
_gameController.updater = compute(downloadRebootDll, _updateTime)
|
||||
..then((value) => _updateTime = value)
|
||||
..onError(_saveError);
|
||||
|
||||
86
lib/src/page/settings_page.dart
Normal file
86
lib/src/page/settings_page.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/smart_switch.dart';
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
|
||||
SettingsPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Form(
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
FileSelector(
|
||||
label: "Reboot DLL",
|
||||
placeholder: "Type the path to the reboot dll",
|
||||
controller: _settingsController.rebootDll,
|
||||
windowTitle: "Select a dll",
|
||||
folder: false,
|
||||
extension: "dll",
|
||||
validator: _checkDll
|
||||
),
|
||||
|
||||
FileSelector(
|
||||
label: "Console DLL",
|
||||
placeholder: "Type the path to the console dll",
|
||||
controller: _settingsController.consoleDll,
|
||||
windowTitle: "Select a dll",
|
||||
folder: false,
|
||||
extension: "dll",
|
||||
validator: _checkDll
|
||||
),
|
||||
|
||||
FileSelector(
|
||||
label: "Cranium DLL",
|
||||
placeholder: "Type the path to the cranium dll",
|
||||
controller: _settingsController.craniumDll,
|
||||
windowTitle: "Select a dll",
|
||||
folder: false,
|
||||
extension: "dll",
|
||||
validator: _checkDll
|
||||
),
|
||||
|
||||
SmartSwitch(
|
||||
value: _settingsController.autoUpdate,
|
||||
label: "Update DLLs"
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
|
||||
const Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Text("Version 3.11${kDebugMode ? '-DEBUG' : ''}")
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String? _checkDll(String? text) {
|
||||
if (text == null || text.isEmpty) {
|
||||
return "Empty dll path";
|
||||
}
|
||||
|
||||
if (!File(text).existsSync()) {
|
||||
return "This dll doesn't exist";
|
||||
}
|
||||
|
||||
if (!text.endsWith(".dll")) {
|
||||
return "This file is not a dll";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
Future<File> loadBinary(String binary, bool safe) async{
|
||||
var safeBinary = File("$safeBinariesDirectory/$binary");
|
||||
var safeBinary = File("$safeBinariesDirectory\\$binary");
|
||||
if(await safeBinary.exists()){
|
||||
return safeBinary;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,22 @@ bool get isWin11 {
|
||||
return intBuild != null && intBuild > 22000;
|
||||
}
|
||||
|
||||
Future<String?> openFilePicker(String title) async =>
|
||||
Future<String?> openFolderPicker(String title) async =>
|
||||
await FilePicker.platform.getDirectoryPath(dialogTitle: title);
|
||||
|
||||
Future<String?> openFilePicker(String extension) async {
|
||||
var result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowMultiple: false,
|
||||
allowedExtensions: [extension]
|
||||
);
|
||||
if(result == null || result.files.isEmpty){
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.files.first.path;
|
||||
}
|
||||
|
||||
Future<List<Directory>> scanInstallations(String input) => Directory(input)
|
||||
.list(recursive: true)
|
||||
.handleError((_) {}, test: (e) => e is FileSystemException)
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/widget/select_file.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
|
||||
class AddLocalVersion extends StatelessWidget {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
@@ -76,12 +76,14 @@ class AddLocalVersion extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
|
||||
SelectFile(
|
||||
FileSelector(
|
||||
label: "Location",
|
||||
placeholder: "Type the game folder",
|
||||
windowTitle: "Select game folder",
|
||||
controller: _gamePathController,
|
||||
validator: _checkGameFolder)
|
||||
validator: _checkGameFolder,
|
||||
folder: true
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/util/binary.dart';
|
||||
import 'package:reboot_launcher/src/util/build.dart';
|
||||
import 'package:reboot_launcher/src/widget/select_file.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/widget/version_name_input.dart';
|
||||
|
||||
import 'build_selector.dart';
|
||||
@@ -242,12 +242,13 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
|
||||
VersionNameInput(controller: _nameController),
|
||||
|
||||
SelectFile(
|
||||
FileSelector(
|
||||
label: "Destination",
|
||||
placeholder: "Type the download destination",
|
||||
windowTitle: "Select download destination",
|
||||
controller: _pathController,
|
||||
validator: _checkDownloadDestination
|
||||
validator: _checkDownloadDestination,
|
||||
folder: true
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -3,29 +3,34 @@ import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../util/os.dart';
|
||||
|
||||
class SelectFile extends StatefulWidget {
|
||||
class FileSelector extends StatefulWidget {
|
||||
final String label;
|
||||
final String placeholder;
|
||||
final String windowTitle;
|
||||
final bool allowNavigator;
|
||||
final TextEditingController controller;
|
||||
final String? Function(String?) validator;
|
||||
final String? extension;
|
||||
final bool folder;
|
||||
|
||||
const SelectFile(
|
||||
const FileSelector(
|
||||
{required this.label,
|
||||
required this.placeholder,
|
||||
required this.windowTitle,
|
||||
required this.controller,
|
||||
required this.validator,
|
||||
required this.folder,
|
||||
this.extension,
|
||||
this.allowNavigator = true,
|
||||
Key? key})
|
||||
: super(key: key);
|
||||
: assert(folder || extension != null, "Missing extension for file selector"),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
State<SelectFile> createState() => _SelectFileState();
|
||||
State<FileSelector> createState() => _FileSelectorState();
|
||||
}
|
||||
|
||||
class _SelectFileState extends State<SelectFile> {
|
||||
class _FileSelectorState extends State<FileSelector> {
|
||||
bool _selecting = false;
|
||||
|
||||
@override
|
||||
@@ -47,7 +52,7 @@ class _SelectFileState extends State<SelectFile> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 21.0),
|
||||
child: Tooltip(
|
||||
message: "Select a folder",
|
||||
message: "Select a ${widget.folder ? 'folder' : 'file'}",
|
||||
child: Button(
|
||||
onPressed: _onPressed,
|
||||
child: const Icon(FluentIcons.open_folder_horizontal)
|
||||
@@ -66,7 +71,14 @@ class _SelectFileState extends State<SelectFile> {
|
||||
}
|
||||
|
||||
_selecting = true;
|
||||
compute(openFilePicker, "Select the game folder")
|
||||
if(widget.folder) {
|
||||
compute(openFolderPicker, widget.windowTitle)
|
||||
.then((value) => widget.controller.text = value ?? "")
|
||||
.then((_) => _selecting = false);
|
||||
return;
|
||||
}
|
||||
|
||||
compute(openFilePicker, widget.extension!)
|
||||
.then((value) => widget.controller.text = value ?? "")
|
||||
.then((_) => _selecting = false);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:win32_suspend_process/win32_suspend_process.dart';
|
||||
|
||||
import '../controller/settings_controller.dart';
|
||||
import '../util/server_standalone.dart';
|
||||
|
||||
class LaunchButton extends StatefulWidget {
|
||||
@@ -29,6 +30,7 @@ class LaunchButton extends StatefulWidget {
|
||||
class _LaunchButtonState extends State<LaunchButton> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final ServerController _serverController = Get.find<ServerController>();
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
File? _logFile;
|
||||
bool _fail = false;
|
||||
|
||||
@@ -114,7 +116,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
_gameController.gameProcess = await Process.start(gamePath, createRebootArgs(_gameController.username.text, hosting))
|
||||
..exitCode.then((_) => _onEnd())
|
||||
..outLines.forEach(_onGameOutput);
|
||||
await _injectOrShowError("cranium.dll");
|
||||
await _injectOrShowError(Injectable.cranium);
|
||||
|
||||
if(hosting){
|
||||
await _showServerLaunchingWarning();
|
||||
@@ -333,12 +335,12 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
}
|
||||
|
||||
if (line.contains("Game Engine Initialized") && _gameController.type.value == GameType.client) {
|
||||
_injectOrShowError("console.dll");
|
||||
_injectOrShowError(Injectable.console);
|
||||
return;
|
||||
}
|
||||
|
||||
if(line.contains("Region") && _gameController.type.value != GameType.client){
|
||||
_injectOrShowError("reboot.dll")
|
||||
_injectOrShowError(Injectable.reboot)
|
||||
.then((value) => _closeDialogIfOpen(true));
|
||||
}
|
||||
}
|
||||
@@ -374,22 +376,33 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
_gameController.kill();
|
||||
}
|
||||
|
||||
Future<void> _injectOrShowError(String binary) async {
|
||||
Future<void> _injectOrShowError(Injectable injectable) async {
|
||||
var gameProcess = _gameController.gameProcess;
|
||||
if (gameProcess == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var dll = await loadBinary(binary, true);
|
||||
var success = await injectDll(gameProcess.pid, dll.path);
|
||||
var dllPath = _getDllPath(injectable);
|
||||
var success = await injectDll(gameProcess.pid, dllPath);
|
||||
if (success) {
|
||||
return;
|
||||
}
|
||||
|
||||
_onInjectError(binary);
|
||||
_onInjectError(injectable.name);
|
||||
} catch (exception) {
|
||||
_onInjectError(binary);
|
||||
_onInjectError(injectable.name);
|
||||
}
|
||||
}
|
||||
|
||||
String _getDllPath(Injectable injectable){
|
||||
switch(injectable){
|
||||
case Injectable.reboot:
|
||||
return _settingsController.rebootDll.text;
|
||||
case Injectable.console:
|
||||
return _settingsController.consoleDll.text;
|
||||
case Injectable.cranium:
|
||||
return _settingsController.craniumDll.text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,3 +411,9 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
launchUrl(injectLogFile.uri);
|
||||
}
|
||||
}
|
||||
|
||||
enum Injectable {
|
||||
console,
|
||||
cranium,
|
||||
reboot
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/widget/select_file.dart';
|
||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||
|
||||
|
||||
class ScanLocalVersion extends StatefulWidget {
|
||||
@@ -83,12 +83,14 @@ class _ScanLocalVersionState extends State<ScanLocalVersion> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SelectFile(
|
||||
FileSelector(
|
||||
label: "Location",
|
||||
placeholder: "Type the folder to scan",
|
||||
windowTitle: "Select the folder to scan",
|
||||
controller: _folderController,
|
||||
validator: _checkScanFolder)
|
||||
validator: _checkScanFolder,
|
||||
folder: true
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
|
||||
class SmartInput extends StatelessWidget {
|
||||
final String label;
|
||||
final String? label;
|
||||
final String placeholder;
|
||||
final TextEditingController controller;
|
||||
final TextInputType type;
|
||||
@@ -11,13 +11,13 @@ class SmartInput extends StatelessWidget {
|
||||
|
||||
const SmartInput(
|
||||
{Key? key,
|
||||
required this.label,
|
||||
required this.placeholder,
|
||||
required this.controller,
|
||||
this.onTap,
|
||||
this.enabled = true,
|
||||
this.populate = false,
|
||||
this.type = TextInputType.text})
|
||||
required this.placeholder,
|
||||
required this.controller,
|
||||
this.label,
|
||||
this.onTap,
|
||||
this.enabled = true,
|
||||
this.populate = false,
|
||||
this.type = TextInputType.text})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user