This commit is contained in:
Alessandro Autiero
2024-06-04 20:31:06 +02:00
parent 93c5d6c56b
commit 2bf084d120
28 changed files with 731 additions and 516 deletions

View File

@@ -2,20 +2,26 @@ import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:app_links/app_links.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' show MaterialPage;
import 'package:get/get.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/backend_controller.dart';
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
import 'package:reboot_launcher/src/controller/settings_controller.dart';
import 'package:reboot_launcher/src/controller/update_controller.dart';
import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
import 'package:reboot_launcher/src/dialog/implementation/dll.dart';
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
import 'package:reboot_launcher/src/page/abstract/page.dart';
import 'package:reboot_launcher/src/page/abstract/page_suggestion.dart';
import 'package:reboot_launcher/src/page/pages.dart';
import 'package:reboot_launcher/src/util/dll.dart';
import 'package:reboot_launcher/src/util/matchmaker.dart';
import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/util/translations.dart';
import 'package:reboot_launcher/src/widget/info_bar_area.dart';
@@ -33,6 +39,8 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepAliveClientMixin {
static const double _kDefaultPadding = 12.0;
final BackendController _backendController = Get.find<BackendController>();
final HostingController _hostingController = Get.find<HostingController>();
final SettingsController _settingsController = Get.find<SettingsController>();
final UpdateController _updateController = Get.find<UpdateController>();
final GlobalKey _searchKey = GlobalKey();
@@ -45,9 +53,62 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
@override
void initState() {
windowManager.addListener(this);
WidgetsBinding.instance.addPostFrameCallback((_) => _checkUpdates());
super.initState();
windowManager.addListener(this);
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkUpdates();
_initAppLink();
_checkGameServer();
});
}
void _initAppLink() async {
final appLinks = AppLinks();
final initialUrl = await appLinks.getInitialLink();
if(initialUrl != null) {
_joinServer(initialUrl);
}
appLinks.uriLinkStream.listen(_joinServer);
}
void _joinServer(Uri uri) {
final uuid = uri.host;
final server = _hostingController.findServerById(uuid);
if(server != null) {
_backendController.joinServer(_hostingController.uuid, server);
}else {
showInfoBar(
translations.noServerFound,
duration: infoBarLongDuration,
severity: InfoBarSeverity.error
);
}
}
Future<void> _checkGameServer() async {
try {
final address = _backendController.gameServerAddress.text;
if(isLocalHost(address)) {
return;
}
var result = await pingGameServer(address);
if(result) {
return;
}
var oldOwner = _backendController.gameServerOwner.value;
_backendController.joinLocalHost();
WidgetsBinding.instance.addPostFrameCallback((_) => showInfoBar(
oldOwner == null ? translations.serverNoLongerAvailableUnnamed : translations.serverNoLongerAvailable(oldOwner),
severity: InfoBarSeverity.warning,
duration: infoBarLongDuration
));
}catch(_) {
// Intended behaviour
// Just ignore the error
}
}
void _checkUpdates() {
@@ -58,7 +119,10 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
}
for(final injectable in InjectableDll.values) {
downloadCriticalDllInteractive("${injectable.name}.dll");
downloadCriticalDllInteractive(
injectable.path,
silent: true
);
}
watchDlls().listen((filePath) => showDllDeletedDialog(() {
@@ -157,54 +221,55 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
super.build(context);
_settingsController.language.value;
loadTranslations(context);
return Obx(() => NavigationPaneTheme(
data: NavigationPaneThemeData(
backgroundColor: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.93),
),
child: NavigationView(
paneBodyBuilder: (pane, body) => _PaneBody(
padding: _kDefaultPadding,
controller: pagesController,
body: body
),
appBar: NavigationAppBar(
height: 32,
title: _draggableArea,
actions: WindowTitleBar(focused: _focused()),
leading: _backButton,
automaticallyImplyLeading: false,
),
pane: NavigationPane(
selected: pageIndex.value,
onChanged: (index) {
final lastPageIndex = pageIndex.value;
if(lastPageIndex != index) {
pageIndex.value = index;
}else if(pageStack.isNotEmpty) {
Navigator.of(pageKey.currentContext!).pop();
final element = pageStack.removeLast();
appStack.remove(element);
pagesController.add(null);
}
},
menuButton: const SizedBox(),
displayMode: PaneDisplayMode.open,
items: _items,
customPane: _CustomPane(_settingsController),
header: const ProfileWidget(),
autoSuggestBox: _autoSuggestBox,
indicator: const StickyNavigationIndicator(
duration: Duration(milliseconds: 500),
curve: Curves.easeOut,
indicatorSize: 3.25
)
),
contentShape: const RoundedRectangleBorder(),
onOpenSearch: () => _searchFocusNode.requestFocus(),
transitionBuilder: (child, animation) => child
)
),
);
return Obx(() {
return NavigationPaneTheme(
data: NavigationPaneThemeData(
backgroundColor: FluentTheme.of(context).micaBackgroundColor.withOpacity(0.93),
),
child: NavigationView(
paneBodyBuilder: (pane, body) => _PaneBody(
padding: _kDefaultPadding,
controller: pagesController,
body: body
),
appBar: NavigationAppBar(
height: 32,
title: _draggableArea,
actions: WindowTitleBar(focused: _focused()),
leading: _backButton,
automaticallyImplyLeading: false,
),
pane: NavigationPane(
selected: pageIndex.value,
onChanged: (index) {
final lastPageIndex = pageIndex.value;
if(lastPageIndex != index) {
pageIndex.value = index;
}else if(pageStack.isNotEmpty) {
Navigator.of(pageKey.currentContext!).pop();
final element = pageStack.removeLast();
appStack.remove(element);
pagesController.add(null);
}
},
menuButton: const SizedBox(),
displayMode: PaneDisplayMode.open,
items: _items,
customPane: _CustomPane(_settingsController),
header: const ProfileWidget(),
autoSuggestBox: _autoSuggestBox,
indicator: const StickyNavigationIndicator(
duration: Duration(milliseconds: 500),
curve: Curves.easeOut,
indicatorSize: 3.25
)
),
contentShape: const RoundedRectangleBorder(),
onOpenSearch: () => _searchFocusNode.requestFocus(),
transitionBuilder: (child, animation) => child
)
);
});
}
Widget get _backButton => StreamBuilder(

View File

@@ -69,9 +69,11 @@ class InfoPage extends RebootPage {
class _InfoPageState extends RebootPageState<InfoPage> {
final SettingsController _settingsController = Get.find<SettingsController>();
RxInt _counter = RxInt(kDebugMode ? 0 : 180);
late bool _showButton;
@override
void initState() {
_showButton = _settingsController.firstRun.value;
if(_settingsController.firstRun.value) {
Timer.periodic(const Duration(seconds: 1), (timer) {
if (_counter.value <= 0) {
@@ -89,24 +91,29 @@ class _InfoPageState extends RebootPageState<InfoPage> {
List<Widget> get settings => InfoPage._infoTiles;
@override
Widget? get button => Obx(() {
if(!_settingsController.firstRun.value) {
Widget? get button {
if(!_showButton) {
return const SizedBox.shrink();
}
final totalSecondsLeft = _counter.value;
final minutesLeft = totalSecondsLeft ~/ 60;
final secondsLeft = totalSecondsLeft % 60;
return SizedBox(
width: double.infinity,
height: 48,
child: Button(
onPressed: totalSecondsLeft <= 0 ? () => pageIndex.value = RebootPageType.play.index : null,
child: Text(
totalSecondsLeft <= 0 ? "I have read the instructions"
: "Read the instructions for at least ${secondsLeft == 0 ? '$minutesLeft minute${minutesLeft > 1 ? 's' : ''}' : minutesLeft == 0 ? '$secondsLeft second${secondsLeft > 1 ? 's' : ''}' : '$minutesLeft minute${minutesLeft > 1 ? 's' : ''} and $secondsLeft second${secondsLeft > 1 ? 's' : ''}'}"
),
)
);
});
return Obx(() {
final totalSecondsLeft = _counter.value;
final minutesLeft = totalSecondsLeft ~/ 60;
final secondsLeft = totalSecondsLeft % 60;
return SizedBox(
width: double.infinity,
height: 48,
child: Button(
onPressed: totalSecondsLeft <= 0 ? () {
_showButton = false;
pageIndex.value = RebootPageType.play.index;
} : null,
child: Text(
totalSecondsLeft <= 0 ? "I have read the instructions"
: "Read the instructions for at least ${secondsLeft == 0 ? '$minutesLeft minute${minutesLeft > 1 ? 's' : ''}' : minutesLeft == 0 ? '$secondsLeft second${secondsLeft > 1 ? 's' : ''}' : '$minutesLeft minute${minutesLeft > 1 ? 's' : ''} and $secondsLeft second${secondsLeft > 1 ? 's' : ''}'}"
),
)
);
});
}
}

View File

@@ -11,6 +11,7 @@ import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
import 'package:reboot_launcher/src/controller/settings_controller.dart';
import 'package:reboot_launcher/src/controller/update_controller.dart';
import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
import 'package:reboot_launcher/src/dialog/implementation/data.dart';
import 'package:reboot_launcher/src/dialog/implementation/server.dart';
@@ -65,8 +66,10 @@ class _HostingPageState extends RebootPageState<HostPage> {
}
@override
Widget get button => const LaunchButton(
host: true
Widget get button => LaunchButton(
host: true,
startLabel: translations.startHosting,
stopLabel: translations.stopHosting
);
@override
@@ -194,6 +197,8 @@ class _HostingPageState extends RebootPageState<HostPage> {
title: Text(translations.settingsServerTypeName),
subtitle: Text(translations.settingsServerTypeDescription),
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
leading: Text(_updateController.customGameServer.value ? translations.settingsServerTypeCustomName : translations.settingsServerTypeEmbeddedName),
items: {
false: translations.settingsServerTypeEmbeddedName,
@@ -209,7 +214,9 @@ class _HostingPageState extends RebootPageState<HostPage> {
_updateController.customGameServer.value = entry.key;
_updateController.infoBarEntry?.close();
if(!entry.key) {
_updateController.updateReboot(true);
_updateController.updateReboot(
force: true
);
}
}
)).toList()
@@ -256,13 +263,17 @@ class _HostingPageState extends RebootPageState<HostPage> {
title: Text(translations.settingsServerTimerName),
subtitle: Text(translations.settingsServerTimerSubtitle),
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
leading: Text(_updateController.timer.value.text),
items: UpdateTimer.values.map((entry) => MenuFlyoutItem(
text: Text(entry.text),
onPressed: () {
_updateController.timer.value = entry;
_updateController.infoBarEntry?.close();
_updateController.updateReboot(true);
_updateController.updateReboot(
force: true
);
}
)).toList()
))

View File

@@ -5,6 +5,7 @@ import 'package:flutter_localized_locales/flutter_localized_locales.dart';
import 'package:get/get.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/settings_controller.dart';
import 'package:reboot_launcher/src/dialog/abstract/dialog.dart';
import 'package:reboot_launcher/src/dialog/implementation/data.dart';
import 'package:reboot_launcher/src/page/abstract/page.dart';
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
@@ -46,6 +47,8 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
title: Text(translations.settingsUtilsLanguageName),
subtitle: Text(translations.settingsUtilsLanguageDescription),
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
leading: Text(_getLocaleName(_settingsController.language.value)),
items: AppLocalizations.supportedLocales.map((locale) => MenuFlyoutItem(
text: Text(_getLocaleName(locale.languageCode)),
@@ -60,6 +63,8 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
title: Text(translations.settingsUtilsThemeName),
subtitle: Text(translations.settingsUtilsThemeDescription),
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
leading: Text(_settingsController.themeMode.value.title),
items: ThemeMode.values.map((themeMode) => MenuFlyoutItem(
text: Text(themeMode.title),