Released 9.2.7

This commit is contained in:
Alessandro Autiero
2024-09-14 12:37:56 +02:00
parent a9af28273a
commit bfe15e43d9
15 changed files with 331 additions and 255 deletions

View File

@@ -133,9 +133,9 @@ Future<void> _downloadArchive(FortniteBuildDownloadOptions options, Completer st
throw _genericError;
},
headers: byteStart == null || byteStart <= 0 ? {
"Cookie": "_c_t_c=1"
} : {
"Cookie": "_c_t_c=1",
"Range": "bytes=${byteStart}-"
},
)

View File

@@ -7,7 +7,7 @@ environment:
sdk: ">=3.0.0 <=4.0.0"
dependencies:
dio: ^5.3.2
dio: ^5.7.0
win32: 3.0.0
ffi: ^2.1.0
path: ^1.8.3

View File

@@ -368,5 +368,7 @@
"automaticGameServerDialogStart": "Start server",
"gameResetDefaultsName": "Reset",
"gameResetDefaultsDescription": "Resets the game's settings to their default values",
"gameResetDefaultsContent": "Reset"
"gameResetDefaultsContent": "Reset",
"selectFile": "Select a file",
"reset": "Reset"
}

View File

@@ -109,7 +109,9 @@ class DllController extends GetxController {
duration: null
);
}
timestamp.value = await downloadRebootDll(url.text);
final result = downloadRebootDll(url.text);
timestamp.value = await Future.wait([result, Future.delayed(const Duration(seconds: 1))], eagerError: false)
.then((_) => result);
status.value = UpdateStatus.success;
infoBarEntry?.close();
if(!silent) {
@@ -126,15 +128,18 @@ class DllController extends GetxController {
error = error.contains(": ") ? error.substring(error.indexOf(": ") + 2) : error;
error = error.toLowerCase();
status.value = UpdateStatus.error;
showRebootInfoBar(
translations.downloadDllError("reboot.dll", error.toString()),
infoBarEntry = showRebootInfoBar(
translations.downloadDllError(error.toString(), "reboot.dll"),
duration: infoBarLongDuration,
severity: InfoBarSeverity.error,
action: Button(
onPressed: () => updateGameServerDll(
onPressed: () async {
infoBarEntry?.close();
updateGameServerDll(
force: true,
silent: silent
),
);
},
child: Text(translations.downloadDllRetry),
)
);
@@ -215,7 +220,7 @@ class DllController extends GetxController {
error = error.toLowerCase();
final completer = Completer();
await showRebootInfoBar(
translations.downloadDllError(fileName, error.toString()),
translations.downloadDllError(error.toString(), fileName),
duration: infoBarLongDuration,
severity: InfoBarSeverity.error,
onDismissed: () => completer.complete(null),

View File

@@ -18,9 +18,12 @@ void onError(Object exception, StackTrace? stackTrace, bool framework) {
}
lastError = exception.toString();
final route = ModalRoute.of(pageKey.currentContext!);
if(route != null && !route.isCurrent){
Navigator.of(pageKey.currentContext!).pop(false);
if(inDialog){
final context = pageKey.currentContext;
if(context != null) {
Navigator.of(context).pop(false);
inDialog = false;
}
}
WidgetsBinding.instance.addPostFrameCallback((timeStamp) => showRebootDialog(

View File

@@ -5,10 +5,13 @@ import 'dart:isolate';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/messenger/abstract/dialog.dart';
import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/util/translations.dart';
import 'package:reboot_launcher/src/util/types.dart';
import 'package:reboot_launcher/src/widget/file_selector.dart';
import 'package:universal_disk_space/universal_disk_space.dart';
import 'package:windows_taskbar/windows_taskbar.dart';
@@ -41,6 +44,7 @@ class _AddVersionDialogState extends State<AddVersionDialog> {
SendPort? _downloadPort;
Object? _error;
StackTrace? _stackTrace;
bool _selecting = false;
@override
void initState() {
@@ -102,7 +106,12 @@ class _AddVersionDialogState extends State<AddVersionDialog> {
return ErrorDialog(
exception: _error ?? Exception(translations.unknownError),
stackTrace: _stackTrace,
errorMessageBuilder: (exception) => translations.downloadVersionError(exception.toString())
errorMessageBuilder: (exception) {
var error = exception.toString();
error = error.after("Error: ")?.replaceAll(":", ",") ?? error.after(": ") ?? error;
error = error.toLowerCase();
return translations.downloadVersionError(error);
}
);
case _DownloadStatus.done:
return InfoDialog(
@@ -274,7 +283,8 @@ class _AddVersionDialogState extends State<AddVersionDialog> {
);
}
Widget _buildFormBody(List<FortniteBuild> builds) => Column(
Widget _buildFormBody(List<FortniteBuild> builds) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -292,7 +302,8 @@ class _AddVersionDialogState extends State<AddVersionDialog> {
windowTitle: _source.value == _BuildSource.local ? translations.gameFolderPlaceWindowTitle : translations.buildInstallationDirectoryWindowTitle,
controller: _pathController,
validator: _source.value == _BuildSource.local ? _checkGameFolder : _checkDownloadDestination,
folder: true
folder: true,
allowNavigator: true
),
const SizedBox(
@@ -300,6 +311,7 @@ class _AddVersionDialogState extends State<AddVersionDialog> {
)
],
);
}
String? _checkGameFolder(text) {
if (text == null || text.isEmpty) {

View File

@@ -153,9 +153,9 @@ class _BackendPageState extends RebootPageState<BackendPage> {
contentWidth: null,
content: Row(
children: [
Text(
Obx(() => Text(
_backendController.detached.value ? translations.on : translations.off
),
)),
const SizedBox(
width: 16.0
),

View File

@@ -298,8 +298,7 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
});
}
Widget _buildBody() {
return Expanded(
Widget _buildBody() => Expanded(
child: Padding(
padding: EdgeInsets.only(
left: HomePage.kDefaultPadding,
@@ -339,7 +338,6 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
)
),
);
}
Widget _buildBodyContent() => PageView.builder(
controller: _pageController,

View File

@@ -175,9 +175,9 @@ class _HostingPageState extends RebootPageState<HostPage> {
contentWidth: null,
content: Obx(() => Row(
children: [
Text(
Obx(() => Text(
_hostingController.discoverable.value ? translations.on : translations.off
),
)),
const SizedBox(
width: 16.0
),
@@ -238,9 +238,9 @@ class _HostingPageState extends RebootPageState<HostPage> {
contentWidth: null,
content: Row(
children: [
Text(
Obx(() => Text(
_hostingController.autoRestart.value ? translations.on : translations.off
),
)),
const SizedBox(
width: 16.0
),
@@ -278,12 +278,19 @@ class _HostingPageState extends RebootPageState<HostPage> {
title: Text(translations.settingsServerName),
subtitle: Text(translations.settingsServerSubtitle),
children: [
SettingTile(
_internalFilesServerType,
_internalFilesUpdateTimer,
_internalFilesServerSource
],
);
Widget get _internalFilesServerType => SettingTile(
icon: Icon(
FluentIcons.timer_24_regular
FluentIcons.games_24_regular
),
title: Text(translations.settingsServerTypeName),
subtitle: Text(translations.settingsServerTypeDescription),
contentWidth: SettingTile.kDefaultContentWidth + 30,
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
@@ -309,41 +316,28 @@ class _HostingPageState extends RebootPageState<HostPage> {
}
)).toList()
))
),
Obx(() {
if(!_dllController.customGameServer.value) {
return const SizedBox.shrink();
}
return createFileSetting(
title: translations.settingsServerFileName,
description: translations.settingsServerFileDescription,
controller: _dllController.gameServerDll,
onReset: () {
final path = _dllController.getDefaultDllPath(InjectableDll.reboot);
_dllController.gameServerDll.text = path;
_dllController.downloadCriticalDllInteractive(path);
}
);
}),
Obx(() {
if(_dllController.customGameServer.value) {
return const SizedBox.shrink();
}
Widget get _internalFilesServerSource => Obx(() {
if(!_dllController.customGameServer.value) {
return SettingTile(
icon: Icon(
FluentIcons.globe_24_regular
),
title: Text(translations.settingsServerMirrorName),
subtitle: Text(translations.settingsServerMirrorDescription),
contentWidth: SettingTile.kDefaultContentWidth + 30,
content: Row(
children: [
Expanded(
child: TextFormBox(
placeholder: translations.settingsServerMirrorPlaceholder,
controller: _dllController.url,
validator: _checkUpdateUrl
onChanged: (value) {
if(Uri.tryParse(value) != null) {
_dllController.updateGameServerDll(force: true);
}
},
),
),
const SizedBox(width: 8.0),
@@ -351,7 +345,23 @@ class _HostingPageState extends RebootPageState<HostPage> {
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
),
onPressed: () => _dllController.url.text = kRebootDownloadUrl,
onPressed: () => _dllController.updateGameServerDll(force: true),
child: SizedBox.square(
dimension: 30,
child: Icon(
FluentIcons.arrow_download_24_regular
),
)
),
const SizedBox(width: 8.0),
Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
),
onPressed: () {
_dllController.url.text = kRebootDownloadUrl;
_dllController.updateGameServerDll(force: true);
},
child: SizedBox.square(
dimension: 30,
child: Icon(
@@ -362,8 +372,21 @@ class _HostingPageState extends RebootPageState<HostPage> {
],
)
);
}),
Obx(() {
}else {
return createFileSetting(
title: translations.settingsServerFileName,
description: translations.settingsServerFileDescription,
controller: _dllController.gameServerDll,
onReset: () {
final path = _dllController.getDefaultDllPath(InjectableDll.reboot);
_dllController.gameServerDll.text = path;
_dllController.downloadCriticalDllInteractive(path);
}
);
}
});
Widget get _internalFilesUpdateTimer => Obx(() {
if(_dllController.customGameServer.value) {
return const SizedBox.shrink();
}
@@ -374,10 +397,8 @@ class _HostingPageState extends RebootPageState<HostPage> {
),
title: Text(translations.settingsServerTimerName),
subtitle: Text(translations.settingsServerTimerSubtitle),
content: Row(
children: [
Expanded(
child: Obx(() => DropDownButton(
contentWidth: SettingTile.kDefaultContentWidth + 30,
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
leading: Text(_dllController.timer.value.text),
@@ -391,38 +412,9 @@ class _HostingPageState extends RebootPageState<HostPage> {
);
}
)).toList()
)),
),
const SizedBox(width: 8.0),
Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
),
onPressed: () {
_dllController.updateGameServerDll(force: true);
},
child: SizedBox.square(
dimension: 30,
child: Icon(
FluentIcons.arrow_download_24_regular
),
)
)
],
)
))
);
})
],
);
String? _checkUpdateUrl(String? text) {
if (text == null || text.isEmpty) {
return translations.emptyURL;
}
return null;
}
});
SettingTile get _share => SettingTile(
icon: Icon(

View File

@@ -110,9 +110,9 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
contentWidth: null,
content: Row(
children: [
Text(
Obx(() => Text(
_settingsController.debug.value ? translations.on : translations.off
),
)),
const SizedBox(
width: 16.0
),

View File

@@ -6,3 +6,14 @@ extension IterableExtension<E> on Iterable<E> {
return null;
}
}
extension StringExtension on String {
String? after(String leading) {
final index = indexOf(leading);
if(index == -1) {
return null;
}
return substring(index + leading.length);
}
}

View File

@@ -19,10 +19,10 @@ class FileSelector extends StatefulWidget {
required this.controller,
required this.validator,
required this.folder,
required this.allowNavigator,
this.label,
this.extension,
this.validatorMode,
this.allowNavigator = true,
Key? key})
: assert(folder || extension != null, "Missing extension for file selector"),
super(key: key);

View File

@@ -1,21 +1,29 @@
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
import 'package:fluent_ui/fluent_ui.dart' as fluentIcons show FluentIcons;
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/util/translations.dart';
import 'package:reboot_launcher/src/widget/file_selector.dart';
import 'package:reboot_launcher/src/widget/setting_tile.dart';
const double _kButtonDimensions = 30;
const double _kButtonSpacing = 8;
SettingTile createFileSetting({required String title, required String description, required TextEditingController controller, required void Function() onReset}) {
final obx = RxString(controller.text);
controller.addListener(() => obx.value = controller.text);
final selecting = RxBool(false);
return SettingTile(
icon: Icon(
FluentIcons.document_24_regular
),
title: Text(title),
subtitle: Text(description),
contentWidth: SettingTile.kDefaultContentWidth + _kButtonDimensions * 2 + _kButtonSpacing * 2,
content: Row(
children: [
Expanded(
@@ -26,30 +34,72 @@ SettingTile createFileSetting({required String title, required String descriptio
validator: _checkDll,
extension: "dll",
folder: false,
validatorMode: AutovalidateMode.always
validatorMode: AutovalidateMode.always,
allowNavigator: false,
),
),
const SizedBox(width: 8.0),
const SizedBox(width: _kButtonSpacing),
Obx(() => Padding(
padding: EdgeInsets.only(
bottom: _checkDll(obx.value) == null ? 0.0 : 20.0
),
child: Tooltip(
message: translations.selectFile,
child: Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
),
onPressed: () => _onPressed(selecting, controller),
child: SizedBox.square(
dimension: _kButtonDimensions,
child: Icon(
fluentIcons.FluentIcons.open_folder_horizontal
),
)
),
),
)),
const SizedBox(width: _kButtonSpacing),
Obx(() => Padding(
padding: EdgeInsets.only(
bottom: _checkDll(obx.value) == null ? 0.0 : 20.0
),
child: Tooltip(
message: translations.reset,
child: Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
),
onPressed: onReset,
child: SizedBox.square(
dimension: 30,
dimension: _kButtonDimensions,
child: Icon(
FluentIcons.arrow_reset_24_regular
),
)
),
),
))
],
)
);
);
}
void _onPressed(RxBool selecting, TextEditingController controller) {
if(selecting.value){
return;
}
selecting.value = true;
compute(openFilePicker, "dll")
.then((value) => _updateText(controller, value))
.then((_) => selecting.value = false);
}
void _updateText(TextEditingController controller, String? value) {
final text = value ?? controller.text;
controller.text = text;
controller.selection = TextSelection.collapsed(offset: text.length);
}
String? _checkDll(String? text) {

View File

@@ -24,7 +24,9 @@ class InfoBarAreaState extends State<InfoBarArea> {
}
@override
Widget build(BuildContext context) => Obx(() => Padding(
Widget build(BuildContext context) => StreamBuilder(
stream: pagesController.stream,
builder: (context, _) => Obx(() => Padding(
padding: EdgeInsets.only(
bottom: hasPageButton ? 72.0 : 16.0
),
@@ -38,5 +40,6 @@ class InfoBarAreaState extends State<InfoBarArea> {
child: child
)).toList(growable: false)
),
));
))
);
}

View File

@@ -1,6 +1,6 @@
name: reboot_launcher
description: Graphical User Interface for Project Reboot
version: "9.2.6"
version: "9.2.7"
publish_to: 'none'