diff --git a/lib/main.dart b/lib/main.dart index 25676f2..7791b7c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,10 +9,10 @@ import 'package:get_storage/get_storage.dart'; import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart'; +import 'package:reboot_launcher/src/page/home_page.dart'; import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:system_theme/system_theme.dart'; -import 'package:reboot_launcher/src/page/home_page.dart'; void main() async { await Directory(safeBinariesDirectory) diff --git a/lib/src/controller/build_controller.dart b/lib/src/controller/build_controller.dart index 9eee730..5c3304d 100644 --- a/lib/src/controller/build_controller.dart +++ b/lib/src/controller/build_controller.dart @@ -1,5 +1,4 @@ import 'package:get/get.dart'; - import 'package:reboot_launcher/src/model/fortnite_build.dart'; class BuildController extends GetxController { diff --git a/lib/src/controller/game_controller.dart b/lib/src/controller/game_controller.dart index 948a37f..f2d6dd9 100644 --- a/lib/src/controller/game_controller.dart +++ b/lib/src/controller/game_controller.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; - import 'package:reboot_launcher/src/model/fortnite_version.dart'; class GameController extends GetxController { diff --git a/lib/src/controller/server_controller.dart b/lib/src/controller/server_controller.dart index 323a220..ab6d550 100644 --- a/lib/src/controller/server_controller.dart +++ b/lib/src/controller/server_controller.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; - import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/server.dart'; @@ -13,6 +12,7 @@ class ServerController extends GetxController { late final RxBool embedded; late final RxBool warning; late RxBool started; + HttpServer? reverseProxy; ServerController() { var storage = GetStorage("server"); @@ -23,18 +23,30 @@ class ServerController extends GetxController { port.addListener(() => storage.write("port", port.text)); embedded = RxBool(storage.read("embedded") ?? true); - embedded.listen((value) => storage.write("embedded", value)); + embedded.listen((value) { + storage.write("embedded", value); + + if(!started.value) { + return; + } + + if(value){ + reverseProxy?.close(force: true); + reverseProxy = null; + started(false); + return; + } + + loadBinary("release.bat", false) + .then((value) => Process.run(value.path, [])) + .then((value) => started(false)); + }); warning = RxBool(storage.read("lawin_value") ?? true); warning.listen((value) => storage.write("lawin_value", value)); started = RxBool(false); isLawinPortFree() - .then((value) => started = RxBool(!value)); - } - - Future kill() async { - var release = await loadBinary("release.bat", false); - return Process.run(release.path, []); + .then((value) => !embedded.value ? {} : started = RxBool(!value)); } } \ No newline at end of file diff --git a/lib/src/model/fortnite_version.dart b/lib/src/model/fortnite_version.dart index d8c91e1..86f1042 100644 --- a/lib/src/model/fortnite_version.dart +++ b/lib/src/model/fortnite_version.dart @@ -1,4 +1,5 @@ import 'dart:io'; + import 'package:get/get.dart'; import 'package:path/path.dart' as path; diff --git a/lib/src/page/home_page.dart b/lib/src/page/home_page.dart index 299cd5c..33e8ef7 100644 --- a/lib/src/page/home_page.dart +++ b/lib/src/page/home_page.dart @@ -5,11 +5,10 @@ import 'package:get_storage/get_storage.dart'; import 'package:reboot_launcher/src/page/info_page.dart'; import 'package:reboot_launcher/src/page/launcher_page.dart'; import 'package:reboot_launcher/src/page/server_page.dart'; -import 'package:reboot_launcher/src/widget/window_buttons.dart'; -import 'package:reboot_launcher/src/widget/window_border.dart'; -import 'package:window_manager/window_manager.dart'; - import 'package:reboot_launcher/src/util/os.dart'; +import 'package:reboot_launcher/src/widget/window_border.dart'; +import 'package:reboot_launcher/src/widget/window_buttons.dart'; +import 'package:window_manager/window_manager.dart'; import '../util/reboot.dart'; diff --git a/lib/src/page/launcher_page.dart b/lib/src/page/launcher_page.dart index aa6be0b..59a0e7c 100644 --- a/lib/src/page/launcher_page.dart +++ b/lib/src/page/launcher_page.dart @@ -1,13 +1,12 @@ import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; +import 'package:get/get.dart'; import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/widget/deployment_selector.dart'; import 'package:reboot_launcher/src/widget/launch_button.dart'; import 'package:reboot_launcher/src/widget/username_box.dart'; -import 'package:get/get.dart'; - import 'package:reboot_launcher/src/widget/version_selector.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/lib/src/page/server_page.dart b/lib/src/page/server_page.dart index 0485081..d1bbba6 100644 --- a/lib/src/page/server_page.dart +++ b/lib/src/page/server_page.dart @@ -1,12 +1,11 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart'; -import 'package:reboot_launcher/src/widget/warning_info.dart'; +import 'package:reboot_launcher/src/widget/host_input.dart'; import 'package:reboot_launcher/src/widget/local_server_switch.dart'; import 'package:reboot_launcher/src/widget/port_input.dart'; - -import 'package:reboot_launcher/src/widget/host_input.dart'; import 'package:reboot_launcher/src/widget/server_button.dart'; +import 'package:reboot_launcher/src/widget/warning_info.dart'; class ServerPage extends StatelessWidget { final ServerController _serverController = Get.find(); diff --git a/lib/src/util/build.dart b/lib/src/util/build.dart index 8e6b1a7..abc2a17 100644 --- a/lib/src/util/build.dart +++ b/lib/src/util/build.dart @@ -1,14 +1,12 @@ import 'dart:io'; import 'dart:math'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart' as path; -import 'package:reboot_launcher/src/util/version.dart' as parser; + import 'package:html/parser.dart' show parse; - -import 'package:reboot_launcher/src/model/fortnite_build.dart'; - +import 'package:http/http.dart' as http; import 'package:process_run/shell.dart'; +import 'package:reboot_launcher/src/model/fortnite_build.dart'; import 'package:reboot_launcher/src/util/binary.dart'; +import 'package:reboot_launcher/src/util/version.dart' as parser; const _userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"; diff --git a/lib/src/util/reboot.dart b/lib/src/util/reboot.dart index 3197890..aab6619 100644 --- a/lib/src/util/reboot.dart +++ b/lib/src/util/reboot.dart @@ -1,11 +1,11 @@ import 'dart:io'; import 'package:archive/archive_io.dart'; -import 'package:get/get.dart'; -import 'package:reboot_launcher/src/util/binary.dart'; -import 'package:http/http.dart' as http; import 'package:crypto/crypto.dart'; +import 'package:get/get.dart'; +import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; +import 'package:reboot_launcher/src/util/binary.dart'; const _rebootUrl = "https://nightly.link/Milxnor/Universal-Walking-Simulator/workflows/msbuild/master/Release.zip"; diff --git a/lib/src/util/server.dart b/lib/src/util/server.dart index 7a4829c..66ddc2c 100644 --- a/lib/src/util/server.dart +++ b/lib/src/util/server.dart @@ -1,14 +1,14 @@ -// ignore_for_file: use_build_context_synchronously - import 'dart:io'; + import 'package:archive/archive_io.dart'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/foundation.dart'; -import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; import 'package:process_run/shell.dart'; import 'package:reboot_launcher/src/util/binary.dart'; +import 'package:shelf/shelf_io.dart' as shelf_io; +import 'package:shelf_proxy/shelf_proxy.dart'; final serverLocation = Directory("${Platform.environment["UserProfile"]}/.reboot_launcher/lawin"); const String _serverUrl = @@ -47,27 +47,76 @@ Future isLawinPortFree() async { return !process.outText.contains(" LISTENING "); // Goofy way, best we got } -Future showRemoteServerCheck(BuildContext context, String host, String port, [bool autoClose = false]) async { - var future = _pingServer(host, port).then((value) { - if(value && autoClose){ - Navigator.of(context).pop(); +Future changeReverseProxyState(BuildContext context, String host, String port, HttpServer? server) async { + if(server != null){ + try{ + server.close(force: true); + return null; + }catch(error){ + _showStopProxyError(context, error); + return server; + } + } + + host = host.trim(); + if(host.isEmpty){ + showSnackbar( + context, const Snackbar(content: Text("Missing host name"))); + return null; + } + + port = port.trim(); + if(port.isEmpty){ + showSnackbar( + context, const Snackbar(content: Text("Missing port", textAlign: TextAlign.center))); + return null; + } + + if(int.tryParse(port) == null){ + showSnackbar( + context, const Snackbar(content: Text("Invalid port, use only numbers", textAlign: TextAlign.center))); + return null; + } + + try{ + var uri = await _showReverseProxyCheck(context, host, port); + if(uri == null){ + return null; } - return value; - }); - await showDialog( + return await shelf_io.serve(proxyHandler(uri), 'localhost', 3551); + }catch(error){ + _showStartProxyError(context, error); + return null; + } +} + +Future _showReverseProxyCheck(BuildContext context, String host, String port) async { + var future = _pingServer(host, port); + return await showDialog( context: context, builder: (context) => ContentDialog( - content: FutureBuilder( + content: FutureBuilder( future: future, builder: (context, snapshot) { - if(snapshot.hasData){ + if(snapshot.hasError){ return SizedBox( width: double.infinity, - child: Text(snapshot.data! ? "The server answered correctly" : "The remote server doesn't work correctly or the IP and/or the port are incorrect" , textAlign: TextAlign.center) + child: Text("Cannot ping remote server: ${snapshot.error}" , textAlign: TextAlign.center) ); } + if(snapshot.connectionState == ConnectionState.done && !snapshot.hasData){ + return const SizedBox( + width: double.infinity, + child: Text("The remote server doesn't work correctly or the IP and/or the port are incorrect" , textAlign: TextAlign.center) + ); + } + + if(snapshot.hasData){ + Navigator.of(context).pop(snapshot.data); + } + return const InfoLabel( label: "Pinging remote lawin server...", child: SizedBox( @@ -86,30 +135,81 @@ Future showRemoteServerCheck(BuildContext context, String host, String por backgroundColor: ButtonState.all(Colors.red)), child: const Text('Close'), )) - ], + ] ) ); - - return await future; } -Future _pingServer(String host, String port, [bool https=false]) async { +Future _pingServer(String host, String port, [bool https=false]) async { + var hostName = _getHostName(host); + var declaredScheme = _getScheme(host); try{ var uri = Uri( - scheme: https ? "https" : "http", - host: host, + scheme: declaredScheme ?? (https ? "https" : "http"), + host: hostName, port: int.parse(port) ); var client = HttpClient() ..connectionTimeout = const Duration(seconds: 5); var request = await client.getUrl(uri); var response = await request.close(); - return response.statusCode == 200; + return response.statusCode == 200 ? uri : null; }catch(_){ - return https ? false : await _pingServer(host, port, true); + return https || declaredScheme != null ? null : await _pingServer(host, port, true); } } +String? _getHostName(String host) => host.replaceFirst("http://", "").replaceFirst("https://", ""); + +String? _getScheme(String host) => host.startsWith("http://") ? "http" : host.startsWith("https://") ? "https" : null; + + +void _showStartProxyError(BuildContext context, Object error) { + showDialog( + context: context, + builder: (context) => ContentDialog( + content: SizedBox( + width: double.infinity, + child: Text("Cannot create the reverse proxy: $error", textAlign: TextAlign.center) + ), + actions: [ + SizedBox( + width: double.infinity, + child: FilledButton( + onPressed: () => Navigator.of(context).pop(), + style: ButtonStyle( + backgroundColor: ButtonState.all(Colors.red)), + child: const Text('Close'), + ) + ) + ], + ) + ); +} + +void _showStopProxyError(BuildContext context, Object error) { + showDialog( + context: context, + builder: (context) => ContentDialog( + content: SizedBox( + width: double.infinity, + child: Text("Cannot kill the reverse proxy: $error", textAlign: TextAlign.center) + ), + actions: [ + SizedBox( + width: double.infinity, + child: FilledButton( + onPressed: () => Navigator.of(context).pop(), + style: ButtonStyle( + backgroundColor: ButtonState.all(Colors.red)), + child: const Text('Close'), + ) + ) + ], + ) + ); +} + Future changeEmbeddedServerState(BuildContext context, bool running) async { if (running) { var releaseBat = await loadBinary("release.bat", false); diff --git a/lib/src/widget/add_local_version.dart b/lib/src/widget/add_local_version.dart index 701c50d..32c4252 100644 --- a/lib/src/widget/add_local_version.dart +++ b/lib/src/widget/add_local_version.dart @@ -3,9 +3,8 @@ import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart'; -import 'package:reboot_launcher/src/widget/select_file.dart'; - import 'package:reboot_launcher/src/model/fortnite_version.dart'; +import 'package:reboot_launcher/src/widget/select_file.dart'; class AddLocalVersion extends StatelessWidget { final GameController _gameController = Get.find(); diff --git a/lib/src/widget/add_server_version.dart b/lib/src/widget/add_server_version.dart index 2489bb6..78c94c9 100644 --- a/lib/src/widget/add_server_version.dart +++ b/lib/src/widget/add_server_version.dart @@ -1,19 +1,18 @@ import 'dart:async'; import 'dart:io'; + import 'package:async/async.dart'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; -import 'package:process_run/shell.dart'; import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart'; -import 'package:reboot_launcher/src/util/build.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/util/binary.dart'; +import 'package:reboot_launcher/src/util/build.dart'; import 'package:reboot_launcher/src/widget/select_file.dart'; import 'package:reboot_launcher/src/widget/version_name_input.dart'; -import 'package:reboot_launcher/src/model/fortnite_version.dart'; -import 'package:reboot_launcher/src/model/fortnite_build.dart'; import 'build_selector.dart'; class AddServerVersion extends StatefulWidget { diff --git a/lib/src/widget/build_selector.dart b/lib/src/widget/build_selector.dart index e094b91..d2ebafa 100644 --- a/lib/src/widget/build_selector.dart +++ b/lib/src/widget/build_selector.dart @@ -1,7 +1,6 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/controller/build_controller.dart'; - import 'package:reboot_launcher/src/model/fortnite_build.dart'; class BuildSelector extends StatefulWidget { diff --git a/lib/src/widget/deployment_selector.dart b/lib/src/widget/deployment_selector.dart index 3c42f5f..b759629 100644 --- a/lib/src/widget/deployment_selector.dart +++ b/lib/src/widget/deployment_selector.dart @@ -1,8 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/widget/smart_switch.dart'; - import 'package:reboot_launcher/src/controller/game_controller.dart'; +import 'package:reboot_launcher/src/widget/smart_switch.dart'; class DeploymentSelector extends StatelessWidget { final GameController _gameController = Get.find(); diff --git a/lib/src/widget/host_input.dart b/lib/src/widget/host_input.dart index 8acb359..5c661fd 100644 --- a/lib/src/widget/host_input.dart +++ b/lib/src/widget/host_input.dart @@ -1,8 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/widget/smart_input.dart'; - import 'package:reboot_launcher/src/controller/server_controller.dart'; +import 'package:reboot_launcher/src/widget/smart_input.dart'; class HostInput extends StatelessWidget { final ServerController _serverController = Get.find(); diff --git a/lib/src/widget/launch_button.dart b/lib/src/widget/launch_button.dart index 2c9c447..f8b983a 100644 --- a/lib/src/widget/launch_button.dart +++ b/lib/src/widget/launch_button.dart @@ -6,14 +6,13 @@ import 'package:get/get.dart'; import 'package:process_run/shell.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart'; -import 'package:reboot_launcher/src/util/injector.dart'; import 'package:reboot_launcher/src/util/binary.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:url_launcher/url_launcher.dart'; import 'package:win32_suspend_process/win32_suspend_process.dart'; -import 'package:reboot_launcher/src/util/server.dart'; - class LaunchButton extends StatefulWidget { const LaunchButton( {Key? key}) @@ -65,28 +64,6 @@ class _LaunchButtonState extends State { return; } - if (_serverController.embedded.value && !_serverController.started.value && await isLawinPortFree()) { - if(!mounted){ - return; - } - - var result = await changeEmbeddedServerState(context, false); - _serverController.started(result); - } - - _updateServerState(true); - _onStart(); - } - - Future _updateServerState(bool value) async { - if (_gameController.started.value == value) { - return; - } - - _gameController.started(value); - } - - Future _onStart() async { try { _updateServerState(true); var version = _gameController.selectedVersionObs.value!; @@ -101,17 +78,16 @@ class _LaunchButtonState extends State { Win32Process(_gameController.eacProcess!.pid).suspend(); } - if(!_serverController.embedded.value){ - var available = await _showPingWarning(); - if(!available) { - return; - } - } - if(hosting){ await patchExe(version.executable!); } + await _startServerIfNecessary(); + if(!_serverController.started.value){ + _onStop(); + return; + } + _gameController.gameProcess = await Process.start(version.executable!.path, _createProcessArguments()) ..exitCode.then((_) => _onEnd()) ..outLines.forEach(_onGameOutput); @@ -126,6 +102,43 @@ class _LaunchButtonState extends State { } } + Future _startServerIfNecessary() async { + if (!mounted) { + return; + } + + if(_serverController.started.value){ + return; + } + + if(!(await isLawinPortFree())){ + _serverController.started(true); + return; + } + + if (_serverController.embedded.value) { + var result = await changeEmbeddedServerState(context, false); + _serverController.started(result); + return; + } + + _serverController.reverseProxy = await changeReverseProxyState( + context, + _serverController.host.text, + _serverController.port.text, + _serverController.reverseProxy + ); + _serverController.started(_serverController.reverseProxy != null); + } + + Future _updateServerState(bool value) async { + if (_gameController.started.value == value) { + return; + } + + _gameController.started(value); + } + void _onEnd() { if(_lawinFail){ return; @@ -148,19 +161,6 @@ class _LaunchButtonState extends State { Navigator.of(context).pop(false); } - Future _showPingWarning() async { - if(!mounted){ - return false; - } - - return await showRemoteServerCheck( - context, - _serverController.host.text, - _serverController.port.text, - true - ); - } - Future _showBrokenServerWarning() async { if(!mounted){ return; diff --git a/lib/src/widget/local_server_switch.dart b/lib/src/widget/local_server_switch.dart index ef546ec..51c6407 100644 --- a/lib/src/widget/local_server_switch.dart +++ b/lib/src/widget/local_server_switch.dart @@ -1,8 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/widget/smart_switch.dart'; - import 'package:reboot_launcher/src/controller/server_controller.dart'; +import 'package:reboot_launcher/src/widget/smart_switch.dart'; class LocalServerSwitch extends StatelessWidget { final ServerController _serverController = Get.find(); @@ -15,7 +14,7 @@ class LocalServerSwitch extends StatelessWidget { message: "Determines whether an embedded or remote lawin server should be used", child: SmartSwitch( value: _serverController.embedded, - label: "Embedded" + label: "Embedded", ), ); } diff --git a/lib/src/widget/port_input.dart b/lib/src/widget/port_input.dart index 7dd641e..35aa42d 100644 --- a/lib/src/widget/port_input.dart +++ b/lib/src/widget/port_input.dart @@ -1,8 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/widget/smart_input.dart'; - import 'package:reboot_launcher/src/controller/server_controller.dart'; +import 'package:reboot_launcher/src/widget/smart_input.dart'; class PortInput extends StatelessWidget { final ServerController _serverController = Get.find(); diff --git a/lib/src/widget/scan_local_version.dart b/lib/src/widget/scan_local_version.dart index 4185e63..06acd42 100644 --- a/lib/src/widget/scan_local_version.dart +++ b/lib/src/widget/scan_local_version.dart @@ -2,9 +2,9 @@ import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/foundation.dart'; +import 'package:path/path.dart' as path; import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/widget/select_file.dart'; -import 'package:path/path.dart' as path; class ScanLocalVersion extends StatefulWidget { diff --git a/lib/src/widget/server_button.dart b/lib/src/widget/server_button.dart index 545a084..9cdbc23 100644 --- a/lib/src/widget/server_button.dart +++ b/lib/src/widget/server_button.dart @@ -1,7 +1,6 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart'; - import 'package:reboot_launcher/src/util/server.dart'; class ServerButton extends StatelessWidget { @@ -16,35 +15,56 @@ class ServerButton extends StatelessWidget { child: SizedBox( width: double.infinity, child: Obx(() => Tooltip( - message: !_serverController.embedded.value - ? "Check the address of the remote Lawin server" - : _serverController.started.value - ? "Stop the running Lawin server instance" - : "Start a new Lawin server instance", + message: _helpMessage, child: Button( onPressed: () => _onPressed(context), - child: Text(_serverController.embedded.value - ? !_serverController.started.value + child: Text(!_serverController.started.value ? "Start" - : "Stop" - : "Ping Server")), + : "Stop")), )), ), ); } + String get _helpMessage { + if (_serverController.embedded.value) { + if (_serverController.started.value) { + return "Stop the Lawin server currently running"; + } + + return "Start a new local Lawin server"; + } + + if (_serverController.started.value) { + return "Stop the reverse proxy currently running"; + } + + return "Start a reverse proxy targeting the remote Lawin server"; + } + void _onPressed(BuildContext context) async { + var running = _serverController.started.value; + _serverController.started.value = !running; if (!_serverController.embedded.value) { - showRemoteServerCheck( - context, _serverController.host.text, _serverController.port.text); + _serverController.reverseProxy = await changeReverseProxyState( + context, + _serverController.host.text, + _serverController.port.text, + _serverController.reverseProxy + ); + _updateStarted(_serverController.reverseProxy != null); return; } - var running = _serverController.started.value; - _serverController.started.value = !running; var updatedRunning = await changeEmbeddedServerState(context, running); - if (updatedRunning != _serverController.started.value) { - _serverController.started.value = updatedRunning; + _updateStarted(updatedRunning); + } + + void _updateStarted(bool updatedRunning) { + if (updatedRunning == _serverController.started.value) { + return; } + + _serverController.started.value = updatedRunning; } } diff --git a/lib/src/widget/username_box.dart b/lib/src/widget/username_box.dart index f5ec437..dfb6951 100644 --- a/lib/src/widget/username_box.dart +++ b/lib/src/widget/username_box.dart @@ -1,8 +1,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; -import 'package:reboot_launcher/src/widget/smart_input.dart'; - import 'package:reboot_launcher/src/controller/game_controller.dart'; +import 'package:reboot_launcher/src/widget/smart_input.dart'; class UsernameBox extends StatelessWidget { final GameController _gameController = Get.find(); diff --git a/lib/src/widget/version_name_input.dart b/lib/src/widget/version_name_input.dart index e5f2bf3..bef3178 100644 --- a/lib/src/widget/version_name_input.dart +++ b/lib/src/widget/version_name_input.dart @@ -1,6 +1,5 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; - import 'package:reboot_launcher/src/controller/game_controller.dart'; class VersionNameInput extends StatelessWidget { diff --git a/lib/src/widget/version_selector.dart b/lib/src/widget/version_selector.dart index cf19472..bfc68ec 100644 --- a/lib/src/widget/version_selector.dart +++ b/lib/src/widget/version_selector.dart @@ -1,29 +1,28 @@ -// ignore_for_file: use_build_context_synchronously - import 'dart:async'; -import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' show showMenu, PopupMenuEntry, PopupMenuItem; import 'package:get/get.dart'; +import 'package:reboot_launcher/src/controller/game_controller.dart'; +import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/widget/add_local_version.dart'; import 'package:reboot_launcher/src/widget/add_server_version.dart'; - -import 'package:reboot_launcher/src/model/fortnite_version.dart'; - -import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/widget/scan_local_version.dart'; import 'package:url_launcher/url_launcher.dart'; -import '../controller/build_controller.dart'; - -class VersionSelector extends StatelessWidget { - final GameController _gameController = Get.find(); +class VersionSelector extends StatefulWidget { final bool enableScanner; - VersionSelector({Key? key, this.enableScanner = false}) : super(key: key); + const VersionSelector({Key? key, this.enableScanner = false}) : super(key: key); + + @override + State createState() => _VersionSelectorState(); +} + +class _VersionSelectorState extends State { + final GameController _gameController = Get.find(); @override Widget build(BuildContext context) { @@ -46,14 +45,14 @@ class VersionSelector extends StatelessWidget { const SizedBox( width: 16, ), - if(enableScanner) + if(widget.enableScanner) Tooltip( message: "Scan all fortnite builds in a directory", child: Button( child: const Icon(FluentIcons.site_scan), onPressed: () => _openScanLocalVersionDialog(context)), ), - if(enableScanner) + if(widget.enableScanner) const SizedBox( width: 16, ), @@ -125,7 +124,7 @@ class VersionSelector extends StatelessWidget { void _openScanLocalVersionDialog(BuildContext context) async { await showDialog( context: context, - builder: (context) => ScanLocalVersion()); + builder: (context) => const ScanLocalVersion()); } Future _openMenu( @@ -142,13 +141,26 @@ class VersionSelector extends StatelessWidget { switch (result) { case 0: + if(!mounted){ + return; + } + Navigator.of(context).pop(); launchUrl(version.location.uri); break; case 1: _gameController.removeVersion(version); + + if(!mounted){ + return; + } + await _openDeleteDialog(context, version); + if(!mounted){ + return; + } + Navigator.of(context).pop(); if (_gameController.selectedVersionObs.value?.name == version.name || _gameController.hasNoVersions) { _gameController.selectedVersionObs.value = null; diff --git a/lib/src/widget/window_border.dart b/lib/src/widget/window_border.dart index a0c6e7e..2fdcbc2 100644 --- a/lib/src/widget/window_border.dart +++ b/lib/src/widget/window_border.dart @@ -1,8 +1,7 @@ import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:flutter/material.dart'; -import 'package:system_theme/system_theme.dart'; - import 'package:reboot_launcher/src/util/os.dart'; +import 'package:system_theme/system_theme.dart'; class WindowBorder extends StatelessWidget { const WindowBorder({Key? key}) : super(key: key); diff --git a/lib/src/widget/window_buttons.dart b/lib/src/widget/window_buttons.dart index 0ba3725..5dce903 100644 --- a/lib/src/widget/window_buttons.dart +++ b/lib/src/widget/window_buttons.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:reboot_launcher/src/util/os.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index b371955..ffa8ec7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: get: ^4.6.5 get_storage: ^2.0.3 window_manager: ^0.2.7 + shelf_proxy: ^1.0.2 dependency_overrides: win32: ^3.0.0