import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:hiddify/core/analytics/analytics_controller.dart'; import 'package:hiddify/core/app_info/app_info_provider.dart'; import 'package:hiddify/core/directories/directories_provider.dart'; import 'package:hiddify/core/logger/logger.dart'; import 'package:hiddify/core/logger/logger_controller.dart'; import 'package:hiddify/core/model/environment.dart'; import 'package:hiddify/core/preferences/general_preferences.dart'; import 'package:hiddify/core/preferences/preferences_migration.dart'; import 'package:hiddify/core/preferences/preferences_provider.dart'; import 'package:hiddify/features/app/widget/app.dart'; import 'package:hiddify/features/auto_start/notifier/auto_start_notifier.dart'; import 'package:hiddify/features/common/custom_splash_screen.dart'; import 'package:hiddify/features/deep_link/notifier/deep_link_notifier.dart'; import 'package:hiddify/features/log/data/log_data_providers.dart'; import 'package:hiddify/features/profile/data/profile_data_providers.dart'; import 'package:hiddify/features/profile/notifier/active_profile_notifier.dart'; import 'package:hiddify/features/system_tray/notifier/system_tray_notifier.dart'; import 'package:hiddify/features/window/notifier/window_notifier.dart'; import 'package:hiddify/singbox/service/singbox_service_provider.dart'; import 'package:hiddify/utils/utils.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; Future lazyBootstrap( WidgetsBinding widgetsBinding, Environment env, ) async { LoggerController.preInit(); FlutterError.onError = Logger.logFlutterError; WidgetsBinding.instance.platformDispatcher.onError = Logger.logPlatformDispatcherError; final stopWatch = Stopwatch()..start(); final container = ProviderContainer( overrides: [ environmentProvider.overrideWithValue(env), ], ); // Показываем кастомный splash screen с круговым индикатором runApp( MaterialApp( debugShowCheckedModeBanner: false, home: CustomSplashScreen( onInitializationComplete: () async { await _performBootstrap(container, stopWatch, env); }, ), ), ); } Future _performBootstrap( ProviderContainer container, Stopwatch stopWatch, Environment env, ) async { await _init( "directories", () => container.read(appDirectoriesProvider.future), ); LoggerController.init(container.read(logPathResolverProvider).appFile().path); final appInfo = await _init( "app info", () => container.read(appInfoProvider.future), ); await _init( "preferences", () => container.read(sharedPreferencesProvider.future), ); final enableAnalytics = await container.read(analyticsControllerProvider.future); if (enableAnalytics) { await _init( "analytics", () => container.read(analyticsControllerProvider.notifier).enableAnalytics(), ); } await _init( "preferences migration", () async { try { await PreferencesMigration( sharedPreferences: container.read(sharedPreferencesProvider).requireValue, ).migrate(); } catch (e, stackTrace) { Logger.bootstrap.error("preferences migration failed", e, stackTrace); if (env == Environment.dev) rethrow; Logger.bootstrap.info("clearing preferences"); await container.read(sharedPreferencesProvider).requireValue.clear(); } }, ); final debug = container.read(debugModeNotifierProvider) || kDebugMode; if (PlatformUtils.isDesktop) { await _init( "window controller", () => container.read(windowNotifierProvider.future), ); final silentStart = container.read(Preferences.silentStart); Logger.bootstrap.debug("silent start [${silentStart ? "Enabled" : "Disabled"}]"); if (!silentStart) { await container.read(windowNotifierProvider.notifier).open(focus: false); } else { Logger.bootstrap.debug("silent start, remain hidden accessible via tray"); } await _init( "auto start service", () => container.read(autoStartNotifierProvider.future), ); } await _init( "logs repository", () => container.read(logRepositoryProvider.future), ); await _init("logger controller", () => LoggerController.postInit(debug)); Logger.bootstrap.info(appInfo.format()); await _init( "profile repository", () => container.read(profileRepositoryProvider.future), ); await _safeInit( "active profile", () => container.read(activeProfileProvider.future), timeout: 1000, ); await _safeInit( "deep link service", () => container.read(deepLinkNotifierProvider.future), timeout: 1000, ); await _init( "sing-box", () => container.read(singboxServiceProvider).init(), ); if (PlatformUtils.isDesktop) { await _safeInit( "system tray", () => container.read(systemTrayNotifierProvider.future), timeout: 1000, ); } if (Platform.isAndroid) { await _safeInit( "android display mode", () async { await FlutterDisplayMode.setHighRefreshRate(); }, ); } Logger.bootstrap.info("bootstrap took [${stopWatch.elapsedMilliseconds}ms]"); stopWatch.stop(); runApp( ProviderScope( parent: container, child: SentryUserInteractionWidget( child: const App(), ), ), ); } Future _init( String name, Future Function() initializer, { int? timeout, }) async { final stopWatch = Stopwatch()..start(); Logger.bootstrap.info("initializing [$name]"); Future func() => timeout != null ? initializer().timeout(Duration(milliseconds: timeout)) : initializer(); try { final result = await func(); Logger.bootstrap.debug("[$name] initialized in ${stopWatch.elapsedMilliseconds}ms"); return result; } catch (e, stackTrace) { Logger.bootstrap.error("[$name] error initializing", e, stackTrace); rethrow; } finally { stopWatch.stop(); } } Future _safeInit( String name, Future Function() initializer, { int? timeout, }) async { try { return await _init(name, initializer, timeout: timeout); } catch (e) { return null; } }