import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:media_kit/media_kit.dart'; import 'package:window_manager/window_manager.dart'; import 'package:trainhub_flutter/core/router/app_router.dart'; import 'package:trainhub_flutter/core/theme/app_theme.dart'; import 'package:trainhub_flutter/data/services/ai_process_manager.dart'; import 'package:trainhub_flutter/injection.dart' as di; void main() async { WidgetsFlutterBinding.ensureInitialized(); MediaKit.ensureInitialized(); await windowManager.ensureInitialized(); di.init(); const windowOptions = WindowOptions( size: Size(1280, 800), minimumSize: Size(800, 600), center: true, backgroundColor: Colors.transparent, skipTaskbar: false, titleBarStyle: TitleBarStyle.normal, title: 'TrainHub', ); windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.show(); await windowManager.focus(); }); runApp(const ProviderScope(child: TrainHubApp())); } // ============================================================================= // Root application widget // ============================================================================= class TrainHubApp extends ConsumerStatefulWidget { const TrainHubApp({super.key}); @override ConsumerState createState() => _TrainHubAppState(); } class _TrainHubAppState extends ConsumerState with WindowListener { // Create the router once and reuse it across rebuilds. final _appRouter = AppRouter(); // ------------------------------------------------------------------------- // Lifecycle // ------------------------------------------------------------------------- @override void initState() { super.initState(); windowManager.addListener(this); // Intercept the OS close event so we can kill child processes first. windowManager.setPreventClose(true); } @override void dispose() { windowManager.removeListener(this); super.dispose(); } // ------------------------------------------------------------------------- // WindowListener — critical: kill servers before the window is destroyed // so they don't become zombie processes consuming 5 GB of RAM. // ------------------------------------------------------------------------- @override void onWindowClose() async { await di.getIt().stopServers(); await windowManager.destroy(); } // ------------------------------------------------------------------------- // Build // ------------------------------------------------------------------------- @override Widget build(BuildContext context) { return MaterialApp.router( title: 'TrainHub', theme: AppTheme.dark, routerConfig: _appRouter.config(), debugShowCheckedModeBanner: false, ); } }