@@ -39,27 +39,42 @@ Future<Widget> bootstrap(
3939 app_config.AppConfig appConfig,
4040 app_config.AppEnvironment environment,
4141) async {
42- Logger .root.level = Level .ALL ;
43- Logger .root.onRecord.listen (
44- (record) => print (
42+ // Setup logging
43+ Logger .root.level = environment == app_config.AppEnvironment .production
44+ ? Level .INFO
45+ : Level .ALL ;
46+ Logger .root.onRecord.listen ((record) {
47+ print (
4548 '${record .level .name }: ${record .time }: ${record .loggerName }: ${record .message }' ,
46- ),
47- );
49+ );
50+ if (record.error != null ) {
51+ print ('Error: ${record .error }' );
52+ }
53+ if (record.stackTrace != null ) {
54+ print ('Stack Trace: ${record .stackTrace }' );
55+ }
56+ });
57+ final logger = Logger ('bootstrap' );
58+ logger.config ('--- Starting Bootstrap Process ---' );
59+ logger.config ('App Environment: $environment ' );
60+
4861 WidgetsFlutterBinding .ensureInitialized ();
4962 Bloc .observer = const AppBlocObserver ();
50- final logger = Logger ('bootstrap' );
5163 timeago.setLocaleMessages ('en' , EnTimeagoMessages ());
5264 timeago.setLocaleMessages ('ar' , ArTimeagoMessages ());
5365
66+ logger.info ('1. Initializing KV Storage Service...' );
5467 // 1. Initialize KV Storage Service first, as it's a foundational dependency.
5568 final kvStorage = await KVStorageSharedPreferences .getInstance ();
69+ logger.fine ('KV Storage Service initialized (SharedPreferences).' );
5670
5771 // Initialize InlineAdCacheService early as it's a singleton and needs AdService.
5872 // It will be fully configured once AdService is available.
5973 InlineAdCacheService ? inlineAdCacheService;
6074
6175 // 2. Initialize HttpClient. Its tokenProvider now directly reads from
6276 // kvStorage, breaking the circular dependency with AuthRepository.
77+ logger.info ('2. Initializing HttpClient...' );
6378 // This HttpClient instance is used for all subsequent API calls, including
6479 // the initial unauthenticated fetch of RemoteConfig.
6580 final httpClient = HttpClient (
@@ -68,18 +83,22 @@ Future<Widget> bootstrap(
6883 kvStorage.readString (key: StorageKey .authToken.stringValue),
6984 logger: logger,
7085 );
86+ logger.fine ('HttpClient initialized for base URL: ${appConfig .baseUrl }' );
7187
7288 // 3. Initialize RemoteConfigClient and Repository, and fetch RemoteConfig.
89+ logger.info ('3. Initializing RemoteConfig client and repository...' );
7390 // This is done early because RemoteConfig is now publicly accessible (unauthenticated).
7491 late DataClient <RemoteConfig > remoteConfigClient;
7592 if (appConfig.environment == app_config.AppEnvironment .demo) {
93+ logger.fine ('Using in-memory client for RemoteConfig.' );
7694 remoteConfigClient = DataInMemory <RemoteConfig >(
7795 toJson: (i) => i.toJson (),
7896 getId: (i) => i.id,
7997 initialData: remoteConfigsFixturesData,
8098 logger: logger,
8199 );
82100 } else {
101+ logger.fine ('Using API client for RemoteConfig.' );
83102 // For development and production environments, use DataApi.
84103 remoteConfigClient = DataApi <RemoteConfig >(
85104 httpClient: httpClient,
@@ -92,60 +111,62 @@ Future<Widget> bootstrap(
92111 final remoteConfigRepository = DataRepository <RemoteConfig >(
93112 dataClient: remoteConfigClient,
94113 );
114+ logger.fine ('RemoteConfig repository initialized.' );
95115
96116 // Fetch the initial RemoteConfig. This is a critical step to determine
97117 // the app's global status (e.g., maintenance mode, update required)
98118 // before proceeding with other initializations.
99119 RemoteConfig ? initialRemoteConfig;
100120 HttpException ? initialRemoteConfigError;
101121
122+ logger.info ('4. Fetching initial RemoteConfig...' );
102123 try {
103124 initialRemoteConfig = await remoteConfigRepository.read (
104125 id: kRemoteConfigId,
105126 );
106- logger.info ( '[bootstrap] Initial RemoteConfig fetched successfully.' );
127+ logger.fine ( ' Initial RemoteConfig fetched successfully.' );
107128 } on HttpException catch (e) {
108- logger.severe (
109- '[bootstrap] Failed to fetch initial RemoteConfig (HttpException): $e ' ,
110- );
129+ logger.severe ('Failed to fetch initial RemoteConfig (HttpException): $e ' );
111130 initialRemoteConfigError = e;
112131 } catch (e, s) {
113- logger.severe (
114- '[bootstrap] Unexpected error fetching initial RemoteConfig.' ,
115- e,
116- s,
117- );
132+ logger.severe ('Unexpected error fetching initial RemoteConfig.' , e, s);
118133 initialRemoteConfigError = UnknownException (e.toString ());
119134 }
120135
121136 // 4. Conditionally initialize Auth services based on environment.
122137 // This is done after RemoteConfig is fetched, as Auth services might depend
123- // on configurations defined in RemoteConfig (though not directly in this case).
138+ // on configurations defined in RemoteConfig.
139+ logger.info ('5. Initializing Authentication services...' );
124140 late final AuthClient authClient;
125141 late final AuthRepository authenticationRepository;
126142 if (appConfig.environment == app_config.AppEnvironment .demo) {
143+ logger.fine ('Using in-memory client for Authentication.' );
127144 // In-memory authentication for demo environment.
128145 authClient = AuthInmemory ();
129146 authenticationRepository = AuthRepository (
130147 authClient: authClient,
131148 storageService: kvStorage,
132149 );
133150 } else {
151+ logger.fine ('Using API client for Authentication.' );
134152 // Now that httpClient is available, initialize AuthApi and AuthRepository.
135153 authClient = AuthApi (httpClient: httpClient);
136154 authenticationRepository = AuthRepository (
137155 authClient: authClient,
138156 storageService: kvStorage,
139157 );
140158 }
159+ logger.fine ('Authentication repository initialized.' );
141160
142161 // 5. Initialize AdProvider and AdService.
162+ logger.info ('6. Initializing Ad providers and AdService...' );
143163 late final Map <AdPlatformType , AdProvider > adProviders;
144164
145165 // Conditionally instantiate ad providers based on the application environment.
146166 // This ensures that only the relevant ad providers are available for the
147167 // current environment, preventing unintended usage.
148168 if (appConfig.environment == app_config.AppEnvironment .demo || kIsWeb) {
169+ logger.fine ('Using DemoAdProvider for all ad platforms.' );
149170 final demoAdProvider = DemoAdProvider (logger: logger);
150171 adProviders = {
151172 // In the demo environment or on the web, all ad platform types map to
@@ -157,6 +178,7 @@ Future<Widget> bootstrap(
157178 AdPlatformType .demo: demoAdProvider,
158179 };
159180 } else {
181+ logger.fine ('Using AdMobAdProvider and LocalAdProvider.' );
160182 // For development and production environments (non-web), use real ad providers.
161183 adProviders = {
162184 // AdMob provider for Google Mobile Ads.
@@ -186,22 +208,28 @@ Future<Widget> bootstrap(
186208 logger: logger,
187209 );
188210 await adService.initialize ();
211+ logger.fine ('AdService initialized.' );
189212
190213 // Initialize InlineAdCacheService with the created AdService.
191214 inlineAdCacheService = InlineAdCacheService (adService: adService);
215+ logger.fine ('InlineAdCacheService initialized.' );
192216
193217 // Fetch the initial user from the authentication repository.
194218 // This ensures the AppBloc starts with an accurate authentication status.
219+ logger.info ('7. Fetching initial user...' );
195220 final initialUser = await authenticationRepository.getCurrentUser ();
221+ logger.fine ('Initial user fetched: ${initialUser ?.id ?? 'none' }.' );
196222
197223 // Create a GlobalKey for the NavigatorState to be used by AppBloc
198224 // and InterstitialAdManager for BuildContext access.
199225 final navigatorKey = GlobalKey <NavigatorState >();
200226
201227 // Initialize PackageInfoService
202228 final packageInfoService = PackageInfoServiceImpl (logger: logger);
229+ logger.fine ('PackageInfoService initialized.' );
203230
204231 // 6. Initialize all other DataClients and Repositories.
232+ logger.info ('8. Initializing Data clients and repositories...' );
205233 // These now also have a guaranteed valid httpClient.
206234 late final DataClient <Headline > headlinesClient;
207235 late final DataClient <Topic > topicsClient;
@@ -212,6 +240,7 @@ Future<Widget> bootstrap(
212240 late final DataClient <User > userClient;
213241 late final DataClient <LocalAd > localAdClient;
214242 if (appConfig.environment == app_config.AppEnvironment .demo) {
243+ logger.fine ('Using in-memory clients for all data repositories.' );
215244 headlinesClient = DataInMemory <Headline >(
216245 toJson: (i) => i.toJson (),
217246 getId: (i) => i.id,
@@ -286,6 +315,7 @@ Future<Widget> bootstrap(
286315 logger: logger,
287316 );
288317 } else if (appConfig.environment == app_config.AppEnvironment .development) {
318+ logger.fine ('Using API clients for all data repositories (Development).' );
289319 headlinesClient = DataApi <Headline >(
290320 httpClient: httpClient,
291321 modelName: 'headline' ,
@@ -343,6 +373,7 @@ Future<Widget> bootstrap(
343373 logger: logger,
344374 );
345375 } else {
376+ logger.fine ('Using API clients for all data repositories (Production).' );
346377 // Default to API clients for production
347378 headlinesClient = DataApi <Headline >(
348379 httpClient: httpClient,
@@ -401,6 +432,7 @@ Future<Widget> bootstrap(
401432 logger: logger,
402433 );
403434 }
435+ logger.fine ('All data clients instantiated.' );
404436
405437 final headlinesRepository = DataRepository <Headline >(
406438 dataClient: headlinesClient,
@@ -419,6 +451,7 @@ Future<Widget> bootstrap(
419451 dataClient: userAppSettingsClient,
420452 );
421453 final userRepository = DataRepository <User >(dataClient: userClient);
454+ logger.fine ('All data repositories initialized.' );
422455
423456 // Conditionally instantiate DemoDataMigrationService
424457 final demoDataMigrationService =
@@ -428,6 +461,9 @@ Future<Widget> bootstrap(
428461 userContentPreferencesRepository: userContentPreferencesRepository,
429462 )
430463 : null ;
464+ logger.fine (
465+ 'DemoDataMigrationService initialized: ${demoDataMigrationService != null }' ,
466+ );
431467
432468 // Conditionally instantiate DemoDataInitializerService
433469 // This service is responsible for ensuring that essential user-specific data
@@ -441,7 +477,11 @@ Future<Widget> bootstrap(
441477 userContentPreferencesRepository: userContentPreferencesRepository,
442478 )
443479 : null ;
480+ logger.fine (
481+ 'DemoDataInitializerService initialized: ${demoDataInitializerService != null }' ,
482+ );
444483
484+ logger.info ('--- Bootstrap Process Complete. Returning App widget. ---' );
445485 return App (
446486 authenticationRepository: authenticationRepository,
447487 headlinesRepository: headlinesRepository,
0 commit comments