8.2
BIN
assets/images/auth.png
Normal file
|
After Width: | Height: | Size: 698 B |
BIN
assets/images/cloud.png
Normal file
|
After Width: | Height: | Size: 522 B |
BIN
assets/images/download.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/host.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/info.png
Normal file
|
After Width: | Height: | Size: 549 B |
BIN
assets/images/play.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/images/settings.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/images/user.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
45
dependencies/bitsdojo_window-0.1.5/CHANGELOG.md
vendored
@@ -1,45 +0,0 @@
|
||||
## 0.1.5
|
||||
- Runs on Windows 7
|
||||
## 0.1.4
|
||||
- Updated win32 to 3.0.0
|
||||
## 0.1.3
|
||||
- Updated ffi to 2.0.0
|
||||
## 0.1.2
|
||||
- Flutter 3.0 support
|
||||
## 0.1.1+1
|
||||
- Added Linux usage instructions
|
||||
## 0.1.1
|
||||
- Linux support now stable
|
||||
## 0.1.0+1
|
||||
- Fix gtk library name on Linux
|
||||
## 0.1.0
|
||||
- Added null safety support
|
||||
## 0.0.9
|
||||
- Linux support added
|
||||
## 0.0.8
|
||||
- Added macOS readme instructions
|
||||
## 0.0.7
|
||||
- macOS support added
|
||||
## 0.0.6
|
||||
- Works with latest Flutter version (master channel)
|
||||
## 0.0.5
|
||||
- Works with latest Flutter version (dev channel)
|
||||
## 0.0.4
|
||||
- Better integration with other plugins
|
||||
## 0.0.3
|
||||
- Using dpi-aware values for title bar and buttons dimensions
|
||||
- Dynamically calculating default button padding instead of fixed one
|
||||
## 0.0.2
|
||||
- Added video tutorial link
|
||||
## 0.0.1
|
||||
|
||||
* Initial release
|
||||
- Custom window frame - remove standard Windows titlebar and buttons
|
||||
- Hide window on startup
|
||||
- Show/hide window
|
||||
- Minimize/Maximize/Restore/Close window
|
||||
- Move window using Flutter widget
|
||||
- Set window size, minimum size and maximum size
|
||||
- Set window position
|
||||
- Set window alignment on screen (center/topLeft/topRight/bottomLeft/bottomRight)
|
||||
- Set window title
|
||||
21
dependencies/bitsdojo_window-0.1.5/LICENSE
vendored
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Bogdan Hobeanu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
262
dependencies/bitsdojo_window-0.1.5/README.md
vendored
@@ -1,262 +0,0 @@
|
||||
# bitsdojo_window
|
||||
|
||||
A [Flutter package](https://pub.dev/packages/bitsdojo_window) that makes it easy to customize and work with your Flutter desktop app window **on Windows, macOS and Linux**.
|
||||
|
||||
Watch the tutorial to get started. Click the image below to watch the video:
|
||||
|
||||
[](https://www.youtube.com/watch?v=bee2AHQpGK4 "Click to open")
|
||||
|
||||
<img src="https://raw.githubusercontent.com/bitsdojo/bitsdojo_window/master/resources/screenshot.png">
|
||||
|
||||
**Features**:
|
||||
|
||||
- Custom window frame - remove standard Windows/macOS/Linux titlebar and buttons
|
||||
- Hide window on startup
|
||||
- Show/hide window
|
||||
- Move window using Flutter widget
|
||||
- Minimize/Maximize/Restore/Close window
|
||||
- Set window size, minimum size and maximum size
|
||||
- Set window position
|
||||
- Set window alignment on screen (center/topLeft/topRight/bottomLeft/bottomRight)
|
||||
- Set window title
|
||||
|
||||
# Getting Started
|
||||
|
||||
Install the package using `pubspec.yaml`
|
||||
|
||||
# For Windows apps
|
||||
|
||||
Inside your application folder, go to `windows\runner\main.cpp` and add these two lines at the beginning of the file:
|
||||
|
||||
```cpp
|
||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||
auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
|
||||
```
|
||||
|
||||
# For macOS apps
|
||||
|
||||
Inside your application folder, go to `macos\runner\MainFlutterWindow.swift` and add this line after the one saying `import FlutterMacOS` :
|
||||
|
||||
```swift
|
||||
import FlutterMacOS
|
||||
import bitsdojo_window_macos // Add this line
|
||||
```
|
||||
|
||||
Then change this line from:
|
||||
|
||||
```swift
|
||||
class MainFlutterWindow: NSWindow {
|
||||
```
|
||||
|
||||
to this:
|
||||
|
||||
```swift
|
||||
class MainFlutterWindow: BitsdojoWindow {
|
||||
```
|
||||
|
||||
After changing `NSWindow` to `BitsdojoWindow` add these lines below the line you changed:
|
||||
|
||||
```swift
|
||||
override func bitsdojo_window_configure() -> UInt {
|
||||
return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP
|
||||
}
|
||||
```
|
||||
|
||||
Your code should now look like this:
|
||||
|
||||
```swift
|
||||
class MainFlutterWindow: BitsdojoWindow {
|
||||
|
||||
override func bitsdojo_window_configure() -> UInt {
|
||||
return BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
... //rest of your code
|
||||
```
|
||||
#
|
||||
|
||||
If you don't want to use a custom frame and prefer the standard window titlebar and buttons, you can remove the `BDW_CUSTOM_FRAME` flag from the code above.
|
||||
|
||||
If you don't want to hide the window on startup, you can remove the `BDW_HIDE_ON_STARTUP` flag from the code above.
|
||||
|
||||
# For Linux apps
|
||||
|
||||
Inside your application folder, go to `linux\my_application.cc` and add this line at the beginning of the file:
|
||||
|
||||
```cpp
|
||||
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
||||
```
|
||||
Then look for these two lines:
|
||||
|
||||
```cpp
|
||||
gtk_window_set_default_size(window, 1280, 720);
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
```
|
||||
and change them to this:
|
||||
|
||||
```cpp
|
||||
auto bdw = bitsdojo_window_from(window); // <--- add this line
|
||||
bdw->setCustomFrame(true); // <-- add this line
|
||||
//gtk_window_set_default_size(window, 1280, 720); // <-- comment this line
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
```
|
||||
|
||||
As you can see, we commented the line calling `gtk_window_set_default_size` and added these two lines before `gtk_widget_show(GTK_WIDGET(window));`
|
||||
|
||||
```cpp
|
||||
auto bdw = bitsdojo_window_from(window);
|
||||
bdw->setCustomFrame(true);
|
||||
```
|
||||
|
||||
# Flutter app integration
|
||||
|
||||
Now go to `lib\main.dart` and add this code in the `main` function right after `runApp(MyApp());` :
|
||||
|
||||
```dart
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
|
||||
// Add this code below
|
||||
|
||||
doWhenWindowReady(() {
|
||||
const initialSize = Size(600, 450);
|
||||
appWindow.minSize = initialSize;
|
||||
appWindow.size = initialSize;
|
||||
appWindow.alignment = Alignment.center;
|
||||
appWindow.show();
|
||||
});
|
||||
}
|
||||
```
|
||||
This will set an initial size and a minimum size for your application window, center it on the screen and show it on the screen.
|
||||
|
||||
You can find examples in the `example` folder.
|
||||
|
||||
Here is an example that displays this window:
|
||||
<details>
|
||||
<summary>Click to expand</summary>
|
||||
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
doWhenWindowReady(() {
|
||||
final win = appWindow;
|
||||
const initialSize = Size(600, 450);
|
||||
win.minSize = initialSize;
|
||||
win.size = initialSize;
|
||||
win.alignment = Alignment.center;
|
||||
win.title = "Custom window with Flutter";
|
||||
win.show();
|
||||
});
|
||||
}
|
||||
|
||||
const borderColor = Color(0xFF805306);
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: Scaffold(
|
||||
body: WindowBorder(
|
||||
color: borderColor,
|
||||
width: 1,
|
||||
child: Row(
|
||||
children: const [LeftSide(), RightSide()],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const sidebarColor = Color(0xFFF6A00C);
|
||||
|
||||
class LeftSide extends StatelessWidget {
|
||||
const LeftSide({Key? key}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: 200,
|
||||
child: Container(
|
||||
color: sidebarColor,
|
||||
child: Column(
|
||||
children: [
|
||||
WindowTitleBarBox(child: MoveWindow()),
|
||||
Expanded(child: Container())
|
||||
],
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
const backgroundStartColor = Color(0xFFFFD500);
|
||||
const backgroundEndColor = Color(0xFFF6A00C);
|
||||
|
||||
class RightSide extends StatelessWidget {
|
||||
const RightSide({Key? key}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [backgroundStartColor, backgroundEndColor],
|
||||
stops: [0.0, 1.0]),
|
||||
),
|
||||
child: Column(children: [
|
||||
WindowTitleBarBox(
|
||||
child: Row(
|
||||
children: [Expanded(child: MoveWindow()), const WindowButtons()],
|
||||
),
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final buttonColors = WindowButtonColors(
|
||||
iconNormal: const Color(0xFF805306),
|
||||
mouseOver: const Color(0xFFF6A00C),
|
||||
mouseDown: const Color(0xFF805306),
|
||||
iconMouseOver: const Color(0xFF805306),
|
||||
iconMouseDown: const Color(0xFFFFD500));
|
||||
|
||||
final closeButtonColors = WindowButtonColors(
|
||||
mouseOver: const Color(0xFFD32F2F),
|
||||
mouseDown: const Color(0xFFB71C1C),
|
||||
iconNormal: const Color(0xFF805306),
|
||||
iconMouseOver: Colors.white);
|
||||
|
||||
class WindowButtons extends StatelessWidget {
|
||||
const WindowButtons({Key? key}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
MinimizeWindowButton(colors: buttonColors),
|
||||
MaximizeWindowButton(colors: buttonColors),
|
||||
CloseWindowButton(colors: closeButtonColors),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
#
|
||||
# ❤️ **Sponsors - friends helping this package**
|
||||
|
||||
I am developing this package in my spare time and any help is appreciated.
|
||||
If you want to help you can [become a sponsor](https://github.com/sponsors/bitsdojo).
|
||||
|
||||
🙏 Thank you!
|
||||
|
||||
Want to help? [Become a sponsor](https://github.com/sponsors/bitsdojo)
|
||||
@@ -1,5 +0,0 @@
|
||||
export 'src/widgets/window_border.dart';
|
||||
export 'src/widgets/window_button.dart';
|
||||
export 'src/widgets/window_caption.dart';
|
||||
export 'src/icons/icons.dart';
|
||||
export 'src/app_window.dart';
|
||||
@@ -1,43 +0,0 @@
|
||||
import 'package:bitsdojo_window_platform_interface/bitsdojo_window_platform_interface.dart';
|
||||
import 'package:bitsdojo_window_platform_interface/method_channel_bitsdojo_window.dart';
|
||||
import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart';
|
||||
import 'package:bitsdojo_window_macos/bitsdojo_window_macos.dart';
|
||||
import 'package:bitsdojo_window_linux/bitsdojo_window_linux.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
bool _platformInstanceNeedsInit = true;
|
||||
|
||||
void initPlatformInstance() {
|
||||
if (!kIsWeb) {
|
||||
if (BitsdojoWindowPlatform.instance is MethodChannelBitsdojoWindow) {
|
||||
if (Platform.isWindows) {
|
||||
BitsdojoWindowPlatform.instance = BitsdojoWindowWindows();
|
||||
} else if (Platform.isMacOS) {
|
||||
BitsdojoWindowPlatform.instance = BitsdojoWindowMacOS();
|
||||
} else if (Platform.isLinux) {
|
||||
BitsdojoWindowPlatform.instance = BitsdojoWindowLinux();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BitsdojoWindowPlatform.instance = BitsdojoWindowPlatformNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
BitsdojoWindowPlatform get _platform {
|
||||
var needsInit = _platformInstanceNeedsInit;
|
||||
if (needsInit) {
|
||||
initPlatformInstance();
|
||||
_platformInstanceNeedsInit = false;
|
||||
}
|
||||
return BitsdojoWindowPlatform.instance;
|
||||
}
|
||||
|
||||
void doWhenWindowReady(VoidCallback callback) {
|
||||
_platform.doWhenWindowReady(callback);
|
||||
}
|
||||
|
||||
DesktopWindow get appWindow {
|
||||
return _platform.appWindow;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import 'package:bitsdojo_window_windows/bitsdojo_window_windows.dart'
|
||||
show WinDesktopWindow;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../app_window.dart';
|
||||
|
||||
class WindowBorder extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Color color;
|
||||
final double? width;
|
||||
|
||||
WindowBorder({Key? key, required this.child, required this.color, this.width})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isWindowsApp =
|
||||
(!kIsWeb) && (defaultTargetPlatform == TargetPlatform.windows);
|
||||
bool isLinuxApp =
|
||||
(!kIsWeb) && (defaultTargetPlatform == TargetPlatform.linux);
|
||||
|
||||
// Only show border on Windows and Linux
|
||||
if (!(isWindowsApp || isLinuxApp)) {
|
||||
return child;
|
||||
}
|
||||
|
||||
var borderWidth = width ?? 1;
|
||||
var topBorderWidth = width ?? 1;
|
||||
|
||||
if (appWindow is WinDesktopWindow) {
|
||||
appWindow as WinDesktopWindow..setWindowCutOnMaximize(borderWidth.ceil());
|
||||
}
|
||||
|
||||
if (isWindowsApp) {
|
||||
topBorderWidth += 1 / appWindow.scaleFactor;
|
||||
}
|
||||
final topBorderSide = BorderSide(color: this.color, width: topBorderWidth);
|
||||
final borderSide = BorderSide(color: this.color, width: borderWidth);
|
||||
|
||||
return Container(
|
||||
child: child,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: topBorderSide,
|
||||
left: borderSide,
|
||||
right: borderSide,
|
||||
bottom: borderSide)));
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../app_window.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
class _MoveWindow extends StatelessWidget {
|
||||
_MoveWindow({Key? key, this.child, this.onDoubleTap}) : super(key: key);
|
||||
final Widget? child;
|
||||
final VoidCallback? onDoubleTap;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPanStart: (details) {
|
||||
appWindow.startDragging();
|
||||
},
|
||||
onDoubleTap: this.onDoubleTap ?? () => appWindow.maximizeOrRestore(),
|
||||
child: this.child ?? Container());
|
||||
}
|
||||
}
|
||||
|
||||
class MoveWindow extends StatelessWidget {
|
||||
final Widget? child;
|
||||
final VoidCallback? onDoubleTap;
|
||||
MoveWindow({Key? key, this.child, this.onDoubleTap}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (child == null) return _MoveWindow(onDoubleTap: this.onDoubleTap);
|
||||
return _MoveWindow(
|
||||
onDoubleTap: this.onDoubleTap,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [Expanded(child: this.child!)]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WindowTitleBarBox extends StatelessWidget {
|
||||
final Widget? child;
|
||||
WindowTitleBarBox({Key? key, this.child}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (kIsWeb) {
|
||||
return Container();
|
||||
}
|
||||
final titlebarHeight = appWindow.titleBarHeight;
|
||||
return SizedBox(height: titlebarHeight, child: this.child ?? Container());
|
||||
}
|
||||
}
|
||||
31
dependencies/bitsdojo_window-0.1.5/pubspec.yaml
vendored
@@ -1,31 +0,0 @@
|
||||
name: bitsdojo_window
|
||||
description: A package to help with creating custom windows with Flutter desktop (custom border, titlebar and minimize/maximize/close buttons) and common desktop window operations (show/hide/position on screen) for Windows and macOS
|
||||
version: 0.1.5
|
||||
homepage: https://www.bitsdojo.com
|
||||
repository: https://github.com/bitsdojo/bitsdojo_window
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
platforms:
|
||||
windows:
|
||||
default_package: bitsdojo_window_windows
|
||||
macos:
|
||||
default_package: bitsdojo_window_macos
|
||||
linux:
|
||||
default_package: bitsdojo_window_linux
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
bitsdojo_window_platform_interface: ^0.1.2
|
||||
#path: ../bitsdojo_window_platform_interface
|
||||
bitsdojo_window_windows: ^0.1.5
|
||||
#path: ../bitsdojo_window_windows
|
||||
bitsdojo_window_macos: ^0.1.3
|
||||
#path: ../bitsdojo_window_macos
|
||||
bitsdojo_window_linux: ^0.1.3
|
||||
#path: ../bitsdojo_window_linux
|
||||
@@ -68,12 +68,11 @@ void main(List<String> args) async {
|
||||
}
|
||||
|
||||
stdout.writeln("Launching game...");
|
||||
if(version.executable == null){
|
||||
var executable = await version.executable;
|
||||
if(executable == null){
|
||||
throw Exception("Missing game executable at: ${version.location.path}");
|
||||
}
|
||||
|
||||
await patchHeadless(version.executable!);
|
||||
|
||||
var serverType = getServerType(result);
|
||||
var serverHost = result["server-host"] ?? serverJson["${serverType.id}_host"];
|
||||
var serverPort = result["server-port"] ?? serverJson["${serverType.id}_port"];
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
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';
|
||||
@@ -17,6 +14,8 @@ import 'package:reboot_launcher/src/ui/page/home_page.dart';
|
||||
import 'package:reboot_launcher/supabase.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
import 'package:flutter_acrylic/flutter_acrylic.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
const double kDefaultWindowWidth = 1024;
|
||||
const double kDefaultWindowHeight = 1024;
|
||||
@@ -42,21 +41,21 @@ void main() async {
|
||||
Get.put(BuildController());
|
||||
Get.put(SettingsController());
|
||||
Get.put(HostingController());
|
||||
doWhenWindowReady(() {
|
||||
var controller = Get.find<SettingsController>();
|
||||
var size = Size(controller.width, controller.height);
|
||||
var window = appWindow as WinDesktopWindow;
|
||||
window.setWindowCutOnMaximize(appBarSize * 2);
|
||||
appWindow.size = size;
|
||||
if(controller.offsetX != null && controller.offsetY != null){
|
||||
appWindow.position = Offset(controller.offsetX!, controller.offsetY!);
|
||||
}else {
|
||||
appWindow.alignment = Alignment.center;
|
||||
}
|
||||
|
||||
appWindow.title = "Reboot Launcher";
|
||||
appWindow.show();
|
||||
});
|
||||
await windowManager.ensureInitialized();
|
||||
var controller = Get.find<SettingsController>();
|
||||
var size = Size(controller.width, controller.height);
|
||||
await windowManager.setSize(size);
|
||||
if(controller.offsetX != null && controller.offsetY != null){
|
||||
await windowManager.setPosition(Offset(controller.offsetX!, controller.offsetY!));
|
||||
}else {
|
||||
await windowManager.setAlignment(Alignment.center);
|
||||
};
|
||||
await Window.initialize();
|
||||
await Window.setEffect(
|
||||
effect: WindowEffect.acrylic,
|
||||
color: Colors.transparent,
|
||||
dark: SystemTheme.isDarkMode
|
||||
);
|
||||
var supabase = Supabase.instance.client;
|
||||
await supabase.from('hosts')
|
||||
.delete()
|
||||
@@ -91,6 +90,7 @@ class _RebootApplicationState extends State<RebootApplication> {
|
||||
FluentThemeData _createTheme(Brightness brightness) => FluentThemeData(
|
||||
brightness: brightness,
|
||||
accentColor: SystemTheme.accentColor.accent.toAccentColor(),
|
||||
visualDensity: VisualDensity.standard
|
||||
visualDensity: VisualDensity.standard,
|
||||
scaffoldBackgroundColor: Colors.transparent
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:win32/win32.dart';
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
|
||||
import '../model/fortnite_version.dart';
|
||||
import '../model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
|
||||
Iterable<String> getServerTypes() => ServerType.values.map((entry) => entry.id);
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@ import 'dart:io';
|
||||
|
||||
import 'package:process_run/shell.dart';
|
||||
import 'package:reboot_launcher/cli.dart';
|
||||
|
||||
import '../model/fortnite_version.dart';
|
||||
import '../util/injector.dart';
|
||||
import '../util/os.dart';
|
||||
import '../util/process.dart';
|
||||
import '../util/server.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/util/injector.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/process.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
|
||||
final List<String> _errorStrings = [
|
||||
"port 3551 failed: Connection refused",
|
||||
@@ -25,10 +24,9 @@ Future<void> startGame() async {
|
||||
await _startLauncherProcess(version);
|
||||
await _startEacProcess(version);
|
||||
|
||||
var gamePath = version.executable?.path;
|
||||
if (gamePath == null) {
|
||||
throw Exception("${version.location
|
||||
.path} no longer contains a Fortnite executable, did you delete or move it?");
|
||||
var executable = await version.executable;
|
||||
if (executable == null) {
|
||||
throw Exception("${version.location.path} no longer contains a Fortnite executable, did you delete or move it?");
|
||||
}
|
||||
|
||||
if (username == null) {
|
||||
@@ -36,7 +34,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(executable.path, createRebootArgs(username!, "", host, ""))
|
||||
..exitCode.then((_) => _onClose())
|
||||
..outLines.forEach((line) => _onGameOutput(line, dll, host, verbose));
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
|
||||
import '../util/os.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
|
||||
const String _baseDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968021373169674/cobalt.dll";
|
||||
const String _consoleDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968095033524234/console.dll";
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:process_run/shell.dart';
|
||||
|
||||
import '../model/server_type.dart';
|
||||
import '../util/server.dart' as server;
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart' as server;
|
||||
|
||||
Future<bool> startServer(String? host, String? port, ServerType type) async {
|
||||
stdout.writeln("Starting backend server...");
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:reboot_launcher/src/util/patcher.dart';
|
||||
|
||||
class FortniteVersion {
|
||||
String name;
|
||||
@@ -22,8 +24,22 @@ class FortniteVersion {
|
||||
}
|
||||
}
|
||||
|
||||
File? get executable {
|
||||
return findExecutable(location, "FortniteClient-Win64-Shipping.exe");
|
||||
Future<File?> get executable async {
|
||||
var result = findExecutable(location, "FortniteClient-Win64-Shipping-Reboot.exe");
|
||||
if(result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
var original = findExecutable(location, "FortniteClient-Win64-Shipping.exe");
|
||||
if(original == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
await Future.wait([
|
||||
compute(patchMatchmaking, original),
|
||||
compute(patchHeadless, original)
|
||||
]);
|
||||
return original;
|
||||
}
|
||||
|
||||
File? get launcher {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
@@ -9,7 +8,6 @@ import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/model/game_instance.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../../model/update_status.dart';
|
||||
|
||||
const String kDefaultPlayerName = "Player";
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/update_controller.dart';
|
||||
|
||||
import '../../model/game_instance.dart';
|
||||
import '../../model/update_status.dart';
|
||||
import '../../util/reboot.dart';
|
||||
import 'package:reboot_launcher/src/model/game_instance.dart';
|
||||
import 'package:reboot_launcher/src/model/update_status.dart';
|
||||
import 'package:reboot_launcher/src/util/reboot.dart';
|
||||
|
||||
|
||||
const String kDefaultServerName = "Reboot Game Server";
|
||||
|
||||
@@ -4,8 +4,8 @@ import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
|
||||
import '../../model/server_type.dart';
|
||||
import '../../util/server.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
|
||||
class ServerController extends GetxController {
|
||||
static const String _kDefaultServerHost = "127.0.0.1";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -5,9 +6,8 @@ import 'package:get_storage/get_storage.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'dart:ui';
|
||||
|
||||
import '../../util/reboot.dart';
|
||||
import 'package:reboot_launcher/src/util/reboot.dart';
|
||||
|
||||
class SettingsController extends GetxController {
|
||||
static const String _kDefaultIp = "127.0.0.1";
|
||||
@@ -49,9 +49,9 @@ class SettingsController extends GetxController {
|
||||
autoUpdate = RxBool(_storage.read("auto_update") ?? _kDefaultAutoUpdate);
|
||||
autoUpdate.listen((value) => _storage.write("auto_update", value));
|
||||
scrollingDistance = 0.0;
|
||||
firstRun = RxBool(_storage.read("fr") ?? true);
|
||||
firstRun.listen((value) => _storage.write("fr", value));
|
||||
index = RxInt(firstRun() ? 0 : 1);
|
||||
firstRun = RxBool(_storage.read("first_run") ?? true);
|
||||
firstRun.listen((value) => _storage.write("first_run", value));
|
||||
index = RxInt(firstRun() ? 3 : 0);
|
||||
}
|
||||
|
||||
TextEditingController _createController(String key, String name) {
|
||||
|
||||
@@ -6,9 +6,8 @@ import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_name_input.dart';
|
||||
|
||||
import '../../util/checks.dart';
|
||||
import '../widget/shared/file_selector.dart';
|
||||
import '../widget/shared/smart_check_box.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart';
|
||||
import 'dialog.dart';
|
||||
import 'dialog_button.dart';
|
||||
|
||||
|
||||
@@ -6,17 +6,16 @@ import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/util/error.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/build.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/util/build.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:universal_disk_space/universal_disk_space.dart';
|
||||
|
||||
import '../../util/checks.dart';
|
||||
import '../controller/build_controller.dart';
|
||||
import '../widget/home/build_selector.dart';
|
||||
import '../widget/home/version_name_input.dart';
|
||||
import '../widget/shared/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/build_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/build_selector.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_name_input.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart';
|
||||
import 'dialog.dart';
|
||||
import 'dialog_button.dart';
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:clipboard/clipboard.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
|
||||
import 'dialog_button.dart';
|
||||
@@ -24,10 +22,6 @@ class GenericDialog extends AbstractDialog {
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
MoveWindow(
|
||||
child: const SizedBox.expand(),
|
||||
),
|
||||
|
||||
ContentDialog(
|
||||
style: ContentDialogThemeData(
|
||||
padding: padding ?? const EdgeInsets.only(left: 20, right: 20, top: 15.0, bottom: 5.0)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'dialog.dart';
|
||||
|
||||
const String _unsupportedServerError = "The build you are currently using is not supported by Reboot. "
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
import 'package:sync/semaphore.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../../util/server.dart';
|
||||
import '../controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/server_controller.dart';
|
||||
import 'dialog.dart';
|
||||
import 'dialog_button.dart';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
|
||||
void showMessage(String text){
|
||||
showSnackbar(
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart' hide WindowBorder;
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/ui/page/launcher_page.dart';
|
||||
import 'package:reboot_launcher/src/ui/page/server_page.dart';
|
||||
import 'package:reboot_launcher/src/ui/page/settings_page.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/profile_widget.dart';
|
||||
|
||||
import '../controller/game_controller.dart';
|
||||
import '../controller/settings_controller.dart';
|
||||
import '../widget/os/window_border.dart';
|
||||
import '../widget/os/window_buttons.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/os/window_border.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/os/window_title_bar.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'hosting_page.dart';
|
||||
import 'info_page.dart';
|
||||
|
||||
@@ -25,8 +23,8 @@ class HomePage extends StatefulWidget {
|
||||
|
||||
class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepAliveClientMixin {
|
||||
static const double _kDefaultPadding = 12.0;
|
||||
static const int _kPagesLength = 5;
|
||||
|
||||
static const int _kPagesLength = 6;
|
||||
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
final GlobalKey _searchKey = GlobalKey();
|
||||
final FocusNode _searchFocusNode = FocusNode();
|
||||
@@ -41,6 +39,7 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
windowManager.show();
|
||||
windowManager.addListener(this);
|
||||
_searchController.addListener(_onSearch);
|
||||
super.initState();
|
||||
@@ -52,7 +51,8 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
return;
|
||||
}
|
||||
|
||||
_searchItems.value = _allItems.whereType<PaneItem>()
|
||||
_searchItems.value = _allItems
|
||||
.whereType<PaneItem>()
|
||||
.where((item) => (item.title as Text).data!.toLowerCase().contains(searchValue.toLowerCase()))
|
||||
.toList()
|
||||
.cast<NavigationPaneItem>();
|
||||
@@ -84,73 +84,88 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
|
||||
@override
|
||||
void onWindowMoved() {
|
||||
_settingsController.saveWindowOffset(appWindow.position);
|
||||
windowManager.getPosition()
|
||||
.then((value) => _settingsController.saveWindowOffset(value));
|
||||
super.onWindowMoved();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return Stack(
|
||||
children: [
|
||||
LayoutBuilder(
|
||||
builder: (context, specs) => Obx(() => NavigationView(
|
||||
paneBodyBuilder: (pane, body) => Padding(
|
||||
padding: const EdgeInsets.all(_kDefaultPadding),
|
||||
child: body
|
||||
return Stack(children: [
|
||||
LayoutBuilder(
|
||||
builder: (context, specs) => Obx(() => NavigationPaneTheme(
|
||||
data: NavigationPaneThemeData(
|
||||
backgroundColor: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.9),
|
||||
),
|
||||
appBar: NavigationAppBar(
|
||||
title: _draggableArea,
|
||||
actions: WindowTitleBar(focused: _focused()),
|
||||
automaticallyImplyLeading: false,
|
||||
leading: _backButton
|
||||
),
|
||||
pane: NavigationPane(
|
||||
key: appKey,
|
||||
selected: _selectedIndex,
|
||||
onChanged: _onIndexChanged,
|
||||
displayMode: specs.biggest.width <= 1536 ? PaneDisplayMode.compact : PaneDisplayMode.open,
|
||||
items: _items,
|
||||
footerItems: _footerItems,
|
||||
autoSuggestBox: _autoSuggestBox,
|
||||
autoSuggestBoxReplacement: const Icon(FluentIcons.search),
|
||||
),
|
||||
onOpenSearch: () => _searchFocusNode.requestFocus(),
|
||||
transitionBuilder: (child, animation) => child
|
||||
))
|
||||
),
|
||||
if(isWin11)
|
||||
Obx(() => _focused.value ? const WindowBorder() : const SizedBox())
|
||||
]
|
||||
);
|
||||
child: NavigationView(
|
||||
paneBodyBuilder: (pane, body) => Padding(
|
||||
padding: const EdgeInsets.all(_kDefaultPadding),
|
||||
child: body
|
||||
),
|
||||
appBar: NavigationAppBar(
|
||||
height: 32,
|
||||
title: _draggableArea,
|
||||
actions: WindowTitleBar(focused: _focused()),
|
||||
automaticallyImplyLeading: false,
|
||||
leading: _backButton
|
||||
),
|
||||
pane: NavigationPane(
|
||||
key: appKey,
|
||||
selected: _selectedIndex,
|
||||
onChanged: _onIndexChanged,
|
||||
menuButton: const SizedBox(),
|
||||
displayMode: PaneDisplayMode.open,
|
||||
items: _items,
|
||||
header: ProfileWidget(),
|
||||
footerItems: _footerItems,
|
||||
autoSuggestBox: _autoSuggestBox,
|
||||
autoSuggestBoxReplacement: const Icon(FluentIcons.search),
|
||||
),
|
||||
contentShape: const RoundedRectangleBorder(),
|
||||
onOpenSearch: () => _searchFocusNode.requestFocus(),
|
||||
transitionBuilder: (child, animation) => child),
|
||||
)
|
||||
)
|
||||
),
|
||||
if (isWin11)
|
||||
Obx(() => _focused.value ? const WindowBorder() : const SizedBox())
|
||||
]);
|
||||
}
|
||||
|
||||
GestureDetector get _draggableArea => GestureDetector(
|
||||
onDoubleTap: () async => await windowManager.isMaximized() ? await windowManager.restore() : await windowManager.maximize(),
|
||||
onHorizontalDragStart: (event) => windowManager.startDragging(),
|
||||
onVerticalDragStart: (event) => windowManager.startDragging()
|
||||
);
|
||||
|
||||
Widget get _backButton => Obx(() {
|
||||
for(var entry in _navigationStatus){
|
||||
for (var entry in _navigationStatus) {
|
||||
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,
|
||||
displayMode: PaneDisplayMode.compact
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Button(
|
||||
onPressed: onBack,
|
||||
style: ButtonStyle(
|
||||
backgroundColor: ButtonState.all(Colors.transparent),
|
||||
border: ButtonState.all(BorderSide(color: Colors.transparent))
|
||||
),
|
||||
child: const Icon(FluentIcons.back, size: 13.0)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Function()? _onBack() {
|
||||
var navigator = _navigators[_settingsController.index.value].currentState;
|
||||
if(navigator == null || !navigator.mounted || !navigator.canPop()){
|
||||
if (navigator == null || !navigator.mounted || !navigator.canPop()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var status = _navigationStatus[_settingsController.index.value];
|
||||
if(status.value <= 0){
|
||||
if (status.value <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -165,17 +180,15 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
_settingsController.index.value = index;
|
||||
}
|
||||
|
||||
TextBox get _autoSuggestBox => TextBox(
|
||||
key: _searchKey,
|
||||
controller: _searchController,
|
||||
placeholder: 'Search',
|
||||
focusNode: _searchFocusNode
|
||||
);
|
||||
|
||||
GestureDetector get _draggableArea => GestureDetector(
|
||||
onDoubleTap: () => appWindow.maximizeOrRestore(),
|
||||
onHorizontalDragStart: (event) => appWindow.startDragging(),
|
||||
onVerticalDragStart: (event) => appWindow.startDragging()
|
||||
Widget get _autoSuggestBox => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: TextBox(
|
||||
key: _searchKey,
|
||||
controller: _searchController,
|
||||
placeholder: 'Find a setting',
|
||||
focusNode: _searchFocusNode,
|
||||
autofocus: true
|
||||
),
|
||||
);
|
||||
|
||||
int? get _selectedIndex {
|
||||
@@ -184,11 +197,12 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
return _settingsController.index();
|
||||
}
|
||||
|
||||
if(_settingsController.index() >= _allItems.length){
|
||||
if (_settingsController.index() >= _allItems.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var indexOnScreen = searchItems.indexOf(_allItems[_settingsController.index()]);
|
||||
var indexOnScreen =
|
||||
searchItems.indexOf(_allItems[_settingsController.index()]);
|
||||
if (indexOnScreen.isNegative) {
|
||||
return null;
|
||||
}
|
||||
@@ -199,36 +213,75 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
|
||||
List<NavigationPaneItem> get _allItems => [..._items, ..._footerItems];
|
||||
|
||||
List<NavigationPaneItem> get _footerItems => searchValue.isNotEmpty ? [] : [
|
||||
PaneItem(
|
||||
title: const Text("Settings"),
|
||||
icon: const Icon(FluentIcons.settings),
|
||||
body: SettingsPage()
|
||||
)
|
||||
PaneItem(
|
||||
title: const Text("Downloads"),
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset("assets/images/download.png")
|
||||
)
|
||||
),
|
||||
body: const SettingsPage()
|
||||
),
|
||||
PaneItem(
|
||||
title: const Text("Settings"),
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset("assets/images/settings.png")
|
||||
)
|
||||
),
|
||||
body: const SettingsPage()
|
||||
)
|
||||
];
|
||||
|
||||
List<NavigationPaneItem> get _items => _searchItems() ?? [
|
||||
PaneItem(
|
||||
title: const Text("Tutorial"),
|
||||
icon: const Icon(FluentIcons.info),
|
||||
body: InfoPage(_navigators[0], _navigationStatus[0])
|
||||
),
|
||||
PaneItem(
|
||||
title: const Text("Play"),
|
||||
icon: const Icon(FluentIcons.game),
|
||||
body: LauncherPage(_navigators[1], _navigationStatus[1])
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset("assets/images/play.png")
|
||||
)
|
||||
),
|
||||
body: LauncherPage(_navigators[0], _navigationStatus[0])
|
||||
),
|
||||
|
||||
PaneItem(
|
||||
title: const Text("Host"),
|
||||
icon: const Icon(FluentIcons.server_processes),
|
||||
body: HostingPage(_navigators[2], _navigationStatus[2])
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset("assets/images/host.png")
|
||||
)
|
||||
),
|
||||
body: HostingPage(_navigators[1], _navigationStatus[1])
|
||||
),
|
||||
|
||||
PaneItem(
|
||||
title: const Text("Backend"),
|
||||
icon: const Icon(FluentIcons.user_window),
|
||||
body: ServerPage(_navigators[3], _navigationStatus[3])
|
||||
title: const Text("Authenticator"),
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset("assets/images/cloud.png")
|
||||
)
|
||||
),
|
||||
body: ServerPage(_navigators[2], _navigationStatus[2])
|
||||
),
|
||||
PaneItem(
|
||||
title: const Text("Tutorial"),
|
||||
icon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: SizedBox.square(
|
||||
dimension: 24,
|
||||
child: Image.asset("assets/images/info.png")
|
||||
)
|
||||
),
|
||||
body: InfoPage(_navigators[3], _navigationStatus[3])
|
||||
)
|
||||
];
|
||||
|
||||
String get searchValue => _searchController.text;
|
||||
|
||||
@@ -3,10 +3,10 @@ import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
|
||||
|
||||
import '../../model/update_status.dart';
|
||||
import 'package:reboot_launcher/src/model/update_status.dart';
|
||||
import 'browse_page.dart';
|
||||
|
||||
class HostingPage extends StatefulWidget {
|
||||
@@ -38,7 +38,7 @@ class _HostingPageState extends State<HostingPage> with AutomaticKeepAliveClient
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ProgressRing(),
|
||||
SizedBox(height: 16.0),
|
||||
SizedBox(height: 8.0),
|
||||
Text("Updating Reboot DLL...")
|
||||
],
|
||||
),
|
||||
@@ -97,7 +97,7 @@ class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin
|
||||
child: _hostingController.updateStatus.value == UpdateStatus.error ? _updateError : _rebootGuiInfo,
|
||||
)),
|
||||
const SizedBox(
|
||||
height: 16.0
|
||||
height: 8.0
|
||||
),
|
||||
SettingTile(
|
||||
title: "Game Server",
|
||||
@@ -135,7 +135,7 @@ class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Version",
|
||||
@@ -163,7 +163,7 @@ class _HostPageState extends State<_HostPage> with AutomaticKeepAliveClientMixin
|
||||
]
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Browse available servers",
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
|
||||
import '../../util/os.dart';
|
||||
import '../controller/game_controller.dart';
|
||||
import '../controller/settings_controller.dart';
|
||||
import '../dialog/dialog.dart';
|
||||
import '../dialog/dialog_button.dart';
|
||||
import '../widget/home/version_selector.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
|
||||
|
||||
class InfoPage extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
@@ -219,7 +215,7 @@ class _PlayPageState extends State<_PlayPage> {
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: '2. Download Fortnite',
|
||||
@@ -255,7 +251,7 @@ class _PlayPageState extends State<_PlayPage> {
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: _remoteGameServerStream.stream,
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/material.dart' show Icons;
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
import 'package:reboot_launcher/src/ui/page/browse_page.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/ui/page/play_page.dart';
|
||||
|
||||
import '../../util/checks.dart';
|
||||
import '../../util/os.dart';
|
||||
|
||||
class LauncherPage extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
@@ -48,185 +36,11 @@ class _LauncherPageState extends State<LauncherPage> with AutomaticKeepAliveClie
|
||||
Widget _createScreen(String? name) {
|
||||
switch(name){
|
||||
case "home":
|
||||
return _GamePage(widget.navigatorKey, widget.nestedNavigation);
|
||||
return PlayPage(widget.navigatorKey, widget.nestedNavigation);
|
||||
case "browse":
|
||||
return const BrowsePage();
|
||||
default:
|
||||
throw Exception("Unknown page: $name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _GamePage extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
final RxInt nestedNavigation;
|
||||
const _GamePage(this.navigatorKey, this.nestedNavigation, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<_GamePage> createState() => _GamePageState();
|
||||
}
|
||||
|
||||
class _GamePageState extends State<_GamePage> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
late final RxBool _showPasswordTrailing = RxBool(_gameController.password.text.isNotEmpty);
|
||||
final StreamController _matchmakingStream = StreamController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_gameController.password.addListener(() => _matchmakingStream.add(null));
|
||||
_settingsController.matchmakingIp.addListener(() => _matchmakingStream.add(null));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
children: [
|
||||
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,
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: _matchmakingStream.stream,
|
||||
builder: (context, value) =>
|
||||
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: "Automatically start game server",
|
||||
subtitle: "This option is available when the matchmaker is set to localhost",
|
||||
contentWidth: null,
|
||||
content: !isLocalHost(_settingsController.matchmakingIp.text) || _gameController.password.text.isNotEmpty ? _disabledAutoGameServerSwitch : _autoGameServerSwitch,
|
||||
isChild: true
|
||||
),
|
||||
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 += 1;
|
||||
},
|
||||
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 LaunchButton(
|
||||
host: false
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _disabledAutoGameServerSwitch => Container(
|
||||
foregroundDecoration: const BoxDecoration(
|
||||
color: Colors.grey,
|
||||
backgroundBlendMode: BlendMode.saturation,
|
||||
),
|
||||
child: _autoGameServerSwitch,
|
||||
);
|
||||
|
||||
Widget get _autoGameServerSwitch => Obx(() => ToggleSwitch(
|
||||
checked: _gameController.autoStartGameServer() && isLocalHost(_settingsController.matchmakingIp.text) && _gameController.password.text.isEmpty,
|
||||
onChanged: (value) {
|
||||
if(!isLocalHost(_settingsController.matchmakingIp.text)){
|
||||
showMessage("This option isn't available when the matchmaker isn't set to 127.0.0.1");
|
||||
return;
|
||||
}
|
||||
|
||||
if(_gameController.password.text.isNotEmpty){
|
||||
showMessage("This option isn't available when the password isn't empty(LawinV2)");
|
||||
return;
|
||||
}
|
||||
|
||||
_gameController.autoStartGameServer.value = value;
|
||||
}
|
||||
));
|
||||
}
|
||||
154
lib/src/ui/page/play_page.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/launch_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/version_selector.dart';
|
||||
|
||||
class PlayPage extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
final RxInt nestedNavigation;
|
||||
const PlayPage(this.navigatorKey, this.nestedNavigation, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<PlayPage> createState() => _PlayPageState();
|
||||
}
|
||||
|
||||
class _PlayPageState extends State<PlayPage> {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||
final StreamController _matchmakingStream = StreamController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_gameController.password.addListener(() => _matchmakingStream.add(null));
|
||||
_settingsController.matchmakingIp.addListener(() =>
|
||||
_matchmakingStream.add(null));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
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,
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: _matchmakingStream.stream,
|
||||
builder: (context, value) =>
|
||||
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: "Automatically start game server",
|
||||
subtitle: "This option is available when the matchmaker is set to localhost",
|
||||
contentWidth: null,
|
||||
content: !isLocalHost(
|
||||
_settingsController.matchmakingIp.text) ||
|
||||
_gameController.password.text.isNotEmpty
|
||||
? _disabledAutoGameServerSwitch
|
||||
: _autoGameServerSwitch,
|
||||
isChild: true
|
||||
),
|
||||
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 += 1;
|
||||
},
|
||||
child: const Text("Browse")
|
||||
),
|
||||
isChild: true
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8.0,
|
||||
),
|
||||
const LaunchButton(
|
||||
host: false
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _disabledAutoGameServerSwitch => Container(
|
||||
foregroundDecoration: const BoxDecoration(
|
||||
color: Colors.grey,
|
||||
backgroundBlendMode: BlendMode.saturation,
|
||||
),
|
||||
child: _autoGameServerSwitch,
|
||||
);
|
||||
|
||||
Widget get _autoGameServerSwitch => Obx(() => ToggleSwitch(
|
||||
checked: _gameController.autoStartGameServer() &&
|
||||
isLocalHost(_settingsController.matchmakingIp.text) &&
|
||||
_gameController.password.text.isEmpty,
|
||||
onChanged: (value) {
|
||||
if (!isLocalHost(_settingsController.matchmakingIp.text)) {
|
||||
showMessage(
|
||||
"This option isn't available when the matchmaker isn't set to 127.0.0.1");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_gameController.password.text.isNotEmpty) {
|
||||
showMessage(
|
||||
"This option isn't available when the password isn't empty(LawinV2)");
|
||||
return;
|
||||
}
|
||||
|
||||
_gameController.autoStartGameServer.value = value;
|
||||
}
|
||||
));
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/server/server_type_selector.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/server/server_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/server/server_type_selector.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../dialog/dialog.dart';
|
||||
import '../dialog/dialog_button.dart';
|
||||
import '../widget/home/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
|
||||
class ServerPage extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
@@ -43,7 +43,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Host",
|
||||
@@ -55,7 +55,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
||||
)
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Port",
|
||||
@@ -67,7 +67,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
||||
)
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Type",
|
||||
@@ -75,7 +75,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
||||
content: ServerTypeSelector()
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Detached",
|
||||
@@ -87,7 +87,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
||||
))
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Server files",
|
||||
@@ -98,7 +98,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
||||
)
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Reset Backend",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
@@ -7,12 +6,10 @@ import 'package:reboot_launcher/src/ui/dialog/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
|
||||
import '../../util/checks.dart';
|
||||
import '../../util/os.dart';
|
||||
import '../../util/selector.dart';
|
||||
import '../dialog/dialog.dart';
|
||||
import '../widget/home/setting_tile.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/home/setting_tile.dart';
|
||||
|
||||
class SettingsPage extends StatefulWidget {
|
||||
const SettingsPage({Key? key}) : super(key: key);
|
||||
@@ -56,7 +53,7 @@ class _SettingsPageState extends State<SettingsPage> with AutomaticKeepAliveClie
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Automatic updates",
|
||||
@@ -82,7 +79,7 @@ class _SettingsPageState extends State<SettingsPage> with AutomaticKeepAliveClie
|
||||
]
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Custom launch arguments",
|
||||
@@ -93,7 +90,7 @@ class _SettingsPageState extends State<SettingsPage> with AutomaticKeepAliveClie
|
||||
)
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Create a bug report",
|
||||
@@ -104,7 +101,7 @@ class _SettingsPageState extends State<SettingsPage> with AutomaticKeepAliveClie
|
||||
)
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Reset settings",
|
||||
@@ -134,7 +131,7 @@ class _SettingsPageState extends State<SettingsPage> with AutomaticKeepAliveClie
|
||||
)
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16.0,
|
||||
height: 8.0,
|
||||
),
|
||||
SettingTile(
|
||||
title: "Version status",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/build_controller.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_build.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/build_controller.dart';
|
||||
|
||||
class BuildSelector extends StatefulWidget {
|
||||
final Function() onSelected;
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:process_run/shell.dart';
|
||||
import 'package:reboot_launcher/src/../main.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/model/game_instance.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/hosting_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/game_dialogs.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/server_dialogs.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/injector.dart';
|
||||
import 'package:reboot_launcher/src/util/patcher.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'package:reboot_launcher/src/../main.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/settings_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
import 'package:reboot_launcher/src/model/game_instance.dart';
|
||||
import 'package:reboot_launcher/src/util/injector.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import '../../../util/process.dart';
|
||||
import 'package:reboot_launcher/src/util/process.dart';
|
||||
|
||||
class LaunchButton extends StatefulWidget {
|
||||
final bool host;
|
||||
@@ -124,7 +121,8 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
|
||||
try {
|
||||
var version = _gameController.selectedVersion!;
|
||||
if(version.executable?.path == null){
|
||||
var executable = await version.executable;
|
||||
if(executable == null){
|
||||
showMissingBuildError(version);
|
||||
_onStop(widget.host);
|
||||
return;
|
||||
@@ -136,9 +134,6 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
return;
|
||||
}
|
||||
|
||||
await compute(patchHeadless, version.executable!);
|
||||
// Is this needed? await compute(patchMatchmaking, version.executable!);
|
||||
|
||||
var automaticallyStartedServer = await _startMatchMakingServer();
|
||||
await _startGameProcesses(version, widget.host, automaticallyStartedServer);
|
||||
|
||||
@@ -156,7 +151,14 @@ class _LaunchButtonState extends State<LaunchButton> {
|
||||
_setStarted(host, true);
|
||||
var launcherProcess = await _createLauncherProcess(version);
|
||||
var eacProcess = await _createEacProcess(version);
|
||||
var gameProcess = await _createGameProcess(version.executable!.path, host);
|
||||
var executable = await version.executable;
|
||||
if(executable == null){
|
||||
showMissingBuildError(version);
|
||||
_onStop(widget.host);
|
||||
return;
|
||||
}
|
||||
|
||||
var gameProcess = await _createGameProcess(executable.path, host);
|
||||
var watchDogProcess = _createWatchdogProcess(gameProcess, launcherProcess, eacProcess);
|
||||
var instance = GameInstance(gameProcess, launcherProcess, eacProcess, watchDogProcess, hasChildServer);
|
||||
if(host){
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/fluent_card.dart';
|
||||
|
||||
class SettingTile extends StatefulWidget {
|
||||
static const double kDefaultContentWidth = 200.0;
|
||||
@@ -42,19 +41,17 @@ class _SettingTileState extends State<SettingTile> {
|
||||
return _contentCard;
|
||||
}
|
||||
|
||||
return Mica(
|
||||
elevation: 1,
|
||||
child: Expander(
|
||||
initiallyExpanded: true,
|
||||
contentBackgroundColor: FluentTheme.of(context).menuColor,
|
||||
headerShape: (open) => const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
),
|
||||
header: _header,
|
||||
headerHeight: widget.expandedContentHeaderHeight,
|
||||
trailing: _trailing,
|
||||
content: _content
|
||||
),
|
||||
return Expander(
|
||||
initiallyExpanded: true,
|
||||
headerShape: (open) => const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
),
|
||||
header: SizedBox(
|
||||
height: widget.expandedContentHeaderHeight,
|
||||
child: _header
|
||||
),
|
||||
trailing: _trailing,
|
||||
content: _content
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,8 +87,9 @@ class _SettingTileState extends State<SettingTile> {
|
||||
);
|
||||
}
|
||||
|
||||
return FluentCard(
|
||||
child: _contentCardBody,
|
||||
return Card(
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
child: _contentCardBody
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,18 @@ import 'dart:io';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/add_local_version.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/add_server_version.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog_button.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/add_local_version.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/smart_check_box.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'package:reboot_launcher/src/ui/dialog/add_server_version.dart';
|
||||
import 'package:reboot_launcher/src/util/checks.dart';
|
||||
import '../shared/file_selector.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/shared/file_selector.dart';
|
||||
|
||||
class VersionSelector extends StatefulWidget {
|
||||
const VersionSelector({Key? key}) : super(key: key);
|
||||
|
||||
@@ -7,7 +7,9 @@ import 'package:flutter/widgets.dart';
|
||||
/// Close
|
||||
class CloseIcon extends StatelessWidget {
|
||||
final Color color;
|
||||
CloseIcon({Key? key, required this.color}) : super(key: key);
|
||||
|
||||
const CloseIcon({Key? key, required this.color}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Align(
|
||||
alignment: Alignment.topLeft,
|
||||
@@ -28,13 +30,16 @@ class CloseIcon extends StatelessWidget {
|
||||
/// Maximize
|
||||
class MaximizeIcon extends StatelessWidget {
|
||||
final Color color;
|
||||
MaximizeIcon({Key? key, required this.color}) : super(key: key);
|
||||
|
||||
const MaximizeIcon({Key? key, required this.color}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _AlignedPaint(_MaximizePainter(color));
|
||||
}
|
||||
|
||||
class _MaximizePainter extends _IconPainter {
|
||||
_MaximizePainter(Color color) : super(color);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
Paint p = getPaint(color);
|
||||
@@ -45,22 +50,25 @@ class _MaximizePainter extends _IconPainter {
|
||||
/// Restore
|
||||
class RestoreIcon extends StatelessWidget {
|
||||
final Color color;
|
||||
RestoreIcon({
|
||||
|
||||
const RestoreIcon({
|
||||
Key? key,
|
||||
required this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _AlignedPaint(_RestorePainter(color));
|
||||
}
|
||||
|
||||
class _RestorePainter extends _IconPainter {
|
||||
_RestorePainter(Color color) : super(color);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
Paint p = getPaint(color);
|
||||
canvas.drawRect(Rect.fromLTRB(0, 2, size.width - 2, size.height), p);
|
||||
canvas.drawLine(Offset(2, 2), Offset(2, 0), p);
|
||||
canvas.drawLine(Offset(2, 0), Offset(size.width, 0), p);
|
||||
canvas.drawLine(const Offset(2, 2), const Offset(2, 0), p);
|
||||
canvas.drawLine(const Offset(2, 0), Offset(size.width, 0), p);
|
||||
canvas.drawLine(
|
||||
Offset(size.width, 0), Offset(size.width, size.height - 2), p);
|
||||
canvas.drawLine(Offset(size.width, size.height - 2),
|
||||
@@ -71,13 +79,16 @@ class _RestorePainter extends _IconPainter {
|
||||
/// Minimize
|
||||
class MinimizeIcon extends StatelessWidget {
|
||||
final Color color;
|
||||
MinimizeIcon({Key? key, required this.color}) : super(key: key);
|
||||
|
||||
const MinimizeIcon({Key? key, required this.color}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _AlignedPaint(_MinimizePainter(color));
|
||||
}
|
||||
|
||||
class _MinimizePainter extends _IconPainter {
|
||||
_MinimizePainter(Color color) : super(color);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
Paint p = getPaint(color);
|
||||
@@ -89,6 +100,7 @@ class _MinimizePainter extends _IconPainter {
|
||||
/// Helpers
|
||||
abstract class _IconPainter extends CustomPainter {
|
||||
_IconPainter(this.color);
|
||||
|
||||
final Color color;
|
||||
|
||||
@override
|
||||
@@ -103,7 +115,7 @@ class _AlignedPaint extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.center,
|
||||
child: CustomPaint(size: Size(10, 10), painter: painter));
|
||||
child: CustomPaint(size: const Size(10, 10), painter: painter));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,26 +6,29 @@ typedef MouseStateBuilderCB = Widget Function(
|
||||
class MouseState {
|
||||
bool isMouseOver = false;
|
||||
bool isMouseDown = false;
|
||||
|
||||
MouseState();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "isMouseDown: ${this.isMouseDown} - isMouseOver: ${this.isMouseOver}";
|
||||
return "isMouseDown: $isMouseDown - isMouseOver: $isMouseOver";
|
||||
}
|
||||
}
|
||||
|
||||
T? _ambiguate<T>(T? value) => value;
|
||||
|
||||
class MouseStateBuilder extends StatefulWidget {
|
||||
final MouseStateBuilderCB builder;
|
||||
final VoidCallback? onPressed;
|
||||
MouseStateBuilder({Key? key, required this.builder, this.onPressed})
|
||||
|
||||
const MouseStateBuilder({Key? key, required this.builder, this.onPressed})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_MouseStateBuilderState createState() => _MouseStateBuilderState();
|
||||
State<MouseStateBuilder> createState() => _MouseStateBuilderState();
|
||||
}
|
||||
|
||||
class _MouseStateBuilderState extends State<MouseStateBuilder> {
|
||||
late MouseState _mouseState;
|
||||
|
||||
_MouseStateBuilderState() {
|
||||
_mouseState = MouseState();
|
||||
}
|
||||
@@ -59,7 +62,7 @@ class _MouseStateBuilderState extends State<MouseStateBuilder> {
|
||||
_mouseState.isMouseDown = false;
|
||||
_mouseState.isMouseOver = false;
|
||||
});
|
||||
_ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (widget.onPressed != null) {
|
||||
widget.onPressed!();
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
@@ -10,18 +9,19 @@ class WindowBorder extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return IgnorePointer(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 1 / appWindow.scaleFactor
|
||||
padding: const EdgeInsets.only(
|
||||
top: 1
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: SystemTheme.accentColor.accent,
|
||||
width: appBarSize.toDouble()
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: SystemTheme.accentColor.accent,
|
||||
width: appBarSize.toDouble()
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
));
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import './mouse_state_builder.dart';
|
||||
import '../icons/icons.dart';
|
||||
import '../app_window.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'dart:io' show Platform;
|
||||
import 'icons.dart';
|
||||
import 'mouse_state_builder.dart';
|
||||
|
||||
typedef WindowButtonIconBuilder = Widget Function(
|
||||
WindowButtonContext buttonContext);
|
||||
@@ -16,6 +14,7 @@ class WindowButtonContext {
|
||||
MouseState mouseState;
|
||||
Color? backgroundColor;
|
||||
Color iconColor;
|
||||
|
||||
WindowButtonContext(
|
||||
{required this.context,
|
||||
required this.mouseState,
|
||||
@@ -30,6 +29,7 @@ class WindowButtonColors {
|
||||
late Color iconNormal;
|
||||
late Color iconMouseOver;
|
||||
late Color iconMouseDown;
|
||||
|
||||
WindowButtonColors(
|
||||
{Color? normal,
|
||||
Color? mouseOver,
|
||||
@@ -48,11 +48,11 @@ class WindowButtonColors {
|
||||
|
||||
final _defaultButtonColors = WindowButtonColors(
|
||||
normal: Colors.transparent,
|
||||
iconNormal: Color(0xFF805306),
|
||||
mouseOver: Color(0xFF404040),
|
||||
mouseDown: Color(0xFF202020),
|
||||
iconMouseOver: Color(0xFFFFFFFF),
|
||||
iconMouseDown: Color(0xFFF0F0F0));
|
||||
iconNormal: const Color(0xFF805306),
|
||||
mouseOver: const Color(0xFF404040),
|
||||
mouseDown: const Color(0xFF202020),
|
||||
iconMouseOver: const Color(0xFFFFFFFF),
|
||||
iconMouseDown: const Color(0xFFF0F0F0));
|
||||
|
||||
class WindowButton extends StatelessWidget {
|
||||
final WindowButtonBuilder? builder;
|
||||
@@ -88,51 +88,35 @@ class WindowButton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (kIsWeb) {
|
||||
return Container();
|
||||
} else {
|
||||
// Don't show button on macOS
|
||||
if (Platform.isMacOS) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
final buttonSize = appWindow.titleBarButtonSize;
|
||||
return MouseStateBuilder(
|
||||
builder: (context, mouseState) {
|
||||
WindowButtonContext buttonContext = WindowButtonContext(
|
||||
mouseState: mouseState,
|
||||
context: context,
|
||||
backgroundColor: getBackgroundColor(mouseState),
|
||||
iconColor: getIconColor(mouseState));
|
||||
builder: (context, mouseState) {
|
||||
WindowButtonContext buttonContext = WindowButtonContext(
|
||||
mouseState: mouseState,
|
||||
context: context,
|
||||
backgroundColor: getBackgroundColor(mouseState),
|
||||
iconColor: getIconColor(mouseState));
|
||||
|
||||
var icon = (this.iconBuilder != null)
|
||||
? this.iconBuilder!(buttonContext)
|
||||
: Container();
|
||||
double borderSize = appWindow.borderSize;
|
||||
double defaultPadding =
|
||||
(appWindow.titleBarHeight - borderSize) / 3 - (borderSize / 2);
|
||||
// Used when buttonContext.backgroundColor is null, allowing the AnimatedContainer to fade-out smoothly.
|
||||
var fadeOutColor =
|
||||
getBackgroundColor(MouseState()..isMouseOver = true).withOpacity(0);
|
||||
var padding = this.padding ?? EdgeInsets.zero;
|
||||
var animationMs =
|
||||
mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0);
|
||||
Widget iconWithPadding = Padding(padding: padding, child: icon);
|
||||
iconWithPadding = AnimatedContainer(
|
||||
curve: Curves.easeOut,
|
||||
duration: Duration(milliseconds: animationMs),
|
||||
color: buttonContext.backgroundColor ?? fadeOutColor,
|
||||
child: iconWithPadding);
|
||||
var button = (this.builder != null)
|
||||
? this.builder!(buttonContext, icon)
|
||||
: iconWithPadding;
|
||||
return SizedBox(
|
||||
width: 48, height: 48, child: button);
|
||||
},
|
||||
onPressed: () {
|
||||
if (this.onPressed != null) this.onPressed!();
|
||||
},
|
||||
);
|
||||
var icon =
|
||||
(iconBuilder != null) ? iconBuilder!(buttonContext) : Container();
|
||||
var fadeOutColor =
|
||||
getBackgroundColor(MouseState()..isMouseOver = true)
|
||||
.withOpacity(0);
|
||||
var padding = this.padding ?? EdgeInsets.zero;
|
||||
var animationMs = mouseState.isMouseOver
|
||||
? (animate ? 100 : 0)
|
||||
: (animate ? 200 : 0);
|
||||
Widget iconWithPadding = Padding(padding: padding, child: icon);
|
||||
iconWithPadding = AnimatedContainer(
|
||||
curve: Curves.easeOut,
|
||||
duration: Duration(milliseconds: animationMs),
|
||||
color: buttonContext.backgroundColor ?? fadeOutColor,
|
||||
child: iconWithPadding);
|
||||
var button = (builder != null)
|
||||
? builder!(buttonContext, icon)
|
||||
: iconWithPadding;
|
||||
return SizedBox.square(dimension: 45, child: button);
|
||||
},
|
||||
onPressed: onPressed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +132,7 @@ class MinimizeWindowButton extends WindowButton {
|
||||
animate: animate ?? false,
|
||||
iconBuilder: (buttonContext) =>
|
||||
MinimizeIcon(color: buttonContext.iconColor),
|
||||
onPressed: onPressed ?? () => appWindow.minimize());
|
||||
onPressed: onPressed ?? () => windowManager.minimize());
|
||||
}
|
||||
|
||||
class MaximizeWindowButton extends WindowButton {
|
||||
@@ -163,7 +147,10 @@ class MaximizeWindowButton extends WindowButton {
|
||||
animate: animate ?? false,
|
||||
iconBuilder: (buttonContext) =>
|
||||
MaximizeIcon(color: buttonContext.iconColor),
|
||||
onPressed: onPressed ?? () => appWindow.maximizeOrRestore());
|
||||
onPressed: onPressed ??
|
||||
() async => await windowManager.isMaximized()
|
||||
? await windowManager.restore()
|
||||
: await windowManager.maximize());
|
||||
}
|
||||
|
||||
class RestoreWindowButton extends WindowButton {
|
||||
@@ -178,14 +165,17 @@ class RestoreWindowButton extends WindowButton {
|
||||
animate: animate ?? false,
|
||||
iconBuilder: (buttonContext) =>
|
||||
RestoreIcon(color: buttonContext.iconColor),
|
||||
onPressed: onPressed ?? () => appWindow.maximizeOrRestore());
|
||||
onPressed: onPressed ??
|
||||
() async => await windowManager.isMaximized()
|
||||
? await windowManager.restore()
|
||||
: await windowManager.maximize());
|
||||
}
|
||||
|
||||
final _defaultCloseButtonColors = WindowButtonColors(
|
||||
mouseOver: Color(0xFFD32F2F),
|
||||
mouseDown: Color(0xFFB71C1C),
|
||||
iconNormal: Color(0xFF805306),
|
||||
iconMouseOver: Color(0xFFFFFFFF));
|
||||
mouseOver: const Color(0xFFD32F2F),
|
||||
mouseDown: const Color(0xFFB71C1C),
|
||||
iconNormal: const Color(0xFF805306),
|
||||
iconMouseOver: const Color(0xFFFFFFFF));
|
||||
|
||||
class CloseWindowButton extends WindowButton {
|
||||
CloseWindowButton(
|
||||
@@ -199,5 +189,5 @@ class CloseWindowButton extends WindowButton {
|
||||
animate: animate ?? false,
|
||||
iconBuilder: (buttonContext) =>
|
||||
CloseIcon(color: buttonContext.iconColor),
|
||||
onPressed: onPressed ?? () => appWindow.close());
|
||||
onPressed: onPressed ?? () => windowManager.close());
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:reboot_launcher/src/ui/widget/os/window_button.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/server_dialogs.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
|
||||
class ServerButton extends StatefulWidget {
|
||||
const ServerButton({Key? key}) : super(key: key);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/server_controller.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/server_controller.dart';
|
||||
|
||||
class ServerTypeSelector extends StatelessWidget {
|
||||
final ServerController _serverController = Get.find<ServerController>();
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/snackbar.dart';
|
||||
|
||||
import 'package:reboot_launcher/src/util/selector.dart';
|
||||
|
||||
class FileSelector extends StatefulWidget {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
|
||||
class FluentCard extends StatelessWidget {
|
||||
final Widget child;
|
||||
const FluentCard({Key? key, required this.child}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Mica(
|
||||
elevation: 1,
|
||||
child: Card(
|
||||
backgroundColor: FluentTheme.of(context).menuColor,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(4.0)),
|
||||
child: child
|
||||
)
|
||||
);
|
||||
}
|
||||
56
lib/src/ui/widget/shared/profile_widget.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../controller/game_controller.dart';
|
||||
|
||||
class ProfileWidget extends StatelessWidget {
|
||||
final GameController _gameController = Get.find<GameController>();
|
||||
|
||||
ProfileWidget({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0,
|
||||
vertical: 12.0
|
||||
),
|
||||
child: GestureDetector(
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle
|
||||
),
|
||||
child: Image.asset("assets/images/user.png")
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12.0,
|
||||
),
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Auties00",
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"alautiero@gmail.com",
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w100
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,12 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:html/parser.dart' show parse;
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:reboot_launcher/src/model/fortnite_build.dart';
|
||||
import 'package:reboot_launcher/src/util/time.dart';
|
||||
import 'package:reboot_launcher/src/util/version.dart' as parser;
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'os.dart';
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:reboot_launcher/src/util/server.dart';
|
||||
|
||||
import '../model/fortnite_version.dart';
|
||||
import 'package:reboot_launcher/src/model/fortnite_version.dart';
|
||||
|
||||
String? checkVersion(String? text, List<FortniteVersion> versions) {
|
||||
if (text == null || text.isEmpty) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
|
||||
import '../../../main.dart';
|
||||
import '../ui/dialog/dialog.dart';
|
||||
import 'package:reboot_launcher/main.dart';
|
||||
import 'package:reboot_launcher/src/ui/dialog/dialog.dart';
|
||||
|
||||
|
||||
String? lastError;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:win32/win32.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:win32/win32.dart';
|
||||
|
||||
final _kernel32 = DynamicLibrary.open('kernel32.dll');
|
||||
final _CreateRemoteThread = _kernel32.lookupFunction<
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:win32/win32.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'dart:ffi';
|
||||
import 'package:win32/win32.dart';
|
||||
|
||||
|
||||
const int appBarSize = 2;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:win32/src/kernel32.dart';
|
||||
import 'package:win32/win32.dart';
|
||||
|
||||
final _ntdll = DynamicLibrary.open('ntdll.dll');
|
||||
|
||||
@@ -2,15 +2,14 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:ini/ini.dart';
|
||||
import 'package:process_run/shell.dart';
|
||||
import 'package:reboot_launcher/src/model/server_type.dart';
|
||||
import 'package:reboot_launcher/src/ui/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/util/os.dart';
|
||||
import 'package:shelf_proxy/shelf_proxy.dart';
|
||||
import 'package:shelf/shelf_io.dart';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:shelf_proxy/shelf_proxy.dart';
|
||||
|
||||
final serverLogFile = File("${logsDirectory.path}\\server.log");
|
||||
final serverDirectory = Directory("${assetsDirectory.path}\\lawin");
|
||||
|
||||
@@ -11,9 +11,7 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
bitsdojo_window:
|
||||
path: ./dependencies/bitsdojo_window-0.1.5
|
||||
fluent_ui: ^4.6.2
|
||||
fluent_ui: ^4.7.3
|
||||
bitsdojo_window_windows: ^0.1.5
|
||||
system_theme: ^2.0.0
|
||||
http: ^0.13.5
|
||||
@@ -43,6 +41,7 @@ dependencies:
|
||||
supabase_flutter: ^1.10.0
|
||||
supabase: ^1.9.1
|
||||
fluentui_system_icons: ^1.1.202
|
||||
flutter_acrylic: ^1.1.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <app_links/app_links_plugin_c_api.h>
|
||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
||||
#include <screen_retriever/screen_retriever_plugin.h>
|
||||
#include <system_theme/system_theme_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
@@ -18,6 +19,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
|
||||
BitsdojoWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
||||
FlutterAcrylicPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterAcrylicPlugin"));
|
||||
ScreenRetrieverPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
|
||||
SystemThemePluginRegisterWithRegistrar(
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
app_links
|
||||
bitsdojo_window_windows
|
||||
flutter_acrylic
|
||||
screen_retriever
|
||||
system_theme
|
||||
url_launcher_windows
|
||||
|
||||
36
windows/packaging/exe/custom-inno-setup-script.iss
Normal file
@@ -0,0 +1,36 @@
|
||||
[Setup]
|
||||
AppId={{APP_ID}}
|
||||
AppVersion={{APP_VERSION}}
|
||||
AppName={{DISPLAY_NAME}}
|
||||
AppPublisher={{PUBLISHER_NAME}}
|
||||
AppPublisherURL={{PUBLISHER_URL}}
|
||||
AppSupportURL={{PUBLISHER_URL}}
|
||||
AppUpdatesURL={{PUBLISHER_URL}}
|
||||
DefaultDirName={{INSTALL_DIR_NAME}}
|
||||
DisableProgramGroupPage=yes
|
||||
OutputBaseFilename={{OUTPUT_BASE_FILENAME}}
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
SetupIconFile={{SETUP_ICON_FILE}}
|
||||
WizardStyle=modern
|
||||
PrivilegesRequired=admin
|
||||
ArchitecturesAllowed=x64
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce
|
||||
Name: "launchAtStartup"; Description: "{cm:AutoStartProgram,{{DISPLAY_NAME}}}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
Source: "reboot_launcher-8.1.0+8.1.0-windows-setup_exe\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\\{{EXECUTABLE_NAME}}"; Description: "{cm:LaunchProgram,{{DISPLAY_NAME}}}"; Flags: runascurrentuser nowait postinstall skipifsilent
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}"
|
||||
Name: "{autodesktop}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}"; Tasks: desktopicon
|
||||
Name: "{userstartup}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}"; WorkingDir: "{app}"; Tasks: launchAtStartup
|
||||
@@ -1,6 +1,9 @@
|
||||
script_template: "custom-inno-setup-script.iss"
|
||||
app_id: 31868Auties00.RebootLauncher
|
||||
publisher_name: Auties00
|
||||
publisher_url: https://github.com/Auties00
|
||||
display_name: Reboot Launcher
|
||||
install_dir_name: Reboot Launcher
|
||||
create_desktop_icon: true
|
||||
locales:
|
||||
- en
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||
auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
|
||||
auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME);
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -15,19 +15,20 @@ auto bdw = bitsdojo_window_configure(BDW_CUSTOM_FRAME | BDW_HIDE_ON_STARTUP);
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
bool CheckOneInstance()
|
||||
{
|
||||
HANDLE m_hStartEvent = CreateEventW( NULL, FALSE, FALSE, L"reboot_launcher");
|
||||
if(m_hStartEvent == NULL)
|
||||
{
|
||||
CloseHandle( m_hStartEvent );
|
||||
bool CheckOneInstance(){
|
||||
HANDLE hMutex = CreateMutexW(NULL, TRUE, L"RebootLauncherMutex");
|
||||
if (hMutex == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
CloseHandle( m_hStartEvent );
|
||||
m_hStartEvent = NULL;
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
HWND hwndExisting = FindWindowW(NULL, L"Reboot Launcher");
|
||||
if (hwndExisting != NULL) {
|
||||
ShowWindow(hwndExisting, SW_RESTORE);
|
||||
SetForegroundWindow(hwndExisting);
|
||||
}
|
||||
|
||||
CloseHandle(hMutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
FlutterWindow window(project);
|
||||
Win32Window::Point origin(10, 10);
|
||||
Win32Window::Size size(1280, 720);
|
||||
if (!window.CreateAndShow(L"reboot_launcher", origin, size)) {
|
||||
if (!window.CreateAndShow(L"Reboot Launcher", origin, size)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#include <dwmapi.h>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
|
||||
@@ -108,7 +110,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
|
||||
Destroy();
|
||||
|
||||
const wchar_t* window_class =
|
||||
WindowClassRegistrar::GetInstance()->GetWindowClass();
|
||||
WindowClassRegistrar::GetInstance()->GetWindowClass();
|
||||
|
||||
const POINT target_point = {static_cast<LONG>(origin.x),
|
||||
static_cast<LONG>(origin.y)};
|
||||
@@ -117,10 +119,18 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
|
||||
double scale_factor = dpi / 96.0;
|
||||
|
||||
HWND window = CreateWindow(
|
||||
window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
|
||||
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
|
||||
nullptr, nullptr, GetModuleHandle(nullptr), this);
|
||||
window_class,
|
||||
title.c_str(),
|
||||
WS_OVERLAPPED & ~WS_VISIBLE,
|
||||
Scale(origin.x, scale_factor),
|
||||
Scale(origin.y, scale_factor),
|
||||
Scale(size.width, scale_factor),
|
||||
Scale(size.height, scale_factor),
|
||||
nullptr,
|
||||
nullptr,
|
||||
GetModuleHandle(nullptr),
|
||||
this
|
||||
);
|
||||
|
||||
if (!window) {
|
||||
return false;
|
||||
|
||||