import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'injection.dart' as di; import 'presentation/blocs/auth/auth_bloc.dart'; import 'presentation/blocs/auth/auth_event.dart'; import 'presentation/blocs/auth/auth_state.dart'; import 'presentation/blocs/server/server_bloc.dart'; import 'presentation/blocs/server/server_event.dart'; import 'presentation/blocs/action_mapping/action_mapping_bloc.dart'; import 'presentation/blocs/action_mapping/action_mapping_event.dart'; import 'presentation/screens/auth/login_screen.dart'; import 'presentation/screens/servers/server_list_screen.dart'; import 'presentation/screens/servers/servers_management_screen.dart'; import 'presentation/screens/servers/server_form_screen.dart'; import 'presentation/screens/action_mappings/action_mappings_list_screen.dart'; import 'presentation/screens/action_mappings/action_mapping_form_screen.dart'; import 'domain/entities/server.dart'; import 'domain/entities/action_mapping.dart'; import 'data/models/server_hive_model.dart'; import 'data/models/action_mapping_hive_model.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize Hive for local storage await Hive.initFlutter(); // Register Hive adapters Hive.registerAdapter(ServerHiveModelAdapter()); Hive.registerAdapter(ActionMappingHiveModelAdapter()); // Initialize dependency injection await di.init(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return BlocProvider( create: (_) => di.sl()..add(const CheckAuthStatus()), child: MaterialApp.router( title: 'GeViAPI - Video Management System', debugShowCheckedModeBanner: false, theme: ThemeData( colorScheme: ColorScheme.fromSeed( seedColor: Colors.blue, brightness: Brightness.light, ), useMaterial3: true, appBarTheme: const AppBarTheme( centerTitle: false, elevation: 2, ), cardTheme: CardThemeData( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), inputDecorationTheme: InputDecorationTheme( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), ), ), routerConfig: _router, ), ); } } final _router = GoRouter( routes: [ GoRoute( path: '/login', builder: (context, state) => BlocProvider.value( value: context.read(), child: const LoginScreen(), ), ), GoRoute( path: '/', builder: (context, state) => BlocProvider.value( value: context.read(), child: const ServerListScreen(), ), ), ShellRoute( builder: (context, state, child) => BlocProvider( create: (_) => di.sl()..add(const LoadServers()), child: child, ), routes: [ GoRoute( path: '/servers', builder: (context, state) => const ServersManagementScreen(), ), GoRoute( path: '/servers/create', builder: (context, state) { final serverType = state.uri.queryParameters['type'] == 'geviscope' ? ServerType.geviscope : ServerType.gcore; return ServerFormScreen(serverType: serverType); }, ), GoRoute( path: '/servers/edit/:id', builder: (context, state) { final server = state.extra as Server; return ServerFormScreen(server: server, serverType: server.type); }, ), ], ), ShellRoute( builder: (context, state, child) => BlocProvider( create: (_) => di.sl()..add(const LoadActionMappings()), child: child, ), routes: [ GoRoute( path: '/action-mappings', builder: (context, state) => const ActionMappingsListScreen(), ), GoRoute( path: '/action-mappings/create', builder: (context, state) => const ActionMappingFormScreen(), ), GoRoute( path: '/action-mappings/edit/:id', builder: (context, state) { final mapping = state.extra as ActionMapping; return ActionMappingFormScreen(mapping: mapping); }, ), ], ), ], redirect: (context, state) { final authBloc = context.read(); final authState = authBloc.state; final isLoginRoute = state.matchedLocation == '/login'; if (authState is Authenticated) { // If authenticated and trying to access login, redirect to home if (isLoginRoute) { return '/'; } } else { // If not authenticated and not on login page, redirect to login if (!isLoginRoute) { return '/login'; } } // No redirect needed return null; }, refreshListenable: GoRouterRefreshStream( di.sl().stream, ), ); class GoRouterRefreshStream extends ChangeNotifier { GoRouterRefreshStream(Stream stream) { notifyListeners(); _subscription = stream.asBroadcastStream().listen( (dynamic _) => notifyListeners(), ); } late final StreamSubscription _subscription; @override void dispose() { _subscription.cancel(); super.dispose(); } }