run static method

Future<void> run(
  1. CLAppConfig config
)

Inizializza e lancia l'app con la configurazione fornita.

Implementation

static Future<void> run(CLAppConfig config) async {
  WidgetsFlutterBinding.ensureInitialized();
  if (kDebugMode && !kIsWeb) {
    HttpOverrides.global = _MyHttpOverrides();
  }
  await SharedManager.initPrefs();
  ApiManager.configure(baseUrl: config.baseUrl, apiVersion: config.apiVersion);

  // Core providers
  final appState = AppState();
  appState.showAiButton = config.showAiButton;
  appState.aiButtonPosition = config.aiButtonPosition;
  appState.aiButtonBuilder = config.aiButtonBuilder;
  appState.profilePosition = config.profilePosition;
  final authState = config.authState;
  final navigationState = NavigationState();
  final errorState = ErrorState();
  final themeProvider = ThemeProvider();
  final moduleThemeProvider = ModuleThemeProvider();
  final notificationsPanelProvider = NotificationsPanelProvider();

  // Callback app-specific di init
  await config.onInit();

  // Popola registry colori moduli (consumato da CLPageHeader e altri widget).
  for (final route in config.shellRoutes) {
    if (route is ModuleRoute && route.color != null) {
      ModuleColorRegistry.register(route.path, route.color!);
    }
  }

  // Router
  final appModule = _CLAppModule(config);

  // Single Listenable instance shared between Modular.configure and the
  // cache-invalidation listener — using the same instance ensures that
  // every state notify flushes the redirect dedup cache exactly once.
  final refreshListenable = Listenable.merge([authState, navigationState, appState, errorState]);
  refreshListenable.addListener(() {
    _lastRedirectLocation = null;
    _lastRedirectResult = null;
  });

  await Modular.configure(
    appModule: appModule,
    initialRoute: config.initialRoute,
    debugLogDiagnostics: config.debugLogDiagnostics,
    debugLogDiagnosticsGoRouter: false,
    pageTransition: PageTransition.fade,
    refreshListenable: refreshListenable,
    redirect: (context, state) {
      final currentLocation = state.matchedLocation;
      // Dedup: identical location + unchanged state ⇒ reuse last result.
      // Cache is invalidated on every notify of refreshListenable above.
      if (currentLocation == _lastRedirectLocation) {
        return _lastRedirectResult;
      }
      String? result;
      try {
        if (config.customRedirect != null) {
          result = config.customRedirect!(context, state);
        }
      } catch (_) {
        // Durante hot-restart, il context può essere deactivato
        // e i Provider non sono ancora disponibili
      }
      _lastRedirectLocation = currentLocation;
      _lastRedirectResult = result;
      return result;
    },
    observers: [GoRouterBreadcrumbObserver()],
    navigatorKey: AlertManager.navigatorKey,
  );

  /// Lazy AI assistant config: starts as `null` and is populated on the next
  /// microtask via [Future.delayed(Duration.zero)]. The notifier is passed
  /// to [_CLMainApp], which rebuilds via [ValueListenableBuilder] when the
  /// value lands. This keeps app-startup off the critical path without
  /// forcing the AI panel into the initial frame.
  final aiConfigNotifier = ValueNotifier<AiAssistantConfig?>(null);
  unawaited(Future.delayed(Duration.zero, () {
    aiConfigNotifier.value = config.buildAiConfig();
  }));

  // Run
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: appState),
        ChangeNotifierProvider.value(value: navigationState),
        ChangeNotifierProvider.value(value: authState),
        ChangeNotifierProvider<CLAuthState>.value(value: authState),
        ChangeNotifierProvider.value(value: errorState),
        ChangeNotifierProvider.value(value: themeProvider),
        ChangeNotifierProvider.value(value: moduleThemeProvider),
        ChangeNotifierProvider.value(value: notificationsPanelProvider),
        ...config.extraProviders,
      ],
      child: _CLMainApp(
        aiConfigNotifier: aiConfigNotifier,
        locale: config.locale,
        supportedLocales: config.supportedLocales,
        mobileBreakpoint: config.mobileBreakpoint,
      ),
    ),
  );
}