import 'package:flutter/foundation.dart'; import '../providers/auth_provider.dart'; import '../services/notification_service.dart'; import '../services/storage_service.dart'; import '../utils/session_manager.dart'; /// Service for handling app initialization tasks /// /// Coordinates initialization of various services and providers: /// - Theme preferences loading /// - Notification service setup /// - Session restoration /// - Cache management /// /// Usage example: /// ```dart /// final initService = AppInitializationService( /// authProvider: authProvider, /// themeProvider: themeProvider, /// notificationService: notificationService, /// ); /// /// final result = await initService.initialize(); /// if (result.success) { /// // App initialized successfully /// } /// ``` class AppInitializationService { final AuthProvider _authProvider; final NotificationService _notificationService; final StorageService _storageService; late final SessionManager _sessionManager; AppInitializationService({ required AuthProvider authProvider, required NotificationService notificationService, StorageService? storageService, }) : _authProvider = authProvider, _notificationService = notificationService, _storageService = storageService ?? StorageService() { _sessionManager = SessionManager(authProvider: _authProvider); } /// Initialize the application /// /// Performs all necessary initialization tasks in the correct order /// Returns InitializationResult with status and details Future initialize() async { final startTime = DateTime.now(); final steps = []; try { // Step 1: Initialize notification service steps.add(await _initializeNotifications()); // Step 2: Load theme preferences steps.add(await _loadThemePreferences()); // Step 3: Check and manage cache steps.add(await _manageCacheVersion()); // Step 4: Attempt session restoration steps.add(await _restoreSession()); final duration = DateTime.now().difference(startTime); final allSuccessful = steps.every((step) => step.success); return InitializationResult( success: allSuccessful, steps: steps, duration: duration, sessionRestored: steps .firstWhere( (s) => s.name == 'Session Restoration', orElse: () => InitializationStep( name: 'Session Restoration', success: false, ), ) .success, ); } catch (e) { debugPrint('Error during app initialization: $e'); final duration = DateTime.now().difference(startTime); return InitializationResult( success: false, steps: steps, duration: duration, error: e.toString(), ); } } /// Initialize notification service Future _initializeNotifications() async { try { await _notificationService.initialize(); return InitializationStep( name: 'Notification Service', success: true, message: 'Notification service initialized', ); } catch (e) { debugPrint('Failed to initialize notifications: $e'); return InitializationStep( name: 'Notification Service', success: false, message: 'Failed to initialize notifications: $e', ); } } /// Load theme preferences Future _loadThemePreferences() async { try { // Theme preferences are loaded in ThemeProvider constructor // This step just confirms it's ready return InitializationStep( name: 'Theme Preferences', success: true, message: 'Theme preferences loaded', ); } catch (e) { debugPrint('Failed to load theme preferences: $e'); return InitializationStep( name: 'Theme Preferences', success: false, message: 'Failed to load theme preferences: $e', ); } } /// Manage cache version Future _manageCacheVersion() async { try { const expectedCacheVersion = 1; // Update this when data structure changes final cleared = await _storageService.clearCacheIfVersionMismatch( expectedCacheVersion, ); if (cleared) { return InitializationStep( name: 'Cache Management', success: true, message: 'Cache cleared due to version mismatch', ); } else { return InitializationStep( name: 'Cache Management', success: true, message: 'Cache version is current', ); } } catch (e) { debugPrint('Failed to manage cache: $e'); return InitializationStep( name: 'Cache Management', success: false, message: 'Failed to manage cache: $e', ); } } /// Attempt to restore previous session Future _restoreSession() async { try { // Check if session can be restored final canRestore = await _sessionManager.canRestoreSession(); if (!canRestore) { return InitializationStep( name: 'Session Restoration', success: false, message: 'No saved session to restore', ); } // Attempt restoration final result = await _sessionManager.restoreSession(); if (result.success) { return InitializationStep( name: 'Session Restoration', success: true, message: 'Session restored successfully', ); } else { // Session restoration failed, but this is not a critical error // User will just need to login again return InitializationStep( name: 'Session Restoration', success: false, message: result.message, reason: result.reason, ); } } catch (e) { debugPrint('Error during session restoration: $e'); return InitializationStep( name: 'Session Restoration', success: false, message: 'Session restoration error: $e', ); } } /// Get session manager instance SessionManager get sessionManager => _sessionManager; /// Get storage service instance StorageService get storageService => _storageService; } /// Result of app initialization class InitializationResult { final bool success; final List steps; final Duration duration; final bool sessionRestored; final String? error; InitializationResult({ required this.success, required this.steps, required this.duration, this.sessionRestored = false, this.error, }); /// Get failed steps List get failedSteps => steps.where((step) => !step.success).toList(); /// Get successful steps List get successfulSteps => steps.where((step) => step.success).toList(); /// Check if initialization is complete (even with some non-critical failures) bool get isComplete => steps.isNotEmpty; @override String toString() { return 'InitializationResult(' 'success: $success, ' 'sessionRestored: $sessionRestored, ' 'steps: ${steps.length}, ' 'duration: ${duration.inMilliseconds}ms' ')'; } } /// Individual initialization step class InitializationStep { final String name; final bool success; final String? message; final SessionRestoreFailureReason? reason; InitializationStep({ required this.name, required this.success, this.message, this.reason, }); @override String toString() { return 'InitializationStep(' 'name: $name, ' 'success: $success, ' 'message: $message' ')'; } }