mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 11:12:23 +01:00
Finished Launcher
Everything is smooth and the UI is perfect
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart'
|
||||
show WinDesktopWindow;
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
@@ -6,11 +8,13 @@ import 'package:reboot_launcher/src/controller/build_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/warning_controller.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
import 'package:reboot_launcher/src/page/home_page.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await SystemTheme.accentColor.load();
|
||||
await GetStorage.init("game");
|
||||
await GetStorage.init("server");
|
||||
await GetStorage.init("update");
|
||||
@@ -21,6 +25,8 @@ void main() async {
|
||||
SystemTheme.accentColor.load();
|
||||
doWhenWindowReady(() {
|
||||
const size = Size(600, 380);
|
||||
var window = appWindow as WinDesktopWindow;
|
||||
window.setWindowCutOnMaximize(appBarSize * 2);
|
||||
appWindow.size = size;
|
||||
appWindow.alignment = Alignment.center;
|
||||
appWindow.title = "Reboot Launcher";
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart' hide WindowBorder;
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/page/info_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/widget/window_buttons.dart';
|
||||
import 'package:reboot_launcher/src/widget/window_border.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../util/os.dart';
|
||||
import '../util/reboot.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
@@ -13,51 +17,92 @@ class HomePage extends StatefulWidget {
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
final List<Widget> _children = [LauncherPage(), ServerPage(), const InfoPage()];
|
||||
class _HomePageState extends State<HomePage> with WindowListener {
|
||||
late final Future _future;
|
||||
bool _focused = true;
|
||||
int _index = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
windowManager.addListener(this);
|
||||
_future = downloadRebootDll();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
windowManager.removeListener(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowFocus() {
|
||||
setState(() => _focused = true);
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowBlur() {
|
||||
setState(() => _focused = false);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NavigationView(
|
||||
pane: NavigationPane(
|
||||
selected: _index,
|
||||
onChanged: (index) => setState(() => _index = index),
|
||||
displayMode: PaneDisplayMode.top,
|
||||
indicator: const EndNavigationIndicator(),
|
||||
items: [
|
||||
_createPane("Launcher", FluentIcons.game),
|
||||
_createPane("Server", FluentIcons.server_enviroment),
|
||||
_createPane("Info", FluentIcons.info),
|
||||
],
|
||||
trailing: const WindowTitleBar()),
|
||||
content: FutureBuilder(
|
||||
future: _future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text(
|
||||
"An error occurred while loading the launcher: ${snapshot.error}",
|
||||
textAlign: TextAlign.center));
|
||||
}
|
||||
return Stack(
|
||||
children: [
|
||||
NavigationView(
|
||||
pane: NavigationPane(
|
||||
selected: _index,
|
||||
onChanged: (index) => setState(() => _index = index),
|
||||
displayMode: PaneDisplayMode.top,
|
||||
indicator: const EndNavigationIndicator(),
|
||||
items: [
|
||||
_createPane("Launcher", FluentIcons.game),
|
||||
_createPane("Server", FluentIcons.server_enviroment),
|
||||
_createPane("Info", FluentIcons.info),
|
||||
],
|
||||
trailing: WindowTitleBar(focused: _focused)),
|
||||
content: FutureBuilder(
|
||||
future: _future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text(
|
||||
"An error occurred while loading the launcher: ${snapshot.error}",
|
||||
textAlign: TextAlign.center));
|
||||
}
|
||||
return NavigationBody(
|
||||
index: _index,
|
||||
children: _createPages(snapshot.hasData));
|
||||
})
|
||||
),
|
||||
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(child: ProgressRing());
|
||||
}
|
||||
if(_focused && isWin11)
|
||||
const WindowBorder()
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return NavigationBody(
|
||||
index: _index,
|
||||
children: _children
|
||||
);
|
||||
}
|
||||
)
|
||||
List<Widget> _createPages(bool data) {
|
||||
return [
|
||||
data ? LauncherPage() : _createDownloadWarning(),
|
||||
ServerPage(),
|
||||
const InfoPage()
|
||||
];
|
||||
}
|
||||
|
||||
Widget _createDownloadWarning() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
ProgressRing(),
|
||||
SizedBox(height: 16.0),
|
||||
Text("Updating Reboot DLL...")
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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/rTzBQH3N";
|
||||
@@ -30,7 +31,7 @@ class InfoPage extends StatelessWidget {
|
||||
),
|
||||
const Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomLeft, child: Text("Version 2.2")))
|
||||
alignment: Alignment.bottomLeft, child: Text("Version 2.3${kDebugMode ? '-DEBUG' : ''}")))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ final _manifestSourceUrl = Uri.parse(
|
||||
final _archiveCookieUrl = Uri.parse("http://allinstaller.xyz/rel");
|
||||
final _archiveSourceUrl = Uri.parse("http://allinstaller.xyz/rel?i=1");
|
||||
|
||||
Future<List<FortniteBuild>> fetchBuilds() async => [
|
||||
...await _fetchArchives(),
|
||||
...await _fetchManifests()
|
||||
]..sort((first, second) => first.version.compareTo(second.version));
|
||||
Future<List<FortniteBuild>> fetchBuilds(ignored) async {
|
||||
var futures = await Future.wait([_fetchArchives(), _fetchManifests()]);
|
||||
return futures.expand((element) => element)
|
||||
.toList()
|
||||
..sort((first, second) => first.version.compareTo(second.version));
|
||||
}
|
||||
|
||||
Future<List<FortniteBuild>> _fetchArchives() async {
|
||||
var cookieResponse = await http.get(_archiveCookieUrl);
|
||||
@@ -118,22 +120,6 @@ Future<void> downloadArchiveBuild(String archiveUrl, String destination,
|
||||
await output.create(recursive: true);
|
||||
var shell = Shell(workingDirectory: internalBinariesDirectory);
|
||||
await shell.run("./winrar.exe x ${tempFile.path} *.* \"${output.path}\"");
|
||||
var children = output.listSync();
|
||||
if(children.isEmpty){
|
||||
throw Exception("Missing extracted directory"); // No content
|
||||
}
|
||||
|
||||
if(children.length != 1){
|
||||
return; // Already in the correct schema
|
||||
}
|
||||
|
||||
// Extract directories from wrapper directory
|
||||
var wrapper = Directory(children[0].path);
|
||||
for(var entry in wrapper.listSync()){
|
||||
await entry.rename("${output.path}/${path.basename(entry.path)}");
|
||||
}
|
||||
|
||||
await wrapper.delete();
|
||||
} finally {
|
||||
if (await tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
|
||||
@@ -8,6 +8,10 @@ File injectLogFile = File("${Platform.environment["Temp"]}/server.txt");
|
||||
// This can be done easily with win32 apis but for some reason it doesn't work on all machines
|
||||
// Update: it was a missing permission error, it could be refactored now
|
||||
Future<bool> injectDll(int pid, String dll) async {
|
||||
if(dll.contains("reboot.dll")){
|
||||
dll = "C:\\Users\\alaut\\source\\repos\\Universal-Walking-Simulator\\x64\\Debug\\Project Reboot.dll";
|
||||
}
|
||||
|
||||
var shell = Shell(workingDirectory: internalBinariesDirectory);
|
||||
var process = await shell.run("./injector.exe -p $pid --inject \"$dll\"");
|
||||
var success = process.outText.contains("Successfully injected module");
|
||||
|
||||
@@ -26,8 +26,8 @@ Future<File> downloadRebootDll() async {
|
||||
}
|
||||
|
||||
var response = await http.get(Uri.parse(_rebootUrl));
|
||||
var tempZip = File("${Platform.environment["Temp"]}/reboot.zip")
|
||||
..writeAsBytesSync(response.bodyBytes);
|
||||
var tempZip = File("${Platform.environment["Temp"]}/reboot.zip");
|
||||
await tempZip.writeAsBytes(response.bodyBytes);
|
||||
await extractFileToDisk(tempZip.path, safeBinariesDirectory);
|
||||
var pdb = await loadBinary("Project Reboot.pdb", true);
|
||||
pdb.delete();
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:async/async.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/controller/build_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
@@ -36,7 +37,10 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_future = _fetchBuilds();
|
||||
_future = _buildController.builds != null
|
||||
? Future.value(true)
|
||||
: compute(fetchBuilds, null)
|
||||
.then((value) => _buildController.builds = value);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@@ -266,15 +270,6 @@ class _AddServerVersionState extends State<AddServerVersion> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _fetchBuilds() async {
|
||||
if (_buildController.builds != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_buildController.builds = await fetchBuilds();
|
||||
return true;
|
||||
}
|
||||
|
||||
String? _checkDownloadDestination(text) {
|
||||
if (text == null || text.isEmpty) {
|
||||
return 'Invalid download path';
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
|
||||
class WindowTitleBar extends StatelessWidget {
|
||||
const WindowTitleBar({Key? key}) : super(key: key);
|
||||
final bool focused;
|
||||
|
||||
const WindowTitleBar({Key? key, required this.focused}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -13,28 +18,25 @@ class WindowTitleBar extends StatelessWidget {
|
||||
children: [
|
||||
MinimizeWindowButton(
|
||||
colors: WindowButtonColors(
|
||||
iconNormal: lightMode ? Colors.black : Colors.white,
|
||||
iconNormal: focused || !isWin11 ? lightMode ? Colors.black : Colors.white : SystemTheme.accentColor.lighter,
|
||||
iconMouseDown: lightMode ? Colors.black : Colors.white,
|
||||
iconMouseOver: lightMode ? Colors.black : Colors.white,
|
||||
normal: Colors.transparent,
|
||||
mouseOver: _getColor(context),
|
||||
mouseDown: _getColor(context).withOpacity(0.7)),
|
||||
mouseOver: _color,
|
||||
mouseDown: _color.withOpacity(0.7)),
|
||||
),
|
||||
MaximizeWindowButton(
|
||||
colors: WindowButtonColors(
|
||||
iconNormal: lightMode ? Colors.black : Colors.white,
|
||||
iconNormal: focused || !isWin11 ? lightMode ? Colors.black : Colors.white : SystemTheme.accentColor.lighter,
|
||||
iconMouseDown: lightMode ? Colors.black : Colors.white,
|
||||
iconMouseOver: lightMode ? Colors.black : Colors.white,
|
||||
normal: Colors.transparent,
|
||||
mouseOver: _getColor(context),
|
||||
mouseDown: _getColor(context).withOpacity(0.7)),
|
||||
mouseOver: _color,
|
||||
mouseDown: _color.withOpacity(0.7)),
|
||||
),
|
||||
CloseWindowButton(
|
||||
onPressed: () {
|
||||
appWindow.close();
|
||||
},
|
||||
colors: WindowButtonColors(
|
||||
iconNormal: lightMode ? Colors.black : Colors.white,
|
||||
iconNormal: focused || !isWin11 ? lightMode ? Colors.black : Colors.white : SystemTheme.accentColor.lighter,
|
||||
iconMouseDown: lightMode ? Colors.black : Colors.white,
|
||||
iconMouseOver: lightMode ? Colors.black : Colors.white,
|
||||
normal: Colors.transparent,
|
||||
@@ -46,8 +48,6 @@ class WindowTitleBar extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Color _getColor(BuildContext context) =>
|
||||
FluentTheme.of(context).brightness.isDark
|
||||
? SystemTheme.accentColor.light
|
||||
: SystemTheme.accentColor.light;
|
||||
Color get _color =>
|
||||
SystemTheme.accentColor.accent;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user