Skip to content

Commit 9fa220b

Browse files
committed
[Launcher] feat: add button to exit dev playtest
1 parent f631de5 commit 9fa220b

3 files changed

Lines changed: 157 additions & 20 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import 'package:fluent_ui/fluent_ui.dart';
2+
import 'package:flutter/material.dart' as mt;
3+
import 'package:grpc/grpc.dart';
4+
import 'package:kyber/kyber.dart';
5+
import 'package:kyber_launcher/core/routing/app_router.dart';
6+
import 'package:kyber_launcher/core/services/app_settings.dart';
7+
import 'package:kyber_launcher/core/services/module_version_service.dart';
8+
import 'package:kyber_launcher/core/services/notification_service.dart';
9+
import 'package:kyber_launcher/features/settings/dialogs/update_dialog.dart';
10+
import 'package:kyber_launcher/gen/rust/api/maxima.dart';
11+
import 'package:kyber_launcher/main.dart';
12+
import 'package:kyber_launcher/shared/ui/buttons/normal_button.dart';
13+
import 'package:kyber_launcher/shared/ui/dialog/kyber_dialog.dart';
14+
import 'package:kyber_launcher/shared/ui/utils/hive_listener.dart';
15+
16+
class ExitDevPlaytestButton extends StatelessWidget {
17+
const ExitDevPlaytestButton({super.key});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return HiveListener(
22+
box: box,
23+
keys: const ['apiEnv'],
24+
builder: (_) {
25+
final env = Preferences.admin.apiEnv;
26+
if (env != kDevPlaytestEnv) {
27+
return const SizedBox.shrink();
28+
}
29+
30+
return _ExitButton(currentEnv: env);
31+
},
32+
);
33+
}
34+
}
35+
36+
class _ExitButton extends StatefulWidget {
37+
const _ExitButton({required this.currentEnv});
38+
39+
final String currentEnv;
40+
41+
@override
42+
State<_ExitButton> createState() => _ExitButtonState();
43+
}
44+
45+
class _ExitButtonState extends State<_ExitButton> {
46+
bool _busy = false;
47+
48+
Future<void> _exit() async {
49+
if (_busy) return;
50+
setState(() => _busy = true);
51+
52+
try {
53+
final service = KyberGRPCService.fromEnv(kProdEnv);
54+
final token = await getAuthToken();
55+
await service.login(token);
56+
57+
Preferences.admin.apiEnv = kProdEnv;
58+
final config = await service.launcherClient.getLauncherConfig(.new());
59+
for (final target in config.defaultChannels.entries) {
60+
await box.put('${target.key}_release_channel', target.value);
61+
}
62+
63+
final updateAvailable = await ModuleVersionService().updateAvailable(
64+
module: .installer,
65+
);
66+
if (!updateAvailable) {
67+
NotificationService.warning(
68+
message: 'Please restart the Launcher to apply the changes.',
69+
);
70+
} else {
71+
NotificationService.info(
72+
message:
73+
'Switched back to production. '
74+
'Downloading latest version of the Launcher...',
75+
);
76+
await showKyberDialog(
77+
context: navigatorKey.currentContext!,
78+
builder: (context) => const UpdateDialog(forceInstall: true),
79+
);
80+
}
81+
} on GrpcError catch (e) {
82+
NotificationService.error(
83+
message: 'Failed to switch back to production: ${e.message ?? e.code}',
84+
);
85+
} catch (e) {
86+
NotificationService.error(
87+
message: 'Failed to switch back to production: $e',
88+
);
89+
} finally {
90+
if (mounted) setState(() => _busy = false);
91+
}
92+
}
93+
94+
@override
95+
Widget build(BuildContext context) {
96+
final icon = switch (_busy) {
97+
true => const SizedBox(
98+
width: 20,
99+
height: 20,
100+
child: ProgressRing(),
101+
),
102+
_ => const Icon(
103+
mt.Icons.exit_to_app,
104+
size: 20,
105+
),
106+
};
107+
108+
return KOutlinedButton(
109+
onPressed: () => _busy ? null : _exit(),
110+
child: Row(
111+
spacing: 10,
112+
children: [
113+
icon,
114+
const Text(
115+
'Leave DevPlaytest',
116+
),
117+
],
118+
),
119+
);
120+
}
121+
}

