This commit is contained in:
@@ -1,18 +1,22 @@
|
||||
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/domain/services/ai_process_manager.dart';
|
||||
import 'package:trainhub_flutter/injection.dart' as di;
|
||||
import 'package:trainhub_flutter/presentation/settings/ai_model_settings_controller.dart';
|
||||
import 'package:trainhub_flutter/presentation/settings/ai_model_settings_state.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
MediaKit.ensureInitialized();
|
||||
await windowManager.ensureInitialized();
|
||||
|
||||
// Initialize dependency injection
|
||||
di.init();
|
||||
|
||||
WindowOptions windowOptions = const WindowOptions(
|
||||
const windowOptions = WindowOptions(
|
||||
size: Size(1280, 800),
|
||||
minimumSize: Size(800, 600),
|
||||
center: true,
|
||||
@@ -30,17 +34,75 @@ void main() async {
|
||||
runApp(const ProviderScope(child: TrainHubApp()));
|
||||
}
|
||||
|
||||
class TrainHubApp extends StatelessWidget {
|
||||
// =============================================================================
|
||||
// Root application widget
|
||||
// =============================================================================
|
||||
class TrainHubApp extends ConsumerStatefulWidget {
|
||||
const TrainHubApp({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<TrainHubApp> createState() => _TrainHubAppState();
|
||||
}
|
||||
|
||||
class _TrainHubAppState extends ConsumerState<TrainHubApp>
|
||||
with WindowListener {
|
||||
// Create the router once and reuse it across rebuilds.
|
||||
final _appRouter = AppRouter();
|
||||
|
||||
// Guard flag so we never start the servers more than once per app session.
|
||||
bool _serversStarted = false;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 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<AiProcessManager>().stopServers();
|
||||
await windowManager.destroy();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Build
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appRouter = AppRouter();
|
||||
// Watch the model-settings state and start servers exactly once, the
|
||||
// first time models are confirmed to be present on disk.
|
||||
ref.listen<AiModelSettingsState>(
|
||||
aiModelSettingsControllerProvider,
|
||||
(prev, next) {
|
||||
if (!_serversStarted && next.areModelsValidated) {
|
||||
_serversStarted = true;
|
||||
di.getIt<AiProcessManager>().startServers();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return MaterialApp.router(
|
||||
title: 'TrainHub',
|
||||
theme: AppTheme.dark,
|
||||
routerConfig: appRouter.config(),
|
||||
routerConfig: _appRouter.config(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user