Minor fixes

This commit is contained in:
Alessandro Autiero
2023-06-04 00:52:31 +02:00
parent 30f1b0f162
commit 0f7d47ef10
11 changed files with 361 additions and 284 deletions

View File

@@ -43,7 +43,6 @@ void main() async {
Get.put(SettingsController());
Get.put(HostingController());
doWhenWindowReady(() {
appWindow.minSize = const Size(kDefaultWindowWidth, kDefaultWindowHeight);
var controller = Get.find<SettingsController>();
var size = Size(controller.width, controller.height);
var window = appWindow as WinDesktopWindow;

View File

@@ -36,7 +36,7 @@ Future<void> startGame() async {
stdout.writeln("No username was specified, using $username by default. Use --username to specify one");
}
_gameProcess = await Process.start(gamePath, createRebootArgs(username!, host, ""))
_gameProcess = await Process.start(gamePath, createRebootArgs(username!, "", host, ""))
..exitCode.then((_) => _onClose())
..outLines.forEach((line) => _onGameOutput(line, dll, host, verbose));
}

View File

@@ -103,6 +103,7 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
appBar: NavigationAppBar(
title: _draggableArea,
actions: WindowTitleBar(focused: _focused()),
automaticallyImplyLeading: false,
leading: _backButton
),
pane: NavigationPane(
@@ -119,7 +120,8 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
transitionBuilder: (child, animation) => child
))
),
Obx(() => isWin11 && _focused.value ? const WindowBorder() : const SizedBox())
if(isWin11)
Obx(() => _focused.value ? const WindowBorder() : const SizedBox())
]
);
}
@@ -129,13 +131,15 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
entry.value;
}
var onBack = _onBack();
return PaneItem(
enabled: onBack != null,
icon: const Icon(FluentIcons.back, size: 14.0),
body: const SizedBox.shrink(),
).build(
context,
false,
_onBack(),
onBack,
displayMode: PaneDisplayMode.compact
);
});
@@ -157,7 +161,10 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
};
}
void _onIndexChanged(int index) => _index.value = index;
void _onIndexChanged(int index) {
_navigationStatus[_index()].value = false;
_index.value = index;
}
TextBox get _autoSuggestBox => TextBox(
key: _searchKey,

View File

@@ -7,11 +7,8 @@ import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
import 'package:reboot_launcher/src/ui/widget/shared/setting_tile.dart';
import '../../model/update_status.dart';
import '../../util/reboot.dart';
import '../controller/update_controller.dart';
import 'browse_page.dart';
class HostingPage extends StatefulWidget {
final GlobalKey<NavigatorState> navigatorKey;
final RxBool nestedNavigation;
@@ -34,6 +31,20 @@ class _HostingPageState extends State<HostingPage> with AutomaticKeepAliveClient
return Obx(() => !_settingsController.autoUpdate() || _hostingController.updateStatus().isDone() ? _body : _updateScreen);
}
Widget get _updateScreen => const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ProgressRing(),
SizedBox(height: 16.0),
Text("Updating Reboot DLL...")
],
),
],
);
Widget get _body => Navigator(
key: widget.navigatorKey,
initialRoute: "home",
@@ -49,129 +60,140 @@ class _HostingPageState extends State<HostingPage> with AutomaticKeepAliveClient
Widget _createScreen(String? name) {
switch(name){
case "home":
return _homeScreen;
return _HostPage(widget.navigatorKey, widget.nestedNavigation);
case "browse":
return const BrowsePage();
default:
throw Exception("Unknown page: $name");
}
}
}
Widget get _homeScreen => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Obx(() => SizedBox(
width: double.infinity,
child: _hostingController.updateStatus.value == UpdateStatus.error ? _updateError :_rebootGuiInfo,
)),
const SizedBox(
height: 16.0
),
SettingTile(
title: "Game Server",
subtitle: "Provide basic information about your server",
expandedContentSpacing: 0,
expandedContent: [
SettingTile(
title: "Name",
subtitle: "The name of your game server",
isChild: true,
content: TextFormBox(
placeholder: "Name",
controller: _hostingController.name
)
class _HostPage extends StatefulWidget {
final GlobalKey<NavigatorState> navigatorKey;
final RxBool nestedNavigation;
const _HostPage(this.navigatorKey, this.nestedNavigation, {Key? key}) : super(key: key);
@override
State<_HostPage> createState() => _HostPageState();
}
class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin {
final HostingController _hostingController = Get.find<HostingController>();
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Column(
children: [
Expanded(
child: ListView(
children: [
Obx(() => SizedBox(
width: double.infinity,
child: _hostingController.updateStatus.value == UpdateStatus.error ? _updateError : _rebootGuiInfo,
)),
const SizedBox(
height: 16.0
),
SettingTile(
title: "Game Server",
subtitle: "Provide basic information about your server",
expandedContentSpacing: 0,
expandedContent: [
SettingTile(
title: "Name",
subtitle: "The name of your game server",
isChild: true,
content: TextFormBox(
placeholder: "Name",
controller: _hostingController.name
)
),
SettingTile(
title: "Description",
subtitle: "The description of your game server",
isChild: true,
content: TextFormBox(
placeholder: "Description",
controller: _hostingController.description
)
),
SettingTile(
title: "Discoverable",
subtitle: "Make your server available to other players on the server browser",
isChild: true,
contentWidth: null,
content: Obx(() => ToggleSwitch(
checked: _hostingController.discoverable(),
onChanged: (value) => _hostingController.discoverable.value = value
))
),
],
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Version",
subtitle: "Select the version of Fortnite you want to host",
content: const VersionSelector(),
expandedContent: [
SettingTile(
title: "Add a version from this PC's local storage",
subtitle: "Versions coming from your local disk are not guaranteed to work",
content: Button(
onPressed: () => VersionSelector.openAddDialog(context),
child: const Text("Add build"),
),
isChild: true
),
SettingTile(
title: "Download any version from the cloud",
subtitle: "A curated list of supported versions by Project Reboot",
content: Button(
onPressed: () => VersionSelector.openDownloadDialog(context),
child: const Text("Download"),
),
isChild: true
)
]
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Browse available servers",
subtitle: "See a list of other game servers that are being hosted",
content: Button(
onPressed: () {
widget.navigatorKey.currentState?.pushNamed('browse');
widget.nestedNavigation.value = true;
},
child: const Text("Browse")
)
),
],
),
SettingTile(
title: "Description",
subtitle: "The description of your game server",
isChild: true,
content: TextFormBox(
placeholder: "Description",
controller: _hostingController.description
)
),
SettingTile(
title: "Discoverable",
subtitle: "Make your server available to other players on the server browser",
isChild: true,
contentWidth: null,
content: Obx(() => ToggleSwitch(
checked: _hostingController.discoverable(),
onChanged: (value) => _hostingController.discoverable.value = value
))
),
],
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Version",
subtitle: "Select the version of Fortnite you want to host",
content: const VersionSelector(),
expandedContent: [
SettingTile(
title: "Add a version from this PC's local storage",
subtitle: "Versions coming from your local disk are not guaranteed to work",
content: Button(
onPressed: () => VersionSelector.openAddDialog(context),
child: const Text("Add build"),
),
isChild: true
),
SettingTile(
title: "Download any version from the cloud",
subtitle: "A curated list of supported versions by Project Reboot",
content: Button(
onPressed: () => VersionSelector.openDownloadDialog(context),
child: const Text("Download"),
),
isChild: true
)
]
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Browse available servers",
subtitle: "See a list of other game servers that are being hosted",
content: Button(
onPressed: () {
widget.navigatorKey.currentState?.pushNamed('browse');
widget.nestedNavigation.value = true;
},
child: const Text("Browse")
)
),
const Expanded(child: SizedBox()),
const LaunchButton(
host: true
)
],
);
),
const SizedBox(
height: 8.0,
),
const LaunchButton(
host: true
)
],
);
}
InfoBar get _rebootGuiInfo => const InfoBar(
title: Text("A window will pop up after the game server is started to modify its in-game settings"),
severity: InfoBarSeverity.info
);
Widget get _updateScreen => const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ProgressRing(),
SizedBox(height: 16.0),
Text("Updating Reboot DLL...")
],
),
],
);
Widget get _updateError => MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(

View File

@@ -69,108 +69,115 @@ class _GamePageState extends State<_GamePage> {
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SettingTile(
title: "Credentials",
subtitle: "Your in-game login credentials",
expandedContentSpacing: 0,
expandedContent: [
SettingTile(
title: "Username",
subtitle: "The username that other players will see when you are in game",
isChild: true,
content: TextFormBox(
placeholder: "Username",
controller: _gameController.username,
autovalidateMode: AutovalidateMode.always
),
),
SettingTile(
title: "Password",
subtitle: "The password of your account, only used if the backend requires it",
isChild: true,
content: Obx(() => TextFormBox(
placeholder: "Password",
controller: _gameController.password,
autovalidateMode: AutovalidateMode.always,
obscureText: !_gameController.showPassword.value,
enableSuggestions: false,
autocorrect: false,
onChanged: (text) => _showPasswordTrailing.value = text.isNotEmpty,
suffix: Button(
onPressed: () => _gameController.showPassword.value = !_gameController.showPassword.value,
style: ButtonStyle(
shape: ButtonState.all(const CircleBorder()),
backgroundColor: ButtonState.all(Colors.transparent)
),
child: Icon(
_gameController.showPassword.value ? Icons.visibility_off : Icons.visibility,
color: _showPasswordTrailing.value ? null : Colors.transparent
Expanded(
child: ListView(
children: [
SettingTile(
title: "Credentials",
subtitle: "Your in-game login credentials",
expandedContentSpacing: 0,
expandedContent: [
SettingTile(
title: "Username",
subtitle: "The username that other players will see when you are in game",
isChild: true,
content: TextFormBox(
placeholder: "Username",
controller: _gameController.username,
autovalidateMode: AutovalidateMode.always
),
),
SettingTile(
title: "Password",
subtitle: "The password of your account, only used if the backend requires it",
isChild: true,
content: Obx(() => TextFormBox(
placeholder: "Password",
controller: _gameController.password,
autovalidateMode: AutovalidateMode.always,
obscureText: !_gameController.showPassword.value,
enableSuggestions: false,
autocorrect: false,
onChanged: (text) => _showPasswordTrailing.value = text.isNotEmpty,
suffix: Button(
onPressed: () => _gameController.showPassword.value = !_gameController.showPassword.value,
style: ButtonStyle(
shape: ButtonState.all(const CircleBorder()),
backgroundColor: ButtonState.all(Colors.transparent)
),
child: Icon(
_gameController.showPassword.value ? Icons.visibility_off : Icons.visibility,
color: _showPasswordTrailing.value ? null : Colors.transparent
),
)
))
)
))
)
],
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Matchmaking host",
subtitle: "Enter the IP address of the game server hosting the match",
content: TextFormBox(
placeholder: "IP:PORT",
controller: _settingsController.matchmakingIp,
validator: checkMatchmaking,
autovalidateMode: AutovalidateMode.always
),
expandedContent: [
SettingTile(
title: "Browse available servers",
subtitle: "Discover new game servers that fit your play-style",
content: Button(
onPressed: () {
widget.navigatorKey.currentState?.pushNamed('browse');
widget.nestedNavigation.value = true;
},
child: const Text("Browse")
],
),
isChild: true
)
]
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Version",
subtitle: "Select the version of Fortnite you want to play",
content: const VersionSelector(),
expandedContent: [
SettingTile(
title: "Add a version from this PC's local storage",
subtitle: "Versions coming from your local disk are not guaranteed to work",
content: Button(
onPressed: () => VersionSelector.openAddDialog(context),
child: const Text("Add build"),
),
isChild: true
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Download any version from the cloud",
subtitle: "A curated list of supported versions by Project Reboot",
content: Button(
onPressed: () => VersionSelector.openDownloadDialog(context),
child: const Text("Download"),
),
isChild: true
title: "Matchmaking host",
subtitle: "Enter the IP address of the game server hosting the match",
content: TextFormBox(
placeholder: "IP:PORT",
controller: _settingsController.matchmakingIp,
validator: checkMatchmaking,
autovalidateMode: AutovalidateMode.always
),
expandedContent: [
SettingTile(
title: "Browse available servers",
subtitle: "Discover new game servers that fit your play-style",
content: Button(
onPressed: () {
widget.navigatorKey.currentState?.pushNamed('browse');
widget.nestedNavigation.value = true;
},
child: const Text("Browse")
),
isChild: true
)
]
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Version",
subtitle: "Select the version of Fortnite you want to play",
content: const VersionSelector(),
expandedContent: [
SettingTile(
title: "Add a version from this PC's local storage",
subtitle: "Versions coming from your local disk are not guaranteed to work",
content: Button(
onPressed: () => VersionSelector.openAddDialog(context),
child: const Text("Add build"),
),
isChild: true
),
SettingTile(
title: "Download any version from the cloud",
subtitle: "A curated list of supported versions by Project Reboot",
content: Button(
onPressed: () => VersionSelector.openDownloadDialog(context),
child: const Text("Download"),
),
isChild: true
)
]
)
]
],
),
),
const SizedBox(
height: 8.0,
),
const Expanded(child: SizedBox()),
const LaunchButton(
host: false
host: false
)
],
);

View File

@@ -29,73 +29,80 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
Widget build(BuildContext context) {
super.build(context);
return Obx(() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
width: double.infinity,
child: InfoBar(
title: Text("The backend server handles authentication and parties, not game hosting"),
severity: InfoBarSeverity.info
),
children: [
Expanded(
child: ListView(
children: [
const SizedBox(
width: double.infinity,
child: InfoBar(
title: Text("The backend server handles authentication and parties, not game hosting"),
severity: InfoBarSeverity.info
),
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Host",
subtitle: "Enter the host of the backend server",
content: TextFormBox(
placeholder: "Host",
controller: _serverController.host,
enabled: _isRemote
)
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Port",
subtitle: "Enter the port of the backend server",
content: TextFormBox(
placeholder: "Port",
controller: _serverController.port,
enabled: _isRemote
)
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Type",
subtitle: "Select the type of backend to use",
content: ServerTypeSelector()
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Detached",
subtitle: "Choose whether the backend should be started as a separate process, useful for debugging",
contentWidth: null,
content: Obx(() => ToggleSwitch(
checked: _serverController.detached(),
onChanged: (value) => _serverController.detached.value = value
))
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Server files",
subtitle: "The location where the backend is stored",
content: Button(
onPressed: () => launchUrl(serverDirectory.uri),
child: const Text("Open")
)
),
]
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Host",
subtitle: "Enter the host of the backend server",
content: TextFormBox(
placeholder: "Host",
controller: _serverController.host,
enabled: _isRemote
)
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Port",
subtitle: "Enter the port of the backend server",
content: TextFormBox(
placeholder: "Port",
controller: _serverController.port,
enabled: _isRemote
)
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Type",
subtitle: "Select the type of backend to use",
content: ServerTypeSelector()
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Detached",
subtitle: "Choose whether the backend should be started as a separate process, useful for debugging",
contentWidth: null,
content: Obx(() => ToggleSwitch(
checked: _serverController.detached(),
onChanged: (value) => _serverController.detached.value = value
))
),
const SizedBox(
height: 16.0,
),
SettingTile(
title: "Server files",
subtitle: "The location where the backend is stored",
content: Button(
onPressed: () => launchUrl(serverDirectory.uri),
child: const Text("Open")
)
),
const Expanded(child: SizedBox()),
const ServerButton()
]
),
const SizedBox(
height: 8.0,
),
ServerButton()
],
));
}

View File

@@ -33,8 +33,7 @@ class _SettingsPageState extends State<SettingsPage> with AutomaticKeepAliveClie
@override
Widget build(BuildContext context) {
super.build(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
return ListView(
children: [
SettingTile(
title: "File settings",

View File

@@ -185,7 +185,7 @@ class _LaunchButtonState extends State<LaunchButton> {
}
Future<Process> _createGameProcess(String gamePath, bool host) async {
var gameArgs = createRebootArgs(_safeUsername, host, _gameController.customLaunchArgs.text);
var gameArgs = createRebootArgs(_safeUsername, _gameController.password.text, host, _gameController.customLaunchArgs.text);
var gameProcess = await Process.start(gamePath, gameArgs);
gameProcess
..exitCode.then((_) => _onEnd())

View File

@@ -0,0 +1,31 @@
import 'package:fluent_ui/fluent_ui.dart';
class SquaredPaneItem extends PaneItem {
SquaredPaneItem({
super.key,
required super.title,
required super.icon,
required super.body,
});
@override
Widget build(
BuildContext context,
bool selected,
VoidCallback? onPressed, {
PaneDisplayMode? displayMode,
bool showTextOnTop = true,
int? itemIndex,
bool? autofocus,
}) {
return Column(
children: [
SizedBox.square(
dimension: 48,
child: icon
),
title!
],
);
}
}

View File

@@ -82,9 +82,13 @@ Future<void> resetWinNat() async {
await runElevated(binary.path, "");
}
List<String> createRebootArgs(String username, bool host, String additionalArgs) {
username = username.isEmpty ? kDefaultPlayerName : username;
username = host ? "$username${Random().nextInt(1000)}" : username;
List<String> createRebootArgs(String username, String password, bool host, String additionalArgs) {
if(password.isNotEmpty) {
username = username.isEmpty ? kDefaultPlayerName : username;
username = host ? "$username${Random().nextInt(1000)}" : username;
username = '$username@projectreboot.dev';
}
password = password.isNotEmpty ? password : "Rebooted";
var args = [
"-epicapp=Fortnite",
"-epicenv=Prod",
@@ -95,8 +99,8 @@ List<String> createRebootArgs(String username, bool host, String additionalArgs)
"-fromfl=eac",
"-fltoken=3db3ba5dcbd2e16703f3978d",
"-caldera=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50X2lkIjoiYmU5ZGE1YzJmYmVhNDQwN2IyZjQwZWJhYWQ4NTlhZDQiLCJnZW5lcmF0ZWQiOjE2Mzg3MTcyNzgsImNhbGRlcmFHdWlkIjoiMzgxMGI4NjMtMmE2NS00NDU3LTliNTgtNGRhYjNiNDgyYTg2IiwiYWNQcm92aWRlciI6IkVhc3lBbnRpQ2hlYXQiLCJub3RlcyI6IiIsImZhbGxiYWNrIjpmYWxzZX0.VAWQB67RTxhiWOxx7DBjnzDnXyyEnX7OljJm-j2d88G_WgwQ9wrE6lwMEHZHjBd1ISJdUO1UVUqkfLdU5nofBQ",
"-AUTH_LOGIN=$username@projectreboot.dev",
"-AUTH_PASSWORD=Rebooted",
"-AUTH_LOGIN=$username",
"-AUTH_PASSWORD=${password.isNotEmpty ? password : "Rebooted"}",
"-AUTH_TYPE=epic"
];

View File

@@ -42,6 +42,7 @@ dependencies:
uuid: ^3.0.6
supabase_flutter: ^1.10.0
supabase: ^1.9.1
fluentui_system_icons: ^1.1.202
dev_dependencies:
flutter_test: