import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' as shad; import '../core/window/app_window_frame.dart'; import '../core/window/app_window_appearance.dart'; import '../core/window/window_capability_transport.dart'; import '../l10n/l10n.dart'; import '../shared/theme/app_component_themes.dart'; import '../shared/theme/app_theme.dart'; import '../features/auth/application/web_auth_controller.dart'; import 'application/app_appearance_controller.dart'; import 'application/app_runtime_controller.dart'; import 'rpc/webview_rpc_overlay.dart'; import 'rpc/webview_rpc_service.dart'; import 'router/app_router.dart'; class GopeedApp extends ConsumerStatefulWidget { const GopeedApp({super.key}); @override ConsumerState createState() => _GopeedAppState(); } class _GopeedAppState extends ConsumerState with WidgetsBindingObserver { late final GoRouter _router; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); _router = AppRouter.build(ref.read(webAuthControllerProvider)); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); _router.dispose(); super.dispose(); } @override void didChangePlatformBrightness() { setState(() {}); } @override Widget build(BuildContext context) { ref.listen(appRuntimeControllerProvider, (_, next) { final runtime = next.value; if (runtime != null) { ref.read(appAppearanceControllerProvider.notifier).initialize(runtime.downloaderConfig.extra); } }); final runtime = ref.watch(appRuntimeControllerProvider).value; if (runtime != null) { WidgetsBinding.instance.addPostFrameCallback((_) { ref.read(appAppearanceControllerProvider.notifier).initialize(runtime.downloaderConfig.extra); }); } final appearance = ref.watch(appAppearanceControllerProvider); final themeColor = appearance.themeColor; final isLightTheme = appearance.resolveIsLight(WidgetsBinding.instance.platformDispatcher.platformBrightness); final themeMode = switch (appearance.themeMode) { AppThemeMode.system => shad.ThemeMode.system, AppThemeMode.light => shad.ThemeMode.light, AppThemeMode.dark => shad.ThemeMode.dark, }; AppWindowCapabilityHost.instance.updateAppearance( AppWindowAppearance( themeMode: appearance.themeMode.key, themeColor: appearance.themeColor.key, locale: runtime?.downloaderConfig.extra.locale ?? '', ), ); return shad.ShadcnApp.router( debugShowCheckedModeBanner: false, disableBrowserContextMenu: false, title: 'Gopeed', theme: AppTheme.light(themeColor), darkTheme: AppTheme.dark(themeColor), materialTheme: isLightTheme ? AppTheme.materialLight(themeColor) : AppTheme.materialDark(themeColor), themeMode: themeMode, locale: supportedLocaleFromConfig(runtime?.downloaderConfig.extra.locale ?? ''), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, builder: (context, child) { final content = AppComponentThemes(child: AppWindowFrame(child: child ?? const SizedBox.shrink())); if (!WebViewRpcService.instance.supported) { return content; } return Overlay( initialEntries: [ OverlayEntry(builder: (_) => content), OverlayEntry(builder: (_) => const WebViewRpcOverlay()), ], ); }, routerConfig: _router, ); } }