Launcher/lib/features/navigation_bar/widgets/social_bar.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:kyber_launcher/features/maxima/dialogs/maxima_friends_dialog.dar
99
import 'package:kyber_launcher/features/maxima/providers/maxima_cubit.dart';
1010
import 'package:kyber_launcher/features/maxima/providers/maxima_rtm_cubit.dart';
1111
import 'package:kyber_launcher/features/maxima/widgets/maxima_avatar.dart';
12+
import 'package:kyber_launcher/features/navigation_bar/widgets/exit_devplaytest_button.dart';
1213
import 'package:kyber_launcher/features/settings/dialogs/chromium_download_dialog.dart';
1314
import 'package:kyber_launcher/gen/fonts.gen.dart';
1415
import 'package:kyber_launcher/shared/ui/ui.dart';
@@ -39,6 +40,7 @@ class _SocialBarState extends State<SocialBar> {
3940
spacing: 15,
4041
children: [
4142
const Expanded(flex: 3, child: SizedBox.shrink()),
43+
const ExitDevPlaytestButton(),
4244
const VCardSection(),
4345
const _UserBar(),
4446
const SizedBox(width: 0),

Launcher/lib/main.dart

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,7 @@ import 'package:form_builder_validators/localization/l10n.dart';
1313
import 'package:grpc/grpc.dart';
1414
import 'package:hive_ce_flutter/hive_flutter.dart';
1515
import 'package:kyber_collection/kyber_collection.dart';
16-
import 'package:kyber_launcher/core/config/colors.dart';
17-
import 'package:kyber_launcher/core/i18n/app_locale.dart';
18-
import 'package:kyber_launcher/core/routing/app_router.dart';
19-
import 'package:kyber_launcher/core/services/module_version_service.dart';
20-
import 'package:kyber_launcher/core/services/native_dialog.dart';
21-
import 'package:kyber_launcher/core/services/storage_helper.dart';
22-
import 'package:kyber_launcher/core/services/window_helper.dart';
23-
import 'package:kyber_launcher/core/utils/custom_logger.dart';
16+
import 'package:kyber_launcher/core/core.dart';
2417
import 'package:kyber_launcher/features/download_manager/providers/download_manager_cubit.dart';
2518
import 'package:kyber_launcher/features/events/providers/event_cubic.dart';
2619
import 'package:kyber_launcher/features/kyber/providers/kyber_api_status_cubit.dart';
@@ -66,6 +59,9 @@ JavascriptRuntime? flutterJs;
6659
WebViewEnvironment? webViewEnvironment;
6760
String? bbCodeJs;
6861

62+
const kProdEnv = 'prod';
63+
const kDevPlaytestEnv = 'devplaytest';
64+
6965
Box<dynamic> box = Hive.box('data');
7066
Box<List> mapRotationBox = Hive.box('mapRotation');
7167
Box<ModCollectionMetaData> collectionBox = Hive.box<ModCollectionMetaData>(
@@ -100,7 +96,8 @@ Future<void> initSentry(String currentVersion) async => SentryFlutter.init(
10096
return null;
10197
}
10298

103-
if (exception is FlutterError && exception.message.contains('RenderFlex')) {
99+
if (exception is FlutterError &&
100+
exception.message.contains('RenderFlex')) {
104101
return null;
105102
}
106103

@@ -132,7 +129,7 @@ Future<void> loadCerts() async {
132129
String? launcherVersion;
133130

134131
void main() async {
135-
if (Platform.isWindows &&! kDebugMode) {
132+
if (Platform.isWindows && !kDebugMode) {
136133
final exeDir = dirname(Platform.resolvedExecutable);
137134
final rustLib = File(join(exeDir, 'rust_lib.dll'));
138135
if (!rustLib.existsSync()) {
@@ -166,7 +163,7 @@ void main() async {
166163
Logger('bootstrap').info('Loading Certificates');
167164
await loadCerts();
168165
await initSentry(info.version);
169-
if (defaultTargetPlatform == TargetPlatform.windows) {
166+
if (defaultTargetPlatform == .windows) {
170167
final availableVersion = await WebViewEnvironment.getAvailableVersion();
171168
if (availableVersion == null) {
172169
showWebViewDialog();
@@ -245,7 +242,8 @@ class _AppState extends State<App> {
245242
return ToastificationWrapper(
246243
config: ToastificationConfig(
247244
animationDuration: const Duration(seconds: 1),
248-
marginBuilder: (context, child) => const .only(bottom: 20, left: 20, right: 20),
245+
marginBuilder: (context, child) =>
246+
const .only(bottom: 20, left: 20, right: 20),
249247
),
250248
child: HiveListener(
251249
box: box,
@@ -263,13 +261,14 @@ class _AppState extends State<App> {
263261
lightFactor: 0,
264262
),
265263
activeColor: kActiveColor,
266-
brightness: Brightness.dark,
264+
brightness: .dark,
267265
fontFamily: FontFamily.battlefrontUI,
268266
radioButtonTheme: RadioButtonThemeData(
269267
foregroundColor: WidgetStateProperty.resolveWith((states) {
270268
if (states.contains(WidgetState.hovered)) {
271269
return kInactiveColor;
272270
}
271+
273272
return kActiveColor;
274273
}),
275274
),
@@ -281,8 +280,8 @@ class _AppState extends State<App> {
281280
hoveringTrackBorderColor: kWhiteBackgroundColor,
282281
hoveringMainAxisMargin: 0,
283282
crossAxisMargin: 0,
284-
padding: EdgeInsets.zero,
285-
hoveringPadding: EdgeInsets.zero,
283+
padding: .zero,
284+
hoveringPadding: .zero,
286285
hoveringCrossAxisMargin: 0,
287286
mainAxisMargin: 0,
288287
backgroundColor: Colors.transparent,
@@ -292,21 +291,36 @@ class _AppState extends State<App> {
292291
),
293292
),
294293
backButtonDispatcher: RootBackButtonDispatcher(),
295-
themeMode: ThemeMode.dark,
294+
themeMode: .dark,
296295
locale: AppLocale.getLocale(),
297296
localizationsDelegates: const [
298297
...GlobalMaterialLocalizations.delegates,
299298
FormBuilderLocalizations.delegate,
300299
],
301300
supportedLocales: const [Locale('en')],
302301
debugShowCheckedModeBanner: false,
303-
builder: (context, child) {
304-
child = WindowController(
302+
builder: (context, c) {
303+
final currentRoute = router.routeInformationProvider.value.location;
304+
305+
Widget child = WindowController(
305306
child: GraphqlProvider(
306-
child: child!,
307+
child: c ?? Text('No route found for $currentRoute'),
307308
),
308309
);
309310

311+
if (Preferences.admin.apiEnv == kDevPlaytestEnv) {
312+
child = Banner(
313+
message: 'NOT FINAL',
314+
location: .topEnd,
315+
color: Colors.red,
316+
textStyle: const TextStyle(
317+
fontSize: 10,
318+
fontWeight: .bold,
319+
),
320+
child: child,
321+
);
322+
}
323+
310324
return Builder(
311325
builder: (context) {
312326
return DisableAcrylic(
@@ -336,7 +350,7 @@ class _AppState extends State<App> {
336350
),
337351
],
338352
child: KyberBackground(
339-
child: child ?? const SizedBox.shrink(),
353+
child: child,
340354
),
341355
),
342356
);

0 commit comments

Comments
 (0